Drag&Drop from Outlook (Express) - Possible?
Re: Drag&Drop from Outlook (Express) - Possible?
Yes you can customise the drop completely via the DropTarget_SetEffects() function. Examine the value of *pdwEffect\l to see what drag actions the source allows; it will usually be a combination of #DROPEFFECT_COPY and #DROPEFFECT_MOVE (though there are others) which are the same as #PB_Drag_Copy and #PB_Drag_Move.
In the case of Outlook then, it sounds as if it always sets this value to #DROPEFFECT_COPY on entry to the various drop methods. No reason why you can't allow the drop even if the control key is not down, just ignore the value of grfKeyState.
In the case of Outlook then, it sounds as if it always sets this value to #DROPEFFECT_COPY on entry to the various drop methods. No reason why you can't allow the drop even if the control key is not down, just ignore the value of grfKeyState.
I may look like a mule, but I'm not a complete ass.
- captain_skank
- Enthusiast
- Posts: 639
- Joined: Fri Oct 06, 2006 3:57 pm
- Location: England
Re: Drag&Drop from Outlook (Express) - Possible?
Thunder93 wrote:To drag an email entry from the email program and drop onto the Desktop or Windows Explorer screen, the saved file is of the raw data. As already stated, the attachments data resides in the raw data.
When an email is dropped, it is using a name just extracted from the email subject (except illegal characters usually replaced with something.)
Less is more.
Code: Select all
If OpenWindow(0, 0, 0, 700, 500, "Drag 'n' drop Outlook Express",#PB_Window_SystemMenu|#PB_Window_ScreenCentered) ListIconGadget(1, 10, 10, 680, 100, "Drop Email here", 730) cf_email = RegisterClipboardFormat_("Internet Message (rfc822/rfc1522)") EnableGadgetDrop(1, cf_email, #PB_Drag_Copy) EnableGadgetDrop(1, #PB_Drop_Files, #PB_Drag_Copy) EditorGadget(2, 10, 120, 680, 370) Repeat event = WaitWindowEvent() If event = #PB_Event_GadgetDrop And EventGadget() = 1 Select EventDropType() Case cf_email ClearGadgetItems(1) ClearGadgetItems(2) *buffer = EventDropBuffer() msg$ = PeekS(*buffer) subject = FindString(msg$, "Subject: ", 1) + 9 eos = FindString(msg$, #CRLF$, subject) subject$ = Mid(msg$, subject, eos - subject) AddGadgetItem(1, 0, "Subject: " +subject$) AddGadgetItem(2, 0, msg$) EndSelect EndIf Until event = #PB_Event_CloseWindow EndIf End
I couldn't get this to work as expected, but perhaps I misunderstood what it was supposed to do.
Using Outlook 2010, I can drag message from the Mailbox listing pane in outlook directly to the editor gadget but not the listicongadget, and it will only get the message info as listed in the listing pane - not the message text.
If i drag the message to the desktop and then try and drag that to this window then that wont work at all.
What i'd like to do is drag a message from Outlook's mail box listing pane and drop it into a pb window but retreive the header and body of the mail as text ( I don't need the attachments ), anyone know if this is possible ? if not then I'm ging to have to look at oulook's VBA and I'd rather cut off my left testicle

Re: Drag&Drop from Outlook (Express) - Possible?
Hi captain_skank.
That was just demonstration code that worked for Outlook Express.., but as it was already determined, Microsoft Outlook (non-Express) does things differently.
I don't use Microsoft Outlook. But with PB DragDrop Lib, and with the right registers, it should work.
That was just demonstration code that worked for Outlook Express.., but as it was already determined, Microsoft Outlook (non-Express) does things differently.
I don't use Microsoft Outlook. But with PB DragDrop Lib, and with the right registers, it should work.
ʽʽSuccess is almost totally dependent upon drive and persistence. The extra energy required to make another effort or try another approach is the secret of winning.ʾʾ --Dennis Waitley
Re: Drag&Drop from Outlook (Express) - Possible?
Well, I have made a bit more progress with regular Outlook, but at this point am getting some extremely odd results. I'm sure I'm doing something wrong but cannot for the life of me figure out what.
I am able to detect and successfully process a FileGroupDescriptor and extract it to a StgMedium using the following code:
From that point I can also correctly test for the number of items/files/attachments dropped, using this:
...and indeed if I have dropped 1 attachment, it will show 1. If I drop 3 I'll get 3 as the value the cItems member of the FileGroupDescriptor structure, just as expected.
The odd parts come next, when first I try:
...to examine the filename of the first file dropped. It is always blank and never shows anything. Even stranger, if I examine another member of the FileDescriptor array such as:
...I get a number.. okay fine. Now if I drop the exact same file attachment onto the window again, during the same instance/session, this number (nFileSizeHigh) increases by exactly 8, every single time. So that if the first time it's 4567354, the second time it will be 4567362, and then 4567370, and so on... If this were truly information about the file itself, I'd expect it to remain the same each time, rather than increasing by increments of 8. This is also true with any other numerical member of the filedescriptor array that I test. It's always a number that increases by 8 every time I repeat the drop during the same session.
What's equally bizarre, this number will keep increasing by 8 even if I select a totally different file attachment and drop it onto the window. It's the same number as before, increased by 8, even though it was a different file altogether last time.
Any idea what I'm doing wrong to retrieve both the filename and these other properties?
I am able to detect and successfully process a FileGroupDescriptor and extract it to a StgMedium using the following code:
Code: Select all
With thisFormatEtc
\cfFormat = CF_FILEGROUPDESCRIPTOR
\ptd =#Null
\dwAspect = #DVASPECT_CONTENT
\lindex = -1
\tymed = #TYMED_HGLOBAL
EndWith
If Dataobject\GetData(thisFormatEtc, thisStgMedium) = #S_OK
Debug "Okay"
EndIf
Code: Select all
*fgdbuffer.filegroupdescriptor=thisStgMedium\hGlobal
Debug PeekU(*fgdbuffer\cItems)
The odd parts come next, when first I try:
Code: Select all
Debug PeekS(@*fgdbuffer\fgd[0]\cFileName)
Code: Select all
Debug PeekL(@*fgdbuffer\fgd[0]\nFileSizeHigh)
What's equally bizarre, this number will keep increasing by 8 even if I select a totally different file attachment and drop it onto the window. It's the same number as before, increased by 8, even though it was a different file altogether last time.
Any idea what I'm doing wrong to retrieve both the filename and these other properties?
Re: Drag&Drop from Outlook (Express) - Possible?
Your problem is here :
The hGlobal handle is not a memory pointer!
You have to use GlobalLock_() on the hGlobal which will return a memory pointer. Once you have this, copy it to some allocated memory. Something like :
Code: Select all
*fgdbuffer.filegroupdescriptor=thisStgMedium\hGlobal
Debug PeekU(*fgdbuffer\cItems)
You have to use GlobalLock_() on the hGlobal which will return a memory pointer. Once you have this, copy it to some allocated memory. Something like :
Code: Select all
numBytes = GlobalSize_(thisStgMedium\hGlobal)
If numBytes
*ptr.FILEGROUPDESCRIPTOR = AllocateMemory(numBytes)
If *ptr
*ptrMem = GlobalLock_(thisStgMedium\hGlobal)
If *ptrMem
CopyMemory(*ptrMem, *ptr, numBytes)
GlobalUnlock_(thisStgMedium\hGlobal)
;Now access the *ptr memory block which contains your FileGroupDescriptor structure.
Debug "Num file descriptors = " + Str(*ptr\cItems)
;ETC.
EndIf
FreeMemory(*ptr)
EndIf
EndIf
I may look like a mule, but I'm not a complete ass.
Re: Drag&Drop from Outlook (Express) - Possible?
Ah okay I see, thanks... to me "memory handle" sounds extremely similar to "memory address/pointer" and the MSDN documentation under StgMedium doesn't exactly specify differently, so I was attacking it as such incorrectly. I was also thrown off by the fact that despite my erroneous approach, I was still always getting the correct value returned for the cItems member of FileGroupDescriptor, whenever I'd test by dropping multiple attachments onto the window.
I have used Globallock_() before when dealing with the creation and retrieval of Registry entries, but it's been a while and not something that jumped immediately to mind when working with an HGlobal.
On a completely separate note, I find it odd that:
...only returns 4 as the total size of the FileGroupDescriptor structure, even when only static arrays are being used in each structure. But that's another matter with its own tangential explanation I suppose...
I have used Globallock_() before when dealing with the creation and retrieval of Registry entries, but it's been a while and not something that jumped immediately to mind when working with an HGlobal.
On a completely separate note, I find it odd that:
Code: Select all
Structure FILEDESCRIPTOR
dwFlags.l
clsid.CLSID
sizel.SIZE
pointl.POINT
dwFileAttributes.l
ftCreationTime.FILETIME
ftLastAccessTime.FILETIME
ftLastWriteTime.FILETIME
nFileSizeHigh.l
nFileSizeLow.l
cFileName.c[#MAX_PATH]
EndStructure
Structure FILEGROUPDESCRIPTOR
cItems.l
fgd.FILEDESCRIPTOR[0]
EndStructure
Debug SizeOf(filegroupdescriptor)
Re: Drag&Drop from Outlook (Express) - Possible?
No 4 is absolutely right. The fgd[] static array field is literally a place-holder (depending on how you've defined the structure) because you don't know in advance how many elements will be placed into the array.
You can see it with a simple example :
When you put a PB dynamic array into a structure (using ARRAY) then you are just throwing a pointer to an array into the structure which will of course add 4 bytes (x86) to the size of the structure. With a static array you physically allocate the memory for every array element in the structure itself. With [0] elements then, you allocate 0 bytes! 
In your case, the method you call to retrieve the data returns a FILEGROUPDESCRIPTOR structure with a certain number of FILEDESCRIPTOR structures pasted on the end, and this is the key. No pointers are involved, the structures really are thrown on the end of our FILEGROUPDESCRIPTOR structure which we access through the fgd[] field.
You can see it with a simple example :
Code: Select all
Structure test
a.l
b.POINT[0]
EndStructure
Debug SizeOf(test) ;Outputs 4.

In your case, the method you call to retrieve the data returns a FILEGROUPDESCRIPTOR structure with a certain number of FILEDESCRIPTOR structures pasted on the end, and this is the key. No pointers are involved, the structures really are thrown on the end of our FILEGROUPDESCRIPTOR structure which we access through the fgd[] field.
I may look like a mule, but I'm not a complete ass.
Re: Drag&Drop from Outlook (Express) - Possible?
I notice that if I do:
...It does not throw an "Array Index Out of Bounds" error, even though I've specified zero elements in the static array yet am assigning a value to element number 7. But if I specify 2 or 3 elements, and then try to assign a value to element 7 as above, it gives that error. So I guess PB must treat a [0] element declaration within a structure as though it were a linked list, with an unspecified/unlimited number of elements.
Useful and interesting to know, even if not covered in the documentation.
Code: Select all
Structure one
a.l
b.l
EndStructure
Structure two
c.l
d.one[0]
EndStructure
e.two\d[7]\a=55
...It does not throw an "Array Index Out of Bounds" error, even though I've specified zero elements in the static array yet am assigning a value to element number 7. But if I specify 2 or 3 elements, and then try to assign a value to element 7 as above, it gives that error. So I guess PB must treat a [0] element declaration within a structure as though it were a linked list, with an unspecified/unlimited number of elements.
Useful and interesting to know, even if not covered in the documentation.
Re: Drag&Drop from Outlook (Express) - Possible?
That is deliberate because Windows uses static arrays in exactly the scenarios you have encountered. Whenever an array is needed to be passed or returned, Windows will specify the use of a static array with zero elements (though it will use an index of [1] whereas PB uses [0]) because it cannot know the number of elements it will need / or return before hand. Hence, in these cases, we cannot have the compiler throwing element out of bounds errors. The PB manual does make mention of this in a roundabout way; referring to them as C++ structures etc.
Have a look at the following where such a construct is used to access the individual characters of a string. You can see with this why you don't want an array index out of bounds error.
Have a look at the following where such a construct is used to access the individual characters of a string. You can see with this why you don't want an array index out of bounds error.

Code: Select all
Structure byteReader
c.c[0]
EndStructure
a$ = "Hello!"
*ptr.ByteReader = @a$
For i = 0 To Len(a$) - 1
Debug Chr(*ptr\c[i])
Next
Last edited by srod on Thu Feb 20, 2014 8:46 pm, edited 1 time in total.
I may look like a mule, but I'm not a complete ass.
Re: Drag&Drop from Outlook (Express) - Possible?
@srod,
Thank you for the explanation.
I found the manual rather confusing on this point. Don't use C. Never will now I've found PureBasic!
Thank you for the explanation.

I found the manual rather confusing on this point. Don't use C. Never will now I've found PureBasic!
DE AA EB
Re: Drag&Drop from Outlook (Express) - Possible?
You're welcome Davido. 

I may look like a mule, but I'm not a complete ass.
Re: Drag&Drop from Outlook (Express) - Possible?
To grab names of multiple dropped Outlook messages is the easy part.
Retrieving the data is the tricky part.
If you can't figure it out, you might be-able to work with the the location of the .PST file you can get from the clipboard and with the message name, get the msg contents you are seeking.
Regards to grabbing the names of multiple dropped Outlook messages. Nothing fancy but here's the code:
Edited: Added another line of code under Case #PB_Drop_Text
Retrieving the data is the tricky part.
If you can't figure it out, you might be-able to work with the the location of the .PST file you can get from the clipboard and with the message name, get the msg contents you are seeking.
Regards to grabbing the names of multiple dropped Outlook messages. Nothing fancy but here's the code:
Code: Select all
Structure _FILEDESCRIPTOR
dwFlags.l
clsid.CLSID
sizel.SIZE
pointl.POINT
dwFileAttributes.l
ftCreationTime.FILETIME
ftLastAccessTime.FILETIME
ftLastWriteTime.FILETIME
nFileSizeHigh.l
nFileSizeLow.l
cFileName.c[#MAX_PATH]
EndStructure
Structure _FILEGROUPDESCRIPTOR
cItems.l
fgd._FILEDESCRIPTOR[0]
EndStructure
Enumeration
#ImageSource
#ImageTarget
EndEnumeration
Enumeration
#Window = 0
#TargetOutlook
#TargetMsG
EndEnumeration
If OpenWindow(#Window, 0, 0, 760, 510, "Drag & Drop", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
CreateImage(#ImageSource, 136, 136)
If StartDrawing(ImageOutput(#ImageSource))
Box(0, 0, 136, 136, $FFFFFF)
DrawText(5, 5, "Drag this image", $000000, $FFFFFF)
For i = 45 To 1 Step -1
Circle(70, 80, i, Random($FFFFFF))
Next i
StopDrawing()
EndIf
CreateImage(#ImageTarget, 136, 136)
If StartDrawing(ImageOutput(#ImageTarget))
Box(0, 0, 136, 136, $FFFFFF)
DrawText(5, 5, "Drop images here", $000000, $FFFFFF)
StopDrawing()
EndIf
ListIconGadget(#TargetOutlook, 0, 0, 760, 150, "Outlook Messages" , 749)
EditorGadget(#TargetMsG, 20, 160, 720, 330)
; rfc822_rfc1522 = RegisterClipboardFormat_("Internet Message (rfc822/rfc1522)")
HTML = RegisterClipboardFormat_("HTML Format")
cf_descrip = RegisterClipboardFormat_(#CFSTR_FILEDESCRIPTOR)
cf_content = RegisterClipboardFormat_(#CFSTR_FILECONTENTS)
EnableGadgetDrop(#TargetOutlook, #PB_Drop_Text, #PB_Drag_Copy|#PB_Drag_Move|#PB_Drag_Link)
EnableGadgetDrop(#TargetOutlook, #PB_Drop_Files, #PB_Drag_Copy|#PB_Drag_Move|#PB_Drag_Link)
; EnableGadgetDrop(#TargetOutlook, #PB_Drop_Image, #PB_Drag_Copy|#PB_Drag_Move|#PB_Drag_Link)
If HTML : iFormat = HTML : ElseIf rfc822_rfc1522 : iFormat = rfc822_rfc1522 : EndIf
If iFormat : EnableGadgetDrop(#TargetOutlook, iFormat, #PB_Drag_Copy|#PB_Drag_Move|#PB_Drag_Link) : EndIf
If cf_content : EnableGadgetDrop(#TargetOutlook, cf_content, #PB_Drag_Copy|#PB_Drag_Move|#PB_Drag_Link) : EndIf
If cf_descrip : EnableGadgetDrop(#TargetOutlook, cf_descrip, #PB_Drag_Copy|#PB_Drag_Move|#PB_Drag_Link) : EndIf
dFormat.s
Repeat
Event = WaitWindowEvent()
If Event = #PB_Event_Gadget And EventType() = #PB_EventType_DragStart
ElseIf Event = #PB_Event_GadgetDrop
Select EventGadget()
Case #TargetOutlook
Select EventDropType()
Case #PB_Drop_Text
ClearGadgetItems(#TargetOutlook) : ClearGadgetItems(#TargetMsG)
AddGadgetItem(EventGadget(), -1, "#PB_Drop_Text["+Str(EventDropSize())+"]: " + EventDropText())
AddGadgetItem(#TargetMsG, -1, EventDropText())
Case #PB_Drop_Files : i = 0
Files$ = EventDropFiles() :
Count = CountString(Files$, Chr(10)) + 1
For i = 1 To Count
AddGadgetItem(EventGadget(), -1, "#PB_Drop_Files: " + StringField(Files$, i, Chr(10)))
Next i
Case iFormat
ClearGadgetItems(#TargetOutlook) : ClearGadgetItems(#TargetMsG)
*Buffer = EventDropBuffer()
If HTML
AddGadgetItem(EventGadget(), -1, "[iFormat]: HTML: " + PeekS(*Buffer, 30, #PB_Ascii))
AddGadgetItem(#TargetMsG, -1, PeekS(*Buffer, EventDropSize(), #PB_Ascii))
ElseIf rfc822_rfc1522
msg$ = PeekS(*Buffer, EventDropSize(), #PB_Ascii)
Subject = FindString(msg$, "Subject: ", 1) + 9
eos = FindString(msg$, #CRLF$, Subject)
subject$ = Mid(msg$, Subject, eos - Subject)
AddGadgetItem(EventGadget(), -1, "[iFormat]: rfc822_rfc1522: " + subject$)
AddGadgetItem(#TargetMsG, -1, PeekS(*Buffer, EventDropSize(), #PB_Ascii))
Else
MessageRequester("Default", "[iFormat]: Not Handled: "+Str(EventDropType()), #PB_MessageRequester_Ok | #MB_ICONINFORMATION)
If *Buffer : AddGadgetItem(#TargetMsG, -1, PeekS(*Buffer, EventDropSize(), #PB_Ascii)) : EndIf
EndIf
Case cf_content : MessageRequester("Hey", "#CFSTR_FILECONTENTS is working", #PB_MessageRequester_Ok | #MB_ICONINFORMATION)
Case cf_descrip
dFormat = "[cf_descrip]: "
If HTML : dFormat + "HTML: "
ElseIf rfc822_rfc1522 : dFormat + "rfc822_rfc1522: "
Else : dFormat + "???: "
EndIf
*fgdBuffer._FILEGROUPDESCRIPTOR = EventDropBuffer()
ItemsCount = *fgdBuffer\cItems
ClearGadgetItems(#TargetOutlook) : ClearGadgetItems(#TargetMsG)
For i=0 To ItemsCount-1
eml$ = PeekS(@*fgdBuffer\fgd[i]\cFileName)
AddGadgetItem(EventGadget(), -1, dFormat+eml$)
Next
Default
MessageRequester("Drag&Drop:", "Not Handled: "+Str(EventDropType()), #PB_MessageRequester_Ok | #MB_ICONINFORMATION)
EndSelect
EndSelect
EndIf
Until Event = #PB_Event_CloseWindow
EndIf
End
Edited: Added another line of code under Case #PB_Drop_Text
Last edited by Thunder93 on Fri Feb 21, 2014 1:12 pm, edited 1 time in total.
ʽʽSuccess is almost totally dependent upon drive and persistence. The extra energy required to make another effort or try another approach is the secret of winning.ʾʾ --Dennis Waitley
Re: Drag&Drop from Outlook (Express) - Possible?
Well, I am almost the whole way there and just one step away from saving the Outlook attachment data to a file on disk. The last stumbling block is how to invoke the READ operation on the iStream data object.
In regular WinAPI the function istream_read() is implemented as an independent function that takes three arguments:
http://msdn.microsoft.com/en-us/library ... 85%29.aspx
...the first argument being a pointer to the istream interface which is to act as the source and have its data read. However in PB, the \Read method is baked into the istream interface directly, so that you can use:
mystream.istream\Read(a,b,c)
But as you see it still accepts three arguments, and I'm not sure what it wants as the first one. It certainly doesn't accept a pointer or reference to itself as the read-source, so that argument placeholder almost seems superfluous and unnecessary. I've tried using self-pointers just to test, with no luck. I've tried other values like #Null but still no dice.
Again I'm sure it's something rather obvious but I'm still trying to figure it out...
In regular WinAPI the function istream_read() is implemented as an independent function that takes three arguments:
http://msdn.microsoft.com/en-us/library ... 85%29.aspx
...the first argument being a pointer to the istream interface which is to act as the source and have its data read. However in PB, the \Read method is baked into the istream interface directly, so that you can use:
mystream.istream\Read(a,b,c)
But as you see it still accepts three arguments, and I'm not sure what it wants as the first one. It certainly doesn't accept a pointer or reference to itself as the read-source, so that argument placeholder almost seems superfluous and unnecessary. I've tried using self-pointers just to test, with no luck. I've tried other values like #Null but still no dice.
Again I'm sure it's something rather obvious but I'm still trying to figure it out...
Re: Drag&Drop from Outlook (Express) - Possible?
The first argument points to a buffer into which the data will be placed. The second argument is the size of the buffer in bytes. The 3rd parameter is the address of a variable which will receive the actual number of bytes read. You can pass 0 for this last parameter.
You might want to take a look at the source to my COMdoc utility if you wish to see some iStorage and iStream objects in use.
You might want to take a look at the source to my COMdoc utility if you wish to see some iStorage and iStream objects in use.
I may look like a mule, but I'm not a complete ass.
Re: Drag&Drop from Outlook (Express) - Possible?
Ah right thanks okay I see... didn't realize it was inheriting the Read method from a parent class, ISequentialStream:srod wrote:The first argument points to a buffer into which the data will be placed. The second argument is the size of the buffer in bytes. The 3rd parameter is the address of a variable which will receive the actual number of bytes read. You can pass 0 for this last parameter.
http://msdn.microsoft.com/en-us/library ... 85%29.aspx
I have it working now and successfully accepting file attachment dragdrops from Outlook for saving to disk (or any other operation). I will post the final code shortly once I've cleaned up all of my debug tests and the like. Thanks again for all the valued assistance.