Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Westi on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Dragging external image into a VFP form... Your favorite subject. Drag and Drop... 2

Status
Not open for further replies.

dkean4

Programmer
Feb 15, 2015
282
US
I have done lots of drag and dropping on VFP apps in the past. But tonight I seem unable to make OLE Drag and Drop drag an image from a browser into a VFP form.

First, I have read up on many of the posts in this forum, about dragging images. I even found Jim Booth's tutorial, one I read many many years ago and a few minutes ago. It did not help. So here are the tests.

1.- I can drag in an image from any Windows subdirectory into the image object.
2.- I cannot drag in an image from a browser.

I found out that oDataObject.GetFormat(13) is what the Browser returns and I accommodate for that. That format indicates UNICODE.

And this is how it comes in for one specific image, when I drag the image into a TextBox:
"fig.06x021ntbrentrap/segami/moc.spit-ket.www//:ptth"
CONFUSED?
In reverse it reads ""... clearly I dragged one of your pictures in... but it does that for all images.

So, I can flip it and play with it all I like, but it still does not get me the image. If I was not exhausted from fighting it for the last 2 hours, I would not bother you, but maybe one of you has a bright idea on how to fetch this image from the Website and plant it into my Image object. Can I find this file in the cache? I thought that all files go into the Browser cache, but I cannot find it anywhere on my disks.

CODE IS BELOW________________________________________________________________


The image's OLEDragDrop:

Code:
LPARAMETERS oDataObject, nEffect, nButton, nShift, nXCoord, nYCoord
LOCAL aFiles[ 1 ], nFiles, i, cExt

