jasonrcox
asked on
How to "Send To" in Visual Basic Code
I have an application that displays a list of items. Some of these items might have a file associated with them. I am wanting to allow the user to right-click one or more items and select from the Standard "Send To" menu.
I have been able to create the "Send To" menu by obtaining the proper folder where the send to shortcuts are stored (i.e. c:\documents and settings\jason\send to) and adding each of the shortcuts to my popup menu dynamically.
I do not know what mechanism is used to actually "Send To". I think it has something to do with Drag-and-Drop and/or the Clipboard but I cannot find any documentation on how to interact with these send to items programatically.
Thanks for your help.
I have been able to create the "Send To" menu by obtaining the proper folder where the send to shortcuts are stored (i.e. c:\documents and settings\jason\send to) and adding each of the shortcuts to my popup menu dynamically.
I do not know what mechanism is used to actually "Send To". I think it has something to do with Drag-and-Drop and/or the Clipboard but I cannot find any documentation on how to interact with these send to items programatically.
Thanks for your help.
listening
Hi
Take a look at http://www.mvps.org/btmtz/shellmenu/
Just add to mMenuDefs.bas:
'Declaration area:
Private Declare Function GetMenuItemCount Lib "user32" (ByVal hMenu As Long) As Long
Private Declare Function GetSubMenu Lib "user32" (ByVal hMenu As Long, ByVal nPos As Long) As Long
Private Declare Function GetMenuString Lib "user32" Alias "GetMenuStringA" (ByVal hMenu As Long, ByVal wIDItem As Long, ByVal lpString As String, ByVal nMaxCount As Long, ByVal wFlag As Long) As Long
' Public Function ShowShellContextMenu(...)
' </optional>
' ========================== ========== ========== =====
' </optional>
' ========================== ========== ========== =====
' ==================ADDED=== ========== ========== =====
Dim nCount As Long, i As Long, nLength As Long
Dim sMenu As String
nCount = GetMenuItemCount(hMenu)
For i = 0 To nCount - 1
sMenu = Space$(256)
nLength = GetMenuString(hMenu, i, sMenu, Len(sMenu), MF_BYPOSITION)
sMenu = Left(sMenu, nLength)
If sMenu = "Îòïðàâèò&ü" Then
hMenu = GetSubMenu(hMenu, 13)
Exit For
End If
Next i
' ========================== ========== ========== =====
Run app and click on folder - you'll see SendTo PopUp menu
Take a look at http://www.mvps.org/btmtz/shellmenu/
Just add to mMenuDefs.bas:
'Declaration area:
Private Declare Function GetMenuItemCount Lib "user32" (ByVal hMenu As Long) As Long
Private Declare Function GetSubMenu Lib "user32" (ByVal hMenu As Long, ByVal nPos As Long) As Long
Private Declare Function GetMenuString Lib "user32" Alias "GetMenuStringA" (ByVal hMenu As Long, ByVal wIDItem As Long, ByVal lpString As String, ByVal nMaxCount As Long, ByVal wFlag As Long) As Long
' Public Function ShowShellContextMenu(...)
' </optional>
' ==========================
' </optional>
' ==========================
' ==================ADDED===
Dim nCount As Long, i As Long, nLength As Long
Dim sMenu As String
nCount = GetMenuItemCount(hMenu)
For i = 0 To nCount - 1
sMenu = Space$(256)
nLength = GetMenuString(hMenu, i, sMenu, Len(sMenu), MF_BYPOSITION)
sMenu = Left(sMenu, nLength)
If sMenu = "Îòïðàâèò&ü" Then
hMenu = GetSubMenu(hMenu, 13)
Exit For
End If
Next i
' ==========================
Run app and click on folder - you'll see SendTo PopUp menu
Oops, sorry,
If sMenu = "Îòïðàâèò&ü" Then '->Change menu name to your locale, ="Send&To", for example
If sMenu = "Îòïðàâèò&ü" Then '->Change menu name to your locale, ="Send&To", for example
ASKER
I don't think this will help me. My application does not expose actual Windows files or folders. The list of items I am referring to is nothing more that a data grid. Some rows in the grid may have a file associated with the data. I am wanting to allow the user to right-click on the item in my data list and if there is a file associated with one or more of the highlighted items, I want to offer the Send To menu to them. If the user selects one of the send to items from the menu, what do I do to deliver the associated file to the designated Send To item selected from the pop-up menu?
I am already able to display the "Send To" menu but once the user clicks on an item, I have no idea how to deliver the file associated with the entry in my data grid to the selected "Send To" item from the menu.
I am already able to display the "Send To" menu but once the user clicks on an item, I have no idea how to deliver the file associated with the entry in my data grid to the selected "Send To" item from the menu.
Hi
There are no problem with *.lnk files - just retrive target path and use
Shell sTargetPath & " " & sFileName
But I've no idea on using Drop Targets, like desktop/mydocs, in VB - in C++ you can use IDropTarget interface, but for VB you have to make *.tlb for this interface.
There are no problem with *.lnk files - just retrive target path and use
Shell sTargetPath & " " & sFileName
But I've no idea on using Drop Targets, like desktop/mydocs, in VB - in C++ you can use IDropTarget interface, but for VB you have to make *.tlb for this interface.
ASKER
Hi Ark, thanks for the help. I wish I could figure out how to send to Drop Targets from a VB app! I've seen lots of information on creating a Drop Target via the IDropTarget interface but I just need to be able to send to existing drop targets. If you think of anything else, I would really appreciate it.
Thanks Again!
Thanks Again!
Hi
Unfortunatelly, I've no time today to experiment with IDropTarget, but if you need *.lnk implementation (Web Publishing wisard etc), just let me know. Hope try DropTarget tomorrow
Unfortunatelly, I've no time today to experiment with IDropTarget, but if you need *.lnk implementation (Web Publishing wisard etc), just let me know. Hope try DropTarget tomorrow
ASKER
I just understood what you were talking about. I now understand that if the "Send To" item is a shortcut I can get the target and then shell with my file as the parameter. That does cover some of the items that are likely to appear in the Send To menu. I am most interested in items like "Mail Recipient" and "Compressed Folder" and such which are actual drop targets and not shortcuts. I look forward to seeing what you are able to learn about the drop targets.
If you definitely know items of interest, you can get some work arount and not use IDropTarget interface. For example (pseudo code)
Select Case extension
Case .MAPIMail Then
Some code using MAPI/Outlook to open send form filled with "To:", "CC:", "Subject:", "Att:", "Body:" fields
Case .ZFSendToTarget Then
Some code opened ZIP folder with file specified
Case .mydocs
Some code to copy file to "MyDocuments" folder
Case .desklink
Some code to add link to your file on desktop
Case .lnk
Some code to resolve target path and call Shell sTargetPath & " " & sFileName
Case Else 'donno yet
EndSelect
Select Case extension
Case .MAPIMail Then
Some code using MAPI/Outlook to open send form filled with "To:", "CC:", "Subject:", "Att:", "Body:" fields
Case .ZFSendToTarget Then
Some code opened ZIP folder with file specified
Case .mydocs
Some code to copy file to "MyDocuments" folder
Case .desklink
Some code to add link to your file on desktop
Case .lnk
Some code to resolve target path and call Shell sTargetPath & " " & sFileName
Case Else 'donno yet
EndSelect
ASKER
Thats a good idea. If I am forced to implement my own code for the drop targets, I will probably just ignore what is available in the Send To and make my own set of actions like you have suggested. I will hold out just a little longer...
ASKER
I am bumping up the points cause this appears to be very difficult.
Hi
Found an easy and interesting workaround:
'Using menu editor add 2 menus:
'1. - top level menu, Caption = "SendTo", Name = AnyYourWant
'2. - Child of first level menu, Caption=AnyYouWant, Name = mnuSendToItem, Index=0
Const ssfSENDTO = 9
Const sTestFile = "C:\test.txt"
Dim sSendToPath As String
Dim oShell As Object
Private Sub FillMenu()
Dim i As Integer
Dim fld As Object
Set fld = oShell.NameSpace(ssfSENDTO )
sSendToPath = fld.Self.Path
For Each f In fld.Items
If i > 0 Then
Load mnuSendToItem(i)
End If
mnuSendToItem(i).Caption = f.Name
mnuSendToItem(i).Tag = f.Path
i = i + 1
Next
End Sub
Private Sub Form_Load()
Set oShell = CreateObject("Shell.Applic ation")
FillMenu
End Sub
Private Function GetExtension(ByVal sPath As String) As String
Dim nPos As Integer
nPos = InStrRev(sPath, ".")
If nPos Then GetExtension = Mid(sPath, nPos)
End Function
Private Function GetFolderPath(ByVal sPath As String) As String
Dim nPos As Integer
nPos = InStrRev(sPath, "\")
If nPos Then GetFolderPath = Left(sPath, nPos - 1)
End Function
Private Function GetFileName(ByVal sPath As String) As String
Dim nPos As Integer
nPos = InStrRev(sPath, "\")
If nPos Then GetFileName = Mid(sPath, nPos + 1)
End Function
Private Sub Form_Unload(Cancel As Integer)
Set oShell = Nothing
End Sub
Private Sub mnuSendToItem_Click(Index As Integer)
Dim sPath As String
Dim oSource As Object, oTarget As Object
sPath = mnuSendToItem(Index).Tag
Set oSource = oShell.NameSpace(GetFolder Path(sTest File)).Par seName(Get FileName(s TestFile))
Set oTarget = oShell.NameSpace(GetFolder Path(sPath )).ParseNa me(GetFile Name(sPath ))
oSource.InvokeVerb ("copy")
oTarget.InvokeVerb ("paste")
Set oTarget = Nothing
Set oSource = Nothing
End Sub
Found an easy and interesting workaround:
'Using menu editor add 2 menus:
'1. - top level menu, Caption = "SendTo", Name = AnyYourWant
'2. - Child of first level menu, Caption=AnyYouWant, Name = mnuSendToItem, Index=0
Const ssfSENDTO = 9
Const sTestFile = "C:\test.txt"
Dim sSendToPath As String
Dim oShell As Object
Private Sub FillMenu()
Dim i As Integer
Dim fld As Object
Set fld = oShell.NameSpace(ssfSENDTO
sSendToPath = fld.Self.Path
For Each f In fld.Items
If i > 0 Then
Load mnuSendToItem(i)
End If
mnuSendToItem(i).Caption = f.Name
mnuSendToItem(i).Tag = f.Path
i = i + 1
Next
End Sub
Private Sub Form_Load()
Set oShell = CreateObject("Shell.Applic
FillMenu
End Sub
Private Function GetExtension(ByVal sPath As String) As String
Dim nPos As Integer
nPos = InStrRev(sPath, ".")
If nPos Then GetExtension = Mid(sPath, nPos)
End Function
Private Function GetFolderPath(ByVal sPath As String) As String
Dim nPos As Integer
nPos = InStrRev(sPath, "\")
If nPos Then GetFolderPath = Left(sPath, nPos - 1)
End Function
Private Function GetFileName(ByVal sPath As String) As String
Dim nPos As Integer
nPos = InStrRev(sPath, "\")
If nPos Then GetFileName = Mid(sPath, nPos + 1)
End Function
Private Sub Form_Unload(Cancel As Integer)
Set oShell = Nothing
End Sub
Private Sub mnuSendToItem_Click(Index As Integer)
Dim sPath As String
Dim oSource As Object, oTarget As Object
sPath = mnuSendToItem(Index).Tag
Set oSource = oShell.NameSpace(GetFolder
Set oTarget = oShell.NameSpace(GetFolder
oSource.InvokeVerb ("copy")
oTarget.InvokeVerb ("paste")
Set oTarget = Nothing
Set oSource = Nothing
End Sub
ASKER
Now thats what I am talking about! I will try this today. Thanks!
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thanks Ark. It works! I have learned a lot about the shell and its possible uses beyond my original question because of this. My only wish is that it would be possible to manipulate the FolderItems collection by adding and removing items programatically. Then, I could more easily do "send to" processes to multiple files at the same time. In my program, I ended up having to copy all of the selected item's associated files to a temporary folder and then obtain the folderitems collection from that Folder. Then, I invoke the InvokeVerbEx method to copy the entire group at once. This is important for sending multiple files for example to a mail recipient in one email instead of a separate email for each file. Take a look (You should add a reference to Shell32.dll to your VB project):
Private Sub mnuSendToList_Click(Index As Integer)
' Handle the selected Send To menu item
Dim fso As New FileSystemObject
Dim SelectedCount As Long
Dim iCounter As Long
Dim rs As ADODB.Recordset
Dim oShell As New Shell
Dim oSource As Folder2
Dim oTarget As FolderItem
Dim oSourceItems As FolderItems
Dim tfld As Folder
On Error Resume Next
' Lets create a temporary folder where we can deposit the files
If fso.FolderExists(fso.GetSp ecialFolde r(2) & "\tsendto") Then
' delete the folder
fso.DeleteFolder fso.GetSpecialFolder(2) & "\tsendto", True
End If
Set tfld = fso.CreateFolder(fso.GetSp ecialFolde r(2) & "\tsendto")
SelectedCount = frmDataList.objDocList.p.S electedCou nt
' Loop through the recordset and process any items with file attachments:
For iCounter = 0 To SelectedCount - 1
' Check for a file attachment
If frmDataList.objDocList.p.S electedNod es(iCounte r).Values( 2) = 2 Then ' if the value is 2, this record has an attachment
' Get the source file
Set rs = cnn.Execute("SELECT [Filename] from tblDocuments WHERE DocID = " & frmDataList.objDocList.p.S electedNod es(iCounte r).KeyFiel dValue)
If Not rs Is Nothing Then
' Copy it to the temp folder
fso.CopyFile GetStoreFile(rs.Fields("fi lename").V alue), tfld.Path & "\"
End If
End If
Next iCounter
' now, lets get the folder items in the temp path
Set oSource = oShell.NameSpace(tfld.Path )
Set oSourceItems = oSource.Items
oSourceItems.InvokeVerbEx "copy"
Set oTarget = oShell.NameSpace(0).ParseN ame(mnuSen dToList(In dex).Tag)
oTarget.InvokeVerb "paste"
' Clear the temp folder
'I learned that the temp folder clean up has to happen on application exit because it is possible
' and likely that the paste process is not yet complete when the folder is deleted by the following command.
' Therefore, I have commented it out and clean up later.
'tfld.Delete True
Set oTarget = Nothing
Set oSource = Nothing
Set oSourceItems = Nothing
Set oShell = Nothing
Set rs = Nothing
Set fso = Nothing
Set tfld = Nothing
End Sub
Sorry it took me so long to accept your answer and thanks again.
Private Sub mnuSendToList_Click(Index As Integer)
' Handle the selected Send To menu item
Dim fso As New FileSystemObject
Dim SelectedCount As Long
Dim iCounter As Long
Dim rs As ADODB.Recordset
Dim oShell As New Shell
Dim oSource As Folder2
Dim oTarget As FolderItem
Dim oSourceItems As FolderItems
Dim tfld As Folder
On Error Resume Next
' Lets create a temporary folder where we can deposit the files
If fso.FolderExists(fso.GetSp
' delete the folder
fso.DeleteFolder fso.GetSpecialFolder(2) & "\tsendto", True
End If
Set tfld = fso.CreateFolder(fso.GetSp
SelectedCount = frmDataList.objDocList.p.S
' Loop through the recordset and process any items with file attachments:
For iCounter = 0 To SelectedCount - 1
' Check for a file attachment
If frmDataList.objDocList.p.S
' Get the source file
Set rs = cnn.Execute("SELECT [Filename] from tblDocuments WHERE DocID = " & frmDataList.objDocList.p.S
If Not rs Is Nothing Then
' Copy it to the temp folder
fso.CopyFile GetStoreFile(rs.Fields("fi
End If
End If
Next iCounter
' now, lets get the folder items in the temp path
Set oSource = oShell.NameSpace(tfld.Path
Set oSourceItems = oSource.Items
oSourceItems.InvokeVerbEx "copy"
Set oTarget = oShell.NameSpace(0).ParseN
oTarget.InvokeVerb "paste"
' Clear the temp folder
'I learned that the temp folder clean up has to happen on application exit because it is possible
' and likely that the paste process is not yet complete when the folder is deleted by the following command.
' Therefore, I have commented it out and clean up later.
'tfld.Delete True
Set oTarget = Nothing
Set oSource = Nothing
Set oSourceItems = Nothing
Set oShell = Nothing
Set rs = Nothing
Set fso = Nothing
Set tfld = Nothing
End Sub
Sorry it took me so long to accept your answer and thanks again.