Put image in picturebox to clipboard

I can't seem to find a way to do this.  I have a picturebox/imagebox that displays photos.  I want to click a button which will place the current image on the clipboard so that it can be pasted in other applications (ie. Word, Outlook, etc).

So far all I've found is API code - but its for strings.. and the DoCmd.RunCommand accmdCopy command requires the control to have the focus (and I can't set focus on the picturebox) ...

Any other ideas?
Who is Participating?
No I hadn't tried it.

I am not so familiar with what needs to be changed with the sample code (other than needing to use PictureData property, not the control), but I have done this before using sample code from the following page: http://www.lebans.com/imagecontroltoclipboard.htm.

Here's some code to do it:

Option Compare Database
Option Explicit

Public Const GHND = &H42
Public Const CF_TEXT = 1
Private Const CF_ANSIONLY = &H400&
Private Const CF_APPLY = &H200&
Private Const CF_BITMAP = 2
Private Const CF_DIB = 8
Private Const CF_DIF = 5
Private Const CF_DSPBITMAP = &H82
Private Const CF_DSPTEXT = &H81
Private Const CF_EFFECTS = &H100&
Private Const CF_ENABLEHOOK = &H8&
Private Const CF_ENABLETEMPLATE = &H10&
Private Const CF_ENHMETAFILE = 14
Private Const CF_FIXEDPITCHONLY = &H4000&
Private Const CF_FORCEFONTEXIST = &H10000
Private Const CF_GDIOBJFIRST = &H300
Private Const CF_GDIOBJLAST = &H3FF
Private Const CF_HDROP = 15
Private Const CF_LIMITSIZE = &H2000&
Private Const CF_LOCALE = 16
Private Const CF_MAX = 17
Private Const CF_METAFILEPICT = 3
Private Const CF_NOFACESEL = &H80000
Private Const CF_NOSCRIPTSEL = &H800000
Private Const CF_NOSIMULATIONS = &H1000&
Private Const CF_NOSIZESEL = &H200000
Private Const CF_NOSTYLESEL = &H100000
Private Const CF_NOVECTORFONTS = &H800&
Private Const CF_NOVERTFONTS = &H1000000
Private Const CF_OEMTEXT = 7
Private Const CF_OWNERDISPLAY = &H80
Private Const CF_PALETTE = 9
Private Const CF_PENDATA = 10
Private Const CF_PRINTERFONTS = &H2
Private Const CF_PRIVATEFIRST = &H200
Private Const CF_PRIVATELAST = &H2FF
Private Const CF_RIFF = 11
Private Const CF_SCALABLEONLY = &H20000
Private Const CF_SCREENFONTS = &H1
Private Const CF_SELECTSCRIPT = &H400000
Private Const CF_SHOWHELP = &H4&
Private Const CF_SYLK = 4
Private Const CF_TIFF = 6
Private Const CF_TTONLY = &H40000
Private Const CF_UNICODETEXT = 13
Private Const CF_USESTYLE = &H80&
Private Const CF_WAVE = 12
Private Const CF_WYSIWYG = &H8000

Private Declare Function GlobalAlloc Lib "kernel32" (ByVal wFlags&, ByVal _
  dwBytes As Long) As Long
Private Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) _
  As Long
Private Declare Function GlobalSize Lib "kernel32" (ByVal hMem As Long) _
  As Long
Private Declare Function lstrcpy Lib "kernel32" (ByVal lpString1 As Any, _
  ByVal lpString2 As Any) As Long
Private Declare Function lstrlen Lib "kernel32" Alias "lstrlenA" _
  (ByVal lpString As String) As Long

Private Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) _
  As Long

Private Declare Function OpenClipboard Lib "user32" (ByVal Hwnd As Long) _
  As Long
Private Declare Function CloseClipboard Lib "user32" () As Long
Private Declare Function GetClipboardData Lib "user32" (ByVal wFormat As _
  Long) As Long
Private Declare Function EmptyClipboard Lib "user32" () As Long
Private Declare Function SetClipboardData Lib "user32" (ByVal wFormat _
  As Long, ByVal hMem As Long) As Long

Function ClipBoard_SetText(strCopyString As String) As Boolean
  Dim hGlobalMemory As Long
  Dim lpGlobalMemory As Long
  Dim hClipMemory As Long

  ' Allocate moveable global memory.
  hGlobalMemory = GlobalAlloc(GHND, Len(strCopyString) + 1)

  ' Lock the block to get a far pointer
  ' to this memory.
  lpGlobalMemory = GlobalLock(hGlobalMemory)

  ' Copy the string to this global memory.
  lpGlobalMemory = lstrcpy(lpGlobalMemory, strCopyString)

  ' Unlock the memory and then copy to the clipboard
  If GlobalUnlock(hGlobalMemory) = 0 Then
    If OpenClipboard(0&) <> 0 Then
      Call EmptyClipboard
      hClipMemory = SetClipboardData(CF_TEXT, hGlobalMemory)
      ClipBoard_SetText = CBool(CloseClipboard)
    End If
  End If
End Function