DO CASE
CASE oDataObject.GetFormat( 15 )[b] OR [COLOR=#EF2929]oDataObject.GetFormat( 13 )[/color][/b]
   * I can handle file data
   * Get the file data into an array
   IF oDataObject.GetData( 15, @aFiles )
      * If we got any set the count
      nFiles = alen( aFiles, 1 )
   ELSE
      * Set the count to 0
      nFiles = 0
   ENDIF
   * Check each of the files
   FOR i = 1 to nFiles
      * Get the extension
      cExt = Upper( JustExt( aFiles[ i ] ))
      IF ( cExt == "BMP" ) or ( cExt == "JPG" ) or ( cExt == "GIF" )
         * If it is a file we can handle
         * Hide the label
         *This.lblDropSpace.Visible = .F.
         * Set the picture property
         This.Picture = aFiles[ i ]
         * Draw he container
         *THIS.Draw
         * Pause for a few seconds in case there was more than one file
         INKEY(2,"H")
     ENDIF
   ENDFOR
   * Set the copy only attribute
   nEffect = 1
   * stop the default action of this drag and drop
   NODEFAULT
CASE oDataObject.GetFormat( "Private Format" )   && Private format
   * I can handle "Private Format" data
   * Hide the label
   *This.lblDropSpace.Visible = .F.
   * Set the picture property
   This.Picture = oDataObject.GetData( "Private Format" )
   * Set the copy attribute
   nEffect = 1
   * Draw the container
   *THIS.Draw
   * Stop the default action of the drag and drop event
   NODEFAULT
ENDCASE


The code in OLEDOver:

Code:
LPARAMETERS oDataObject, nEffect, nButton, nShift, nXCoord, nYCoord, nState
*ThisForm.Activate
ACTIVATE SCREEN 
?oDataObject.GetFormat(1)
?oDataObject.GetFormat(2)
?oDataObject.GetFormat(7)
?oDataObject.GetFormat(13)
?oDataObject.GetFormat(15)
?oDataObject.GetFormat("OLE Variant Array")
?oDataObject.GetFormat("OLE Variant")
?oDataObject.GetFormat("VFP Source Object")


IF nState == 0 && Drag Enter 
   *-- We only need to check out the data format once upon enter 
   DO CASE
   CASE oDataObject.GetFormat( "Private Format" )
      * I can handle drops of "Private Format"
      * Tell OLEDragDrop that I know how to handle this 
      This.OLEDropHasData = 1
      * Tell OLEDragDrop that I want to copy this 
      This.OLEDropEffects = 1
   CASE oDataObject.GetFormat( 15 ) && Files 
      * I can handle drops of files
      This.OLEDropHasData = 1
      This.OLEDropEffects = 1
   CASE [COLOR=#EF2929][b]oDataObject.GetFormat( 13 )[/b][/color] &&  Unicode text format 
      * I can handle drops of files 
      This.OLEDropHasData = 1
      This.OLEDropEffects = 1
   ENDCASE
ENDIF
 
It's funny the url arrives reversed. A joke of a windows developer? Or a browser developer? Perhaps this is a mirror site of tek-tips?

Well, you have a url, you can download it.

Not everything is cached everytime automatically, that depends on cache headers. Let me see:

Code:
o = CREATEOBJECT("msxml2.xmlhttp")
o.open("HEAD","[URL unfurl="true"]http://www.tek-tips.com/images/partnerbtn120x60.gif")[/URL]
o.send()
DO WHILE o.readyState<4
   DOEVENTS force
ENDDO 
? o.getAllResponseHeaders()
This has an ETAG, which points out tek-tips might use some CDN to serve the images (
No browser needs an image file to display it, it can simply download from the given URL and keep that in memory, it may have its internal cache for things, even without any cache, pragma, cache-control or such headers.

To demo the ETAG reducing downloads:
Code:
o = CREATEOBJECT("msxml2.xmlhttp")
o.open("HEAD","[URL unfurl="true"]http://www.tek-tips.com/images/partnerbtn120x60.gif")[/URL]
o.setRequestHeader("If-None-Match",'"087616a5b81c41:0"')
o.send()
DO WHILE o.readyState<4
   DOEVENTS force
ENDDO 
? o.status
If that is still the etag of that image, the status code will be 304. The image was not downloaded anyway, as I used the HEAD request method, but even the head is taken from the cached resource.

In that case the browser should still have the picture somewhere, ask where that could be in browser specific forums.

I'd suggest you simply download the image and use the download, then, emulating what a browser does.

Bye, Olaf.
 
And just to state the obvious: You don't drag the picture itself also in case of dragging from Windows Explorer. You drag file information in that case and HTML tag info in the case of dragging from a browser. The question whether you can get the locally cached resource is really not my expertise, that's most probably also different per browser and that alone also is a problem, or do you get info about the process the drag was started in? I haven't copied and executed your sample code, sorry.

Bye, Olaf.
 
Olaf,

Thank you for the help. As always, great tutorial for me.

I am not familiar with the msxml2.xmlhttp class. Is there any other use for that except for getting data about WEB files? Anything fancy you could tell me about it? I saw a few objects inside and was not able to get at them. Example:
? o.responseStream says that it is an [highlight #FFFFFF](Object)[/highlight]

Sounds interesting. Any way to get at the stream? I tried "? o.responseStream.name" and it goes into an error. Usually I can get something from objects like that in the automation hierarchy.

Is there a quick explanation or tutorial about this class?

Much obliged, Olaf...


Dennis
 
By the way, Olaf... I am able to drag images from Browsers, now. Did some more work on it. I found a way to download the images from websites and it works great. There are several caveats, but I plowed through them.

Dennis
 
Msxml2.xmlhttp is nothing else but the XMLHttpRequest object for IE. It is perhaps the oldest and most downward compatible PROGID (name) of that class working back to Win98. It's just easy to make http requests with it.

The responseXYZ properties are all about the whole http response body in different variants. responseText should always be available even for binary response bodies.

Only seeing (Object) is nothing unusual and even happens in native VFP objects. Not being able to get such a common property as name also isn't unusual for COM objects, they don't necessarily follow VFP norms of standard properties, even though Name is quite common in other programming langauges, too. You also sometimes get no intelllisense, until you copy the object into a variable. So try oStream = o.responseStream and then see what you have.

Besides that, there are simpler download API calls, eg URLDownloadToFile ( It lacks any http details, simply takes a URL and downloads it as the filename you specify. I wanted to get the responseheaders, though, and that's what I usually do via Msxml2.xmlhttp

Bye, Olaf.
 

Olaf,
I know about the variable hop "oStream = o.responseStream", but in this case no! It doesn't give me anything.

Do you know anything about cURL, Olaf?



Dennis
 
I neither use cURL nor the VFP binding since I used WinInet and xmlhttprequest earlier already, but it exists:

Maybe responseStream only has a meaning, if you request asynchronous and therefore have a stream that starts and gets loaded. It may also only be active with streamed mime types like video/audio mime types.

Bye, Olaf.
 
Olaf,

I see how this works. GET, HEAD, OPTIONS and TRACE are the HTTP directives, of course... The GET is the right one, which fetches the file data, though it also seems to get the Headers. I guess the HEAD directive is for when you want the get just attributes of the file.

So with directive GET the ? o.responseBody will show the file data. Very, very nice Olaf. This makes me wonder why all the other examples of how to get the file data are so extensive in code... And after extensive testing, indeed that is the case.
Code:
o = CREATEOBJECT("msxml2.xmlhttp")
o.open("GET","[URL unfurl="true"]http://www.tek-tips.com/images/partnerbtn120x60.gif")[/URL]
o.send()
DO WHILE o.readyState<4
   DOEVENTS force
ENDDO 
? o.responseBody

I tested this and the image comes up perfectly, adding this...
Code:
cNewStr = "[URL unfurl="true"]http://www.tek-tips.com/images/partnerbtn120x60.gif"[/URL]
fileName = SUBSTR(cNewStr,RAT("/",cNewStr)+1)

STRTOFILE(o.responseBody,"f:\"+fileName )

declare integer ShellExecute in shell32;
    integer hwnd,;
    string  lpOperation,;
    string  lpFile,;
    string  lpParameters,;
    string  lpDirectory,;
    integer nShowCmd

ShellExecute(0, "open","f:\"+fileName,0,0,1)


Brilliant, Olaf! This totally rocks! Thank you so much.

Superlative...

Olaf, what about "XMLHttpRequest level 2", can VFP make use of it? I understand that it is richer in its offering... more features.

Dennis
 
Well, as McDonalds and Microsoft said in other contexts, http reponse headers are an integral part of http responses. Always headers and body, The body is empty when you only request the headers and also in many cases of status codes other than 200 (OK), eg the infamous 404 not found error status.

Only headers and body, no arms, legs, hands and footers ;). There also is no mail without headers, though you'll seldom get them displayed.

URLDownloadToFile needs less code:
Code:
DECLARE INTEGER URLDownloadToFile IN urlmon INTEGER, STRING, STRING, INTEGER, INTEGER

cURL = "[URL unfurl="true"]http://www.tek-tips.com/images/partnerbtn120x60.gif"[/URL]
cFileName = JUSTFNAME(cURL)
= URLDownloadToFile(0, cURL, cfileName, 0,0) 
_screen.picture = cFileName
But you have less control.

Level 2? Well, the latest state seems to be: deprecated before having become a standard: Latest previous versíon: Just a specification, no implementation or documentation of an implementation.

Later versions of msxml have later classes of xmlhttp, so if you want most features and don't care for older OSes (even Vista is already outdated today) take a look at thread184-1715949 and the links in there.

Bye, Olaf.
 
By the way, did you use the OLE Drag&Drop Fun code at first? This has a text reverse programmed in the OleDragDrop event of one textbox. It's not native behaviour.

Bye, Olaf.
 
Awesome post, Yoda... errr... I mean Olaf. Takes me a while to catch on to all you are saying to me. I have been reading through myriad articles since this post yesterday. Tell me. though, what incarnation of XMLHTTP are you using in development with VFP?

Also, URLDownloadToFile seems to be faster. Way better than what I was doing. I'm not sorry, though. Now I see the differences.

Thanks Olaf.

 
I did not look closely, at the code I copied, at first. And I deleted it and made many adjustments to get what I want. But I like the "URLDownloadToFile". It pushes the file data into the new file automatically and it is faster in my experiments. You have a sharp eye, Olaf.

Dennis
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top