Link to home
Start Free TrialLog in
Avatar of jasonrcox
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.
Avatar of MYLim
MYLim

listening
Avatar of Ark
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
Oops, sorry,
If sMenu = "Îòïðàâèò&ü" Then '->Change menu name to your locale, ="Send&To", for example
Avatar of jasonrcox

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.
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.
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!
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
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
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...
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.Application")
   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(GetFolderPath(sTestFile)).ParseName(GetFileName(sTestFile))
   Set oTarget = oShell.NameSpace(GetFolderPath(sPath)).ParseName(GetFileName(sPath))
   oSource.InvokeVerb ("copy")
   oTarget.InvokeVerb ("paste")
   Set oTarget = Nothing
   Set oSource = Nothing
End Sub

Now thats what I am talking about!  I will try this today.  Thanks!
ASKER CERTIFIED SOLUTION
Avatar of Ark
Ark
Flag of Russian Federation image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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.GetSpecialFolder(2) & "\tsendto") Then
    ' delete the folder
    fso.DeleteFolder fso.GetSpecialFolder(2) & "\tsendto", True
End If
Set tfld = fso.CreateFolder(fso.GetSpecialFolder(2) & "\tsendto")

SelectedCount = frmDataList.objDocList.p.SelectedCount
' 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.SelectedNodes(iCounter).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.SelectedNodes(iCounter).KeyFieldValue)
        If Not rs Is Nothing Then
            ' Copy it to the temp folder
            fso.CopyFile GetStoreFile(rs.Fields("filename").Value), 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).ParseName(mnuSendToList(Index).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.