Function ClipBoard_GetText() As String
  Dim hClipMemory As Long
  Dim lpClipMemory As Long
  Dim strCBText As String
  Dim RetVal As Long
  Dim lngSize As Long
  If OpenClipboard(0&) <> 0 Then
    ' Obtain the handle to the global memory
    ' block that is referencing the text.
    hClipMemory = GetClipboardData(CF_TEXT)
    If hClipMemory <> 0 Then
      ' Lock Clipboard memory so we can reference
      ' the actual data string.
      lpClipMemory = GlobalLock(hClipMemory)
      If lpClipMemory <> 0 Then
        lngSize = GlobalSize(lpClipMemory)
        strCBText = Space$(lngSize)
        RetVal = lstrcpy(strCBText, lpClipMemory)
        RetVal = GlobalUnlock(hClipMemory)
        ' Peel off the null terminating character.
        strCBText = Left(strCBText, InStr(1, strCBText, Chr$(0), 0) - 1)
        MsgBox "Could not lock memory to copy string from."
      End If
    End If
    Call CloseClipboard
  End If
  ClipBoard_GetText = strCBText
End Function

Function CopyOlePiccy(Piccy As Object)
  Dim hGlobalMemory As Long, lpGlobalMemory As Long
  Dim hClipMemory As Long, x As Long

  ' Allocate moveable global memory.
  hGlobalMemory = GlobalAlloc(GHND, Len(Piccy) + 1)

  ' Lock the block to get a far pointer
  ' to this memory.
  lpGlobalMemory = GlobalLock(hGlobalMemory)

  'Need to copy the object to the memory here

  lpGlobalMemory = lstrcpy(lpGlobalMemory, Piccy)

  ' Unlock the memory.
  If GlobalUnlock(hGlobalMemory) <> 0 Then
    MsgBox "Could not unlock memory location. Copy aborted."
    GoTo OutOfHere2
  End If

  ' Open the Clipboard to copy data to.
  If OpenClipboard(0&) = 0 Then
    MsgBox "Could not open the Clipboard. Copy aborted."
    Exit Function
  End If

  ' Clear the Clipboard.
  x = EmptyClipboard()

  ' Copy the data to the Clipboard.
  hClipMemory = SetClipboardData(CF_TEXT, hGlobalMemory)

  If CloseClipboard() = 0 Then
    MsgBox "Could not close Clipboard."
  End If
End Function
'*********  Code End   ************

This includes code to copy strings. Use the CopyOlePiccy function to copy an OLE image object to the clipboard.
PlamodoAuthor Commented:
Hmmm... I can't get the code to work.  Maybe I'm using it wrong..

Call CopyOlePiccy(imgPhoto)

It crashes at the len(piccy) command - I guess you can't get the the length of a picture (??)

Cloud Class® Course: Microsoft Office 2010

This course will introduce you to the interfaces and features of Microsoft Office 2010 Word, Excel, PowerPoint, Outlook, and Access. You will learn about the features that are shared between all products in the Office suite, as well as the new features that are product specific.

Ah - the image you're trying to copy is an Image control rather than an OLE field, right?
PlamodoAuthor Commented:
Is the image's picture embedded or linked?
PlamodoAuthor Commented:
OK, try this. Insert an unbound OLE frame into your form. You can hide it if you need. Then try:

Set Me!MyUnboundOLE.Picture=LoadPicture(Me!MyImageControl.Picture)
CopyOLEPiccy Me!MyUnboundOLE.Picture

Does that do it?
PlamodoAuthor Commented:
I'm getting an error on this line: "Set Me!OLEUnbound3.Picture = LoadPicture(Me!Image0.Picture)"
"Object doesn't support this property or method"

Does this work for you?
Hmm, seems not. Let me get back to you on this once I test a few things out.
In image control's picture property is the path to the file, not the binary data.

Try the PictureData property instead:

CopyOLEPiccy imgPhoto.PictureData

I thought there was an easier way too, using the DataObject class - but that's apparently not available in Access (but I migh try a google hunt to see).

why cant you use accmdcopy??

i just tested with an ole and a form and it all worked ok..


Dim oWord As Object
DoCmd.RunCommand acCmdCopy
Set oWord = CreateObject("word.application")
oWord.Visible = True

PlamodoAuthor Commented:
I have a moronic question - what is an OLE control?  And where do I get it from?  I've been playing around with Unbound Object Frames.. and it just occured to me, its probably not what I'm supposed to be doing.

