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 gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

More annoying Ole Drag and Drop 1

Status
Not open for further replies.

Scott24x7

Programmer
Jul 12, 2001
2,828
JP
So I decided it would be far easier from the user interface perspective if I allowed users to drop image files dragged from browser sessions directly onto their control, instead of having to first download load them and then pick them from a directory.

However... the Ole control on this proves to be very complicated, and as yet, I can't figure it out, so seeking some guidance from the community.

It's fairly straight forward at the conceptual level. I have an Image object that has all the necessary OLE bits turned on to accept a Ole drop. But I can't figure out once I drop my item on it, how to manipulate it. (I can create a messagebox that states "Something was dropped" but that's about the extent.

I assume that what is being dropped when dragging an image from a web page is a reference to the image (the name of the file and it's location). If I drag and drop it into a directory in windows, the file just appears there as <filename.ext> and the browser completes a "Download" (shows me on the result bar that the file is there). So obviously windows can handle this kind of "understanding" of what the object is.

How do I manipulate it in VFP to do the same thing? I assume that what I need to do is:

a) "recognize" the object
b) parse the object as some kind of array?
c) Save the image file somewhere (the somewhere is the easy part the "Tell VFP to Save something from the internet" part is what I don't understand how to "tell" it to do it.
d) update my control with reference to the object (also easy)

So steps c and d I think I can manage, it's the a and b that I'm totally stumpped over.


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Scott,

If I've understood the question right, the answer to a. is that you call the GetData method. You do this in the OLEDragDrop event. You pass a format code to GetData, along with the name of an array. Teh method fills the array with the relevant data, which in this case will be a list of filenames (or just a single filename if that is what the user is dragging).

The format code that you need to pass is 15. To quote from the Help:

CF_FILES or CF_HDROP 15 A handle that identifies a list of files, such as a set of files dragged from the Windows Explorer.

The array is just a normal VFP array, so you can loop through it in the normal way. (Again, it will probably be just one array element in this case, but the principle is the same.)

So now you know the name of the file that the user is dropping. The final step is simply to set the Image control's Picture property to point to that filename.

If I've misunderstood the question, my apologies.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Sorry, Scott. I hadn't taken in that you are dragging from a web browser. In that case, the basic idea is the same. But the array will be filled with the URLs of the files, rather than just the filenames. So, given a URL, you need a way to download the relevant file, and store it in a local directory.

There are various ways of doing that. The method I use is the Internet Transfer Control, which is one of the ActiveX controls that come with VFP. You would call the controls' OpenURL method, passing the URL in question. That will return the image file to a local variable, which you can then save to disk by means of STRTOFILE(). Once the file is in a local directory, you point the Image's Picture property to it, as described previously.

There is documentation for the Internet Transfer Control on the Microsoft site. If you need any help with it, just yell.

Mike



__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
I think that's mostly what I'm after, but I may be confused about the "Save the file" step.
Is there anything magical I need to tell VFP to initiate a download from the internet (which mast happen to copy the file from the browser to the PC)?
Maybe I'm over complicating that step.

I mean, if I just pass the file name being dragged to a COPY FILE (lcFilename) that I pluck out of the object array?

Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Just one more point. Before calling GetData, it might be a good idea to call GetFormat. This will let you check that the drag object does indeed contain a URL. This will help you avoid problems if the user inadvertently dragged a piece of text, for example.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
This program is perfect for downloading files from Internet. There are easier versions, but this is the very best, I have used it without problems for years.

[pre]
*Strtofile(GetDatafromUrl(lcYourUrl),lcYourFile)
*
*GetDatafromUrl.prg
LPARAMETERS pcUrlName
DECLARE INTEGER InternetOpen IN wininet.DLL STRING sAgent, ;
INTEGER lAccessType, STRING sProxyName, ;
STRING sProxyBypass, INTEGER lFlags

