如果我的程序的列表控件中显示了某个文件夹中的内容,然后希望实现如上的功能,也就是用户右键点击某一项时弹出系统的菜单,该如何做呢?谢谢了先,呵呵。
解决方案 »
- vs2010 c++文件 Intellisense不可用
- windump如何抓取从无线网卡接受和发送的数据包?
- 请问隐式连接dll能够自动运行__DllMainCRTStartup吗?
- OVERLAPPED读取文件的时候没什么分别?也是会卡的...,不明白有什么分别?
- strcat出错,求助!
- 关于CEditView的解决方案
- VC下MSCOMM控件编程中遇到的问题。为什么我接收到的字符的10进制值出现负值。
- 200分求<编译原理与实践》的附录B和附录C的电子版?
- 菜鸟用100分求解关于MFC的三个小问题??
- 很菜的问题,GUID是什么意思,有何功用
- 为什么我增加一个.cpp文件到工程中会出现错误,怎么解决,等待。。。
- 关于不规则窗体实现的一个问题?
' File1.MultiSelect = 2
Move (Screen.Width - Width) * 0.5, (Screen.Height - Height) * 0.5
End SubPrivate Sub Drive1_Change()
On Error GoTo Out ' covers invalid path selection
Dir1.Path = Drive1.Drive
Out:
End SubPrivate Sub Dir1_Change()
On Error GoTo Out ' covers invalid path selection
File1 = Dir1.Path
Out:
End SubPrivate Sub Dir1_MouseUp(Button As Integer, Shift As Integer, x As Single, y As Single)
If (Button = vbRightButton) Then
Call ShellContextMenu(Dir1, x, y, Shift)
End If
End Sub' Selects all FileListBox items on a Ctrl+A keypress.Private Sub File1_KeyDown(KeyCode As Integer, Shift As Integer)
If (KeyCode = vbKeyA) And (Shift = vbCtrlMask) Then
Call SendMessage(File1.hWnd, LB_SETSEL, CTrue, ByVal -1)
End If
End SubPrivate Sub File1_MouseUp(Button As Integer, Shift As Integer, x As Single, y As Single)
If (Button = vbRightButton) Then
Call ShellContextMenu(File1, x, y, Shift)
End If
End SubPrivate Sub ShellContextMenu(objLB As Control, _
x As Single, _
y As Single, _
Shift As Integer)
Dim pt As POINTAPI ' screen location of the cursor
Dim iItem As Integer ' listbox index of the selected item (item under the cursor)
Dim cItems As Integer ' count of selected items
Dim i As Integer ' counter
Dim asPaths() As String ' array of selected items' paths (zero based)
Dim apidlFQs() As Long ' array of selected items' fully qualified pidls (zero based)
Dim isfParent As IShellFolder ' selected items' parent shell folder
Dim apidlRels() As Long ' array of selected items' relative pidls (zero based)
' ==================================================
' Get the listbox item under the cursor
' Convert the listbox's client twip coords to screen pixel coords.
pt.x = x \ Screen.TwipsPerPixelX
pt.y = y \ Screen.TwipsPerPixelY
Call ClientToScreen(objLB.hWnd, pt) ' Get the zero-based index of the item under the cursor.
' If none exists, bail...
iItem = LBItemFromPt(objLB.hWnd, pt.x, pt.y, False)
If (iItem = LB_ERR) Then Exit Sub
' ==================================================
' Set listbox focus and selection
objLB.SetFocus
' If neither the Control and/or Shift key are pressed...
If (Shift And (vbCtrlMask Or vbShiftMask)) = False Then
' If Dir1 has the focus...
If (TypeOf objLB Is DirListBox) Then
' Select the item under the cursor. The DirListBox
' doesn't have a Selected property, so we'll get forceful...
Call SendMessage(Dir1.hWnd, LB_SETCURSEL, iItem, 0)
Else
' File1 has the focus, duplicate Explorer listview selection functionality.
' If the right clicked item isn't selected....
If (File1.Selected(iItem) = False) Then
' Deselect all of the items and select the right clicked item.
Call SendMessage(File1.hWnd, LB_SETSEL, CFalse, ByVal -1)
File1.Selected(iItem) = True
Else
' The right clciked item is selected, give it the selection rectangle
' (or caret, does not deselect any other currently selected items).
' File1.Selected doesn't set the caret if the item is already selected.
Call SendMessage(File1.hWnd, LB_SETCARETINDEX, iItem, ByVal 0&)
End If
End If ' (TypeOf objLB Is DirListBox)
End If ' (Shift And (vbCtrlMask Or vbShiftMask)) = False
' ==================================================
' Load the path(s) of the selected listbox item(s) into the array.
If (TypeOf objLB Is DirListBox) Then
' Only one directory can be selected in the DirLB
cItems = 1
ReDim asPaths(0)
asPaths(0) = GetDirLBItemPath(Dir1, iItem)
Else
' Put the focused (and selected) files's relative pidl in the
' first element of the array. This will be the file whose context
' menu will be shown if multiple files are selected.
cItems = 1
ReDim asPaths(0)
asPaths(0) = GetFileLBItemPath(File1, iItem)
' Fill the array with the relative pidls of the rest of any selected
' files(s), making sure that we don't add the focused file again.
For i = 0 To File1.ListCount - 1
If (File1.Selected(i)) And (i <> iItem) Then
cItems = cItems + 1
ReDim Preserve asPaths(cItems - 1)
asPaths(cItems - 1) = GetFileLBItemPath(File1, i)
End If
Next
End If ' (TypeOf objLB Is DirListBox)
' Finally, get the IShellFolder of the selected directory, load the relative
' pidl(s) of the selected items into the array, and show the menu.
' This part won't be elaborated upon, as it is extensively involved.
' For more info on IShellFolder, pidls and the shell's context menu, see:
' http://msdn.microsoft.com/developer/sdk/inetsdk/help/itt/Shell/NameSpace.htm
If Len(asPaths(0)) Then
' Get a copy of each selected item's fully qualified pidl from it's path.
For i = 0 To cItems - 1
ReDim Preserve apidlFQs(i)
apidlFQs(i) = GetPIDLFromPath(hWnd, asPaths(i))
Next
If apidlFQs(0) Then
' Get the selected item's parent IShellFolder.
Set isfParent = GetParentIShellFolder(apidlFQs(0))
If (isfParent Is Nothing) = False Then
' Get a copy of each selected item's relative pidl (the last item ID)
' from each respective item's fully qualified pidl.
For i = 0 To cItems - 1
ReDim Preserve apidlRels(i)
apidlRels(i) = GetItemID(apidlFQs(i), GIID_LAST)
Next
If apidlRels(0) Then
' Subclass the Form so we catch the menu's ownerdraw messages.
Call SubClass(hWnd, AddressOf WndProc)
' Show the shell context menu for the selected items. If a
' menu command was executed, refresh the two listboxes.
If ShowShellContextMenu(hWnd, isfParent, cItems, apidlRels(0), pt, chkPrompt) Then
Dir1.Refresh
Call RefreshListBox(File1)
End If
' Finally, unsubclass the form.
Call UnSubClass(hWnd)
End If ' apidlRels(0)
' Free each item's relative pidl.
For i = 0 To cItems - 1
Call MemAllocator.Free(ByVal apidlRels(i))
Next
End If ' (isfParent Is Nothing) = False ' Free each item's fully qualified pidl.
For i = 0 To cItems - 1
Call MemAllocator.Free(ByVal apidlFQs(i))
Next
End If ' apidlFQs(0)
End If ' Len(asPaths(0))
End SubPrivate Function GetFileLBItemPath(objFLB As FileListBox, iItem As Integer) As String
Dim sPath As String
sPath = objFLB.Path
If Right(sPath, 1) <> "\" Then sPath = sPath & "\"
GetFileLBItemPath = sPath & objFLB.List(iItem)End Function' Returns the DirListBox Path from the specified listbox item index.
' It's a little extra work getting the path of the selected DirListBox item...Private Function GetDirLBItemPath(objDLB As DirListBox, iItem As Integer) As String
Dim nItems As Integer
' Get the count of items in the DirLB
nItems = SendMessage(objDLB.hWnd, LB_GETCOUNT, 0, 0)
If (nItems > -1) Then ' LB_ERR
' Subtract the actual number of LB items from the sum of:
' the DirLB's ListCount and
' the currently selected directory's real LB index value
' (nItems is a value of 1 greater than the last item's real LB index value)
GetDirLBItemPath = objDLB.List((objDLB.ListCount + iItem) - nItems)'Debug.Print "iItem: " & iItem & ", LiistIndex: " & (objDLB.ListCount + iItem) - nItems End IfEnd FunctionPrivate Sub RefreshListBox(objLB As Control)
Dim iFocusedItem As Integer
Dim i As Integer
Dim cItems As Integer
Dim aiSelitems() As Integer
' Cache the focused item, if any.
iFocusedItem = objLB.ListIndex
' Cache any selected items
For i = 0 To objLB.ListCount - 1
If objLB.Selected(i) Then
cItems = cItems + 1
ReDim Preserve aiSelitems(cItems - 1)
aiSelitems(cItems - 1) = i
End If
Next
' Refresh the listbox, sets ListIndex = 0, and removes all selction.
objLB.Refresh ' Restore focus and selection to the cached items.
' objLB.ListIndex = iFocusedItem ' this errs... (?)
Call SendMessage(objLB.hWnd, LB_SETCARETINDEX, iFocusedItem, ByVal 0&)
For i = 0 To cItems - 1
' objLB.Selected(aiSelitems(i)) = True ' may err...
Call SendMessage(objLB.hWnd, LB_SETSEL, CTrue, ByVal aiSelitems(i))
Next
End Sub
感谢你的提示
to 蔬菜
感谢你的关心.我也不太懂vb,所以先把你的代码copy了一份,回去再好好研究.如果不行的话在来问你们好了,呵呵
在网上找到一点资料,整理为一段代码如下:// Helpers
enum
{
MI_BEGIN = 1,
MI_END = 0x7FFF,
MI_INVALID
};
inline
USHORT& SHIdSize(LPCITEMIDLIST pidl, int offset)
{
return ((LPITEMIDLIST)(((char*)pidl)+offset))->mkid.cb;
}inline
USHORT& SHIdSize(LPCITEMIDLIST pidl)
{
return ((LPITEMIDLIST)pidl)->mkid.cb;
}inline
LPITEMIDLIST NextPidl(LPCITEMIDLIST pidl, int offset)
{
return (LPITEMIDLIST)(((char*)pidl)+offset);
}inline
LPITEMIDLIST NextPidl(LPCITEMIDLIST pidl)
{
return (LPITEMIDLIST)(((char*)pidl)+SHIdSize(pidl));
}void SplitPidl(IMalloc* pmalloc, LPCITEMIDLIST pidl, LPITEMIDLIST& pidlFolder, LPITEMIDLIST& pidlObject)
{
int n1;
int n;
LPITEMIDLIST p;
for ( n1 = 0, n = 0, p = (LPITEMIDLIST)pidl; SHIdSize(p); n1 = n, n += SHIdSize(p), p = NextPidl(p) )
; if ( n1 == 0 )
pidlFolder = NULL;
else if ( pidlFolder = (LPITEMIDLIST)(pmalloc->Alloc(n1+2)) ) {
CopyMemory(pidlFolder, pidl, n1);
SHIdSize(pidlFolder, n1) = 0;
} int m = n-n1;
if ( m == 0 )
pidlObject = NULL;
else if ( pidlObject = (LPITEMIDLIST)(pmalloc->Alloc(m+2)) ) {
CopyMemory(pidlObject, NextPidl(pidl, n1), m);
SHIdSize(pidlObject, m) = 0;
}
}// Global Var for owner-draw
IContextMenu2* pMenu2 = NULL;void CContextMenuDlg::OnRclickList(NMHDR* pNMHDR, LRESULT* pResult)
{
// TODO: Add your control notification handler code here // 弹出“C:\Downloads”文件夹的浏览器菜单
CString sFile = _T("C:\\Downloads");
WCHAR cBuffer[1024] = {0};
ASSERT(MultiByteToWideChar(CP_ACP,
0,
(LPCSTR)(LPCTSTR) sFile,
sFile .GetLength() + 1,
cBuffer,
sFile .GetLength() + 1)); HRESULT hRes;
LPMALLOC pMalloc = NULL;
hRes = SHGetMalloc(&pMalloc);
ASSERT(SUCCEEDED(hRes)); // Get DesktopShellFolder Interface
IShellFolder* pDesktopShellFolder = NULL;
hRes = SHGetDesktopFolder(&pDesktopShellFolder);
ASSERT(SUCCEEDED(hRes)); // Get Full ItemList List of the File&Folder
ITEMIDLIST * pFullItemIDList = NULL;
hRes = pDesktopShellFolder ->ParseDisplayName(GetSafeHwnd(),
NULL,
cBuffer,
NULL,
&pFullItemIDList,
NULL);
ASSERT(SUCCEEDED(hRes));
// Split Full to Parent Folder and Object Item
LPITEMIDLIST pidlFolder = NULL;
LPITEMIDLIST pidlObj = NULL;
SplitPidl(pMalloc, pFullItemIDList, pidlFolder, pidlObj); // Get Parent ShellFolder
IShellFolder* pParentShellFolder = NULL;
hRes = pDesktopShellFolder ->BindToObject(pidlFolder, NULL, IID_IShellFolder, (void**)&pParentShellFolder);
ASSERT(SUCCEEDED(hRes)); // Get IContextMenu of the Object
IContextMenu* pMenu = NULL;
hRes = pParentShellFolder ->GetUIObjectOf(GetSafeHwnd(), 1, (LPCITEMIDLIST*)&pidlObj, IID_IContextMenu, NULL, (LPVOID*)&pMenu);
ASSERT(SUCCEEDED(hRes)); // Create a Empty Menu to Fill Context Menus in
HMENU hMenu = CreatePopupMenu();
pMenu ->QueryContextMenu(hMenu, 0, MI_BEGIN, MI_END, CMF_NORMAL); // Get IContextMenu2 for forwarding owner-draw menu messages
if ( pMenu ->QueryInterface(IID_IContextMenu2, (void**)&pMenu2) != S_OK ) {
pMenu2 = NULL;
}
// Show Menu
int idCmd;
CPoint ptCursor;
GetCursorPos(&ptCursor);
idCmd = TrackPopupMenuEx(hMenu, TPM_LEFTBUTTON|TPM_RIGHTBUTTON|TPM_RETURNCMD, ptCursor .x, ptCursor .y, GetSafeHwnd(), NULL); // Invoke Cmd
if ( idCmd >= MI_BEGIN ) {
CMINVOKECOMMANDINFO cmi;
cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
cmi.fMask = 0;
cmi.hwnd = GetSafeHwnd();
cmi.lpVerb = MAKEINTRESOURCE(idCmd - MI_BEGIN);
cmi.lpParameters = NULL;
cmi.lpDirectory = NULL;
cmi.nShow = SW_SHOWNORMAL;
cmi.dwHotKey = 0;
cmi.hIcon = NULL;
pMenu->InvokeCommand(&cmi);
} if ( pMenu2 != NULL ) {
pMenu2 ->Release();
pMenu2 = NULL;
}
// Release
pMenu ->Release();
pParentShellFolder ->Release(); pMalloc ->Free(pidlObj);
pMalloc ->Free(pidlFolder);
pMalloc ->Free(pFullItemIDList); pDesktopShellFolder ->Release();
pMalloc ->Release();
}
LRESULT CContextMenuDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
// TODO: Add your specialized code here and/or call the base class
switch(message)
{
// 不知道这里为什么会发生断言错误?
case WM_DRAWITEM:
case WM_INITMENUPOPUP:
case WM_MEASUREITEM:
if(pMenu2)
pMenu2 ->HandleMenuMsg(message, wParam, lParam);
break;
}
return CDialog::WindowProc(message, wParam, lParam);
} 以上代码只能弹出弹出一级菜单,当鼠标移动到多级菜单(如打开方式,发送到)的时候就会出现断言错误。但是在Win32类型的工程中运行没问题(以上是基于MFC的),不知道为什么。
看来只有结贴了。
忘记了一点:在初始化的时候要用OleInitialize(),不要使用CoInitialize(),否则不能进行复制操作。
希望有高人能在搞定或者已经知道的时候通知我一下,严重感谢。[email protected]