Bound and Unbound Object Frames are both OLE controls (they're actually the same control). I haven't found a reliable way to do this yet as I'm not really familiar with the ins and outs of the clipboard when working with non-text data.
PlamodoAuthor Commented:
In that case, I don't know how to set the focus on an Unbound Object Frame without getting an error.

Flavo - exactly what control did you use for your last comment?.. because unfortunately it doesn't seem to work for me.
The "Docmd.runcommand accmdcopy" seems like the simplest, most logical way to do things - and looks like the only Access built-in clipboard function .. but the focus dealio is creating some big headaches.

PlamodoAuthor Commented:
Wow.. its been a few months since my last comment.  Sorry about that.  I've had a small problem with my EE alerts going into my bulk folder...

Shane, your link is the closest yet, BUT unfortunately it didn't copy the picture properly.  The picture was copied, but when I pasted, the actual image was shrunk to about 10% and the other 90% was black space.  Have you tried this with any success, Shane?


I did find an interesting work-around though... although it still doesn't completely fit my needs.  If I use a web browser control to display the image, I can right-click it and copy and paste it perfectly.  This also handles a problem I was having with image resolution displaying text very poorly in the image control.  HOWEVER, very very unfortunately, the web browser cannot be resized.  I have a feature set up for my photos to be able to zoom-in and zoom-out... and to do so, the control needs to be resized on the fly.  Go figure, eh?

That said.. since the web browser control offered different features and allows very easy copying - does it remind anyone of any other controls that might also serve as a work-around in a similar fashion?
PlamodoAuthor Commented:
I have thought of another work around.  Take the linked photo that is in the image control and place it in a temporary Word document, and then copy the embedded image in the word document to the clipboard.  Problem is, if I close the word document before I try to paste, the clipboard no longer contains the image.  If I paste before I click "OK" in the messagebox in the code below, it works just as planned.

Is there a way to be able to copy from the Word document and retain the image on the clipboard *after* the word document has been closed?

    Dim strFile As String
    Dim wrdObject As Object
    strFile = Image0.Picture
    Set wrdObject = CreateObject("Word.Application")
    wrdObject.Documents.Open "G:\apddb\templates\PhotoHolder.doc", ReadOnly:=True
    wrdObject.selection.InlineShapes.AddPicture strFile
    MsgBox "Photo copied.", vbInformation
    wrdObject.Quit SaveChanges:=0 'wdDoNotSaveChanges
    Set wrdObject = Nothing
PlamodoAuthor Commented:
Increased points to 500
Rey Obrero (Capricorn1)Commented:
hope this links help

How to Send Information to the Clipboard

How to Retrieve Information from the Clipboard

PlamodoAuthor Commented:
Thanks capricorn.. but those links only cover sending text to the clipboard... images are a different deal all together.
You seem to keep changing between an OLE control and an Image control. Which one are you using, or are you happy to use either?
PlamodoAuthor Commented:
I'm using an Image control.. but I'm cool to use anything that allows the following:

1)  Copying the image in the control to the clipboard
2)  Resizing the control on the fly to create a zoom-in, zoom-out effect.

The webbrowser control lets me do 1), but not 2)
The image control lets me do 2), but not 1)

And a workaround I found was to embed the image (because at run-time I know the file name and location), into a word document with word automation, and copy the object to the clipboard.  This works, UNTIL the document is closed... which seems unavoidable...
The CopyOLEPiccy code that Shane posted should work except for a few things:

1. The Piccy argument is being passed in as an object, but then treated as raw data. You should pass in the Image object, but then reference it's .PictureData property (in the two places it's used), OR, change the Piccy argument to type Byte() (i.e. Byte array) and pass in the Image.PictureData property.

2. It calls SetClipboardData() with the CF_TEXT argument - I think it should be CF_ENHMETAFILE, but I haven't tried it (you are copying an image, not text).

Try 1 first, then try 2 if it doesn't work.

Note you could also resize an img in a web control. But it depends on how you are pointing the webcontrol at the image - either as a direct path (as in: WebControl.Navigate(myImgPath) ) - or as a HTML document with an IMG tag. If it's the latter, you could do the following to resize it programmatically:
webcontrol.Document.All("myImageName").Width = x
webcontrol.Document.All("myImageName").Height = y

What about using an OLE object, setting the focus to the control and then using RunCommand acCmdCopy?

Can't remember if someone suggested that already....
PlamodoAuthor Commented:
apk - I'm trying your suggestions... I'll return with my results in a bit.. and yes, I'm using the webcontrol.navigate format of the webbrowser control, so I guess your suggestion wouldn't apply.

Shane - Yeah.. I've tried the OLE object with acCmdCopy.. but I get errors when I try to set the focus on the OLE.
PlamodoAuthor Commented:
apk - actually.. can you specify where to use the .picturedata property.. After weeding throught the code, I realized I don't know what I'm doing :)

I remember the last time I tried this, it crashed at the len(piccy) statement.
   hGlobalMemory = GlobalAlloc(GHND, Len(Piccy) + 1)
   hGlobalMemory = GlobalAlloc(GHND, Len(Piccy.PictureData) + 1)
and change:
   lpGlobalMemory = lstrcpy(lpGlobalMemory, Piccy)
   lpGlobalMemory = lstrcpy(lpGlobalMemory, Piccy.PictureData)

PlamodoAuthor Commented:
Damn.. never got the notification about apk's last comment back in december.
For the record, apk, I just tried making the changes you indicated, but I get type mismatch error at:

lpGlobalMemory = lstrcpy(lpGlobalMemory, Piccy.PictureData)  '<--- on the picturedata property

Apk - have you actually gotten this to work?
PlamodoAuthor Commented:
ApK - you nailed it.  Works fantastic. (the lebans solution, I mean)

You get the bulk of the points.  I'm gonna give out a few more for everyone else who tried to help me on this one.  What an epic.
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.