DECLARE INTEGER InternetOpenUrl IN wininet.DLL ;
INTEGER hInternetSession, STRING sUrl, STRING sHeaders,;
INTEGER lHeadersLength, INTEGER lFlags, INTEGER lContext

DECLARE INTEGER InternetReadFile IN wininet.DLL INTEGER hfile, ;
STRING @sBuffer, INTEGER lNumberofBytesToRead, INTEGER @lBytesRead

DECLARE short InternetCloseHandle IN wininet.DLL INTEGER hInst

#DEFINE INTERNET_OPEN_TYPE_PRECONFIG 0
#DEFINE INTERNET_OPEN_TYPE_DIRECT 1
#DEFINE INTERNET_OPEN_TYPE_PROXY 3
#DEFINE SYNCHRONOUS 0
#DEFINE INTERNET_FLAG_RELOAD 2147483648
#DEFINE CR CHR(13)

local lsAgent, lhInternetSession, lhUrlFile, llOk, lnOk, lcRetVal, lcReadBuffer, lnBytesRead

* what application is using Internet services?
lsAgent = "VPF 5.0"

lhInternetSession = InternetOpen( lsAgent, INTERNET_OPEN_TYPE_PRECONFIG, ;
'', '', SYNCHRONOUS)

* debugging line - uncomment to see session handle
* WAIT WINDOW "Internet session handle: " + LTRIM(STR(hInternetSession))

IF lhInternetSession = 0
WAIT WINDOW "Internet session cannot be established" TIME 2
RETURN .null.
ENDIF

lhUrlFile = InternetOpenUrl( lhInternetSession, pcUrlName, '', 0, ;
INTERNET_FLAG_RELOAD, 0)

* debugging line - uncomment to see URL handle
* WAIT WINDOW "URL Handle: " + LTRIM(STR(hUrlFile))

IF lhUrlFile = 0
WAIT WINDOW "URL cannot be opened" Timeout 5
RETURN .null.
ENDIF

lcRetVal = ""
llOk = .t.

DO WHILE llOK
* set aside a big buffer
lsReadBuffer = SPACE(32767)
lnBytesRead = 0
lnOK = InternetReadFile( lhUrlFile, @lsReadBuffer, LEN(lsReadBuffer), @lnBytesRead)

if ( lnBytesRead > 0 )
lcRetVal = lcRetVal + left( lsReadBuffer, lnBytesRead )
endif

* error trap - either a read failure or read past eof()
llOk = ( lnOK = 1 ) and ( lnBytesRead > 0 )
ENDDO

* close all the handles we opened
InternetCloseHandle( lhUrlFile )
InternetCloseHandle( lhInternetSession )

* return the URL contents
RETURN lcRetVal
[/pre]
 
Ok, so so far what I've been able to do is I drag the image from the page and drop it onto my control.
In the OLEDragDrop Event I used the code from the Samples example that (I think it was Mike or Griff) pointed out to me last time.

There is a CASE statement here that checks the "GetFormat", and when I drop the image the CASE that it meets is GetFormat(1) - Text... I output that using a MESSAGEBOX(cText) which collected the result from the GetData(1)

The result shows me only the URL of the web site, but nothing about the file.
Should I be passing it some other parameter?


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
tbleken,
This looks really interesting. Can you help explain a couple of things here though?
There is an lsAgent value, which is set in your code to "VFP 5.0". Should I change this to VFP 9.0 for my use? Does this actually tell Windows something necessary, or is it optional?

I've put the code into my COMMON.PRG and made this a procedure called GETDATAFROMURL so I assume that will allow me to make a call to:
GETDATAFROMUSL(lcURLVariable) (where there is a parameter pcUrlName to pass in)
So I assume if I can get the OLEDragDrop to pass the fully qualified URL with the file name in it as the lcURLVariable then it would execute that.
And then to give the full effect, I create a location string to drop the file in, which is then used with:
STRTOFILE(GETDATAFROMURL(lcURLVariable),lcStorageLocation) where lcStorageLocation is some string I put together to show the directory that it needs to go to?

Now if I can just get the OLEDragDrop to provide me with the full URL, this should be Bob's your Uncle. Right?


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Scott, you wrote:

Now if I can just get the OLEDragDrop to provide me with the full URL, this should be Bob's your Uncle.

Have you done what I suggested in my first post, above? That is, call the GetData method from the drop object's OLEDragDrop event? I think that will answer that part of your question.

Mike



__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Mike,
Yes, that is what I have done, and where I have done it. But when I check the value of cText, it is only showing me the URL of the site, and not the fully qualified URL including the image name... :/

tbleken,
I tried this, but I get an error (both in my common or if I moved it out to its own .PRG and called that with the parameters passed), an error message that:
"Variable 'HINTERNETSESSION' is not found."

I see it in the DECLAIR, so I don't understand why this isn't working?
Or is it because the URL it's getting passed does not have the right data in it?


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Hi Mike,
I'm trying your method, found the ActiveX control, but I've no idea how it works.
I tried putting it on the form, next to the image, gave the control a name of actXInternet and then passed it (calling from the drop target):

lcFilename = This.Parent.zctXinternet.OpenURL(cText)

But I get a "Type Mismatch" error on that line. I'm trying couple other things... do I need to assign it? Macro-sub cText?


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Scott, I'm not sure what you've got in cText. The array (whose name you pass to GetData) should contain a complete URL. I just tested it, and this is what I got in the (single) array element:

[ignore][/ignore]

Your call to OpenURL looks OK. But what does cText contain? And what data type is it? It should be a string, containing the URL. After the call, lcFileName should contain the actual image (in a binary format), not a filename. You pass that binary data to STRTOFILE()

STRTOFILE(lcFileName, lcDestination)

and lcDestination will then contain the name of the file that you point the Image to.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Hi Mike,
This is really painful... the kind of stuff that should not be this hard, but wow, there is just nothing in documentation.

Ok, so here's what I have (I will remove unrelated code from the example)

On the OLEDragDrop Event I have (note this code came from the Example in the VFP9 Samples directory:

Code:
LPARAMETERS oDataObject, nEffect, nButton, nShift, nXCoord, nYCoord
LOCAL aValues, i, cText, nOperation

*-- Check to see whether the user wants to copy or move
IF nShift == 1
	nOperation = 1	&&DROPEFFECT_COPY
ELSE
	nOperation = 2	&&DROPEFFECT_MOVE
ENDIF

Thisform.LockScreen = .T.
DO CASE
CASE oDataObject.GetFormat(1)		&& Text
	cText = oDataObject.GetData(1)

*-- Add the text as a new item in the list
	This.AddItem(cText) && I added this method to the Image Object, as it's not present otherwise.
	lcFileSave = "T:\DEVELOPMENT\FOXTEST\DCIDE\LOGOS\Logo.png" && just forcing this for ease of finding at the moment.  I have gotten logo.png to write but only at 0 bytes
	STRTOFILE(This.Parent.oleInternet.OpenURL("cText"),lcFileSave)
*
ENDCASE

Thisform.LockScreen = .F.

*-- Set the nEffect parameter for communication back to the source object
nEffect = nOperation

I've tried 2 things, one just dragging and dropping the image from the web page (you can try and it is their logo file).
But when I drop that all GetData(1) returns me is I right clicked the image on that page, and select "Copy image URL", I pasted that result into the page address bar it shows the logo on screen, and that URL. If I drag and drop THAT image on the control, then I see the full path from GetData(1), but when the "write" completes, I have only an empty file of 0 bytes.

I'm wondering if maybe I'm not defining enough parameters or the right ones for all the data? The oDataObject apparently is only that, and contains only 1 item (it's not an array... maybe I'm looking at this wrong).

Does it work when you use the base URL and drag the image off? Maybe then I am missing something?


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Scott,

Two things jump out at me. First, in your STRTOFILE(), cText should not be in quotes. As it stands, it will be looking for a URL named cText, which is wrong. Instead, you need cText to be a variable which contains the URL.

Second, you are passing 1 to GetData and GetFormat. Is that you want? That will only work if the user actually drags some text from the web page. I understood you want them to drag an image. If so, the parameter should be 15.

Also, testing nShift is redundant, as the user cannot move an object from a webpage; they can only copy it. But that's not a key issue.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Mike,
I got a number of erros when trying to pass cText to STRTOFILE() but maybe there was some other issue.
The very odd thing I still see, and I'm not sure the answer to this, if you go to the URL I mentioned and drag their logo direct to a directory, it saves it there. But if you drag that same logo to an image control and try to drop it there, it ONLY sees the site URL. That's what I'm getting. There has to be something else going on in between there. It doesn't recognize the drag (in VFP at least) as anything other than text.
The GETDATA() function only accepts parameters 1, 7, 13 and 15. I left out the other CASE statements, all of which are tested, and all of which get passed until it reaches (1). Same for GETDATA, they both only accept those tests for formats. It does not recognize a file dragged from a browser dropped onto it as a CF_FILES it only recognizes it as a CF_TEXT which is fine, so long as that text contains the name of the file coming with it. I tried another site, and their logo drags and drops as " (And if you drag and drop them to a form while editing, it will show you exactly that as well). So I'm now guessing in the "modern internet" there are techniques that "mask" that image in some way, or it gets passed into an array that Windows Explorer can understand, but not an OLEDragDrop in VFP... unless there is some parameter that is passed. I thought maybe it was an array, but I can find no additional elements. Is this something I have to give up on? At least for logos that don't "drag" with their name attached?

BTW, I just got this to work using the procedure suggested by tbleken after fixing a few bugs it had... I had "uncommented" the "test code" and that had a variable named incorrectly in it, so that was where it crashed. BUT it only worked on the EPI logo with name attached, and not on the Equinix logo when dragging just from the home page.

Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Hi Mike,
Went back to your suggested method again, because I think it may be more accurate/reliable at the end of the day, and because I want to see it work... >:|

So I changed the STRTOFILE call as you suggested, this is now the real "executing lines":

Code:
cText = oDataObject.GetData(1)
This.AddItem(cText)
lcFileSave = "T:\DEVELOPMENT\FOXTEST\DCIDE\LOGOS\Logo.png"
STRTOFILE(This.Parent.oleInternet.OpenURL(cText),lcFileSave)

BUT when it executes STRTOFILE I get this error message:

OLE IDispatch exception code 0 from Inet: Type mismatch.
And the identified line of occurrence is: STRTOFILE(This.Parent.oleInternet.OpenURL(cText),lcFileSave)

Since the only thing that changed is the cText variable, which I can also verify had the contents: " in it.


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Found another intenet oddity...
So I was just poking around to see what other things migh occur.
If you grab an image from LinedIn, it carries with it as its value "javascript:void(0)" if you drag it onto VFP. But if I drag the same image directly to a directory, it has some funky long value like "AAAAAQAAAJPQQQAGJQuzGzg.JPG"

So it's doing something weird there, that I suspect due to VFP's age, and the more modern internet controls, that these can't be parsed by OLEDragDrop properly given the limitations of GetData and GetFormat... :(


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
The fact that the message indicates a type mismatch suugests that it is unhappy with cText. Can you double-check that cText contains a character string.

Another possibility: Pass 1 (numeric) as an additional parameter to OpenURL:
[tt]
... This.Parent.oleInternet.OpenURL(cText, 1) .....[/tt]

That will tell it to expect binary data (although I've never needed to do this, so it might be a waste of time).

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Will give it a try.
BTW, I have a MESSAGEBOX(cText) immediately preceding the OpenURL call so I can see exactly what it's getting before it executes...


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top