السلام عليكم,
هذا مثال بسيط يوضح كيفية إضافة عنصر القائمة "Menu item"
إلى قائمة مستعرض الويندو عند الضغط كلك يمين على الملفات والمجلدات او فى خلفية المجلد.
// ShellExt.cpp
#include <windows.h>
#include <atlbase.h>
#include <atlcom.h>
#include <atlstr.h>
#include <shlobj.h>
#include <initguid.h>
#include <vector>
#include <string>
using namespace std;
// {E184F749-97E8-47be-A72D-14612D18612C}
DEFINE_GUID(CLSID_ShellExt, 0xe184f749, 0x97e8, 0x47be, 0xa7, 0x2d, 0x14, 0x61, 0x2d, 0x18, 0x61, 0x2c);
#define regCLSID _T("{E184F749-97E8-47be-A72D-14612D18612C}")
#define regFiles _T("*\\shellex\\ContextMenuHandlers\\")
#define regFolder _T("Folder\\shellex\\ContextMenuHandlers\\")
#define regDirectory _T("Directory\\shellex\\ContextMenuHandlers\\")
#define regDirectory_Background _T("Directory\\Background\\shellex\\ContextMenuHandlers\\")
#define regAllFilesystemObjects _T("AllFilesystemObjects\\shellex\\ContextMenuHandlers\\")
#define regShellExt_Approved _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved\\")
// this is the actual OLE Shell extension handler
class ATL_NO_VTABLE CShellExt : // Implementation
public CComObjectRoot,
public CComCoClass<CShellExt, &CLSID_ShellExt>,
public IShellExtInit,
public IContextMenu
{
private:
vector<LPSTR> selectedItems;
public :
DECLARE_NO_REGISTRY()
DECLARE_NOT_AGGREGATABLE(CShellExt)
BEGIN_COM_MAP(CShellExt)
COM_INTERFACE_ENTRY_IID(IID_IShellExtInit, IShellExtInit)
COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
END_COM_MAP()
// IShellExtInit methods
STDMETHODIMP Initialize( LPCITEMIDLIST pidlFolder,
LPDATAOBJECT pDataObj,
HKEY hRegKey)
{
HRESULT hr = S_OK;
char *path = new char[MAX_PATH];
// If Initialize has already been called.
if(pidlFolder) {
if(SHGetPathFromIDList(pidlFolder, path)) {
selectedItems.push_back(path);
if(path) delete[] path;
return S_OK;
}
return E_INVALIDARG;
} else if(pDataObj) {
// Get the file name from the CF_HDROP.
FORMATETC fmt = { CF_HDROP, (DVTARGETDEVICE FAR *)NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stg = { TYMED_HGLOBAL };
if(SUCCEEDED(pDataObj->GetData(&fmt, &stg)) && stg.hGlobal) {
// Get a pointer to the actual data.
HDROP hDrop = (HDROP) GlobalLock(stg.hGlobal);
// Make sure it worked.
if(SUCCEEDED(hDrop)) {
// Get the count of files the user has selected...
UINT filesCount = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
for(UINT i = 0; i < filesCount; ++i) {
if(path) delete[] path;
path = new char[MAX_PATH];
DragQueryFile( hDrop, i, path, MAX_PATH);
selectedItems.push_back(path);
}
}
hr = S_OK;
} else
hr = E_INVALIDARG;
if (stg.hGlobal) {
GlobalUnlock(stg.hGlobal);
ReleaseStgMedium(&stg);
if(path) delete[] path;
}
} else
hr = E_INVALIDARG;
return hr;
}
// IContextMenu members
STDMETHODIMP QueryContextMenu( HMENU hMenu,
UINT indexMenu,
UINT idCmdFirst,
UINT idCmdLast,
UINT uFlags)
{
// If the flags include CMF_DEFAULTONLY then we shouldn't do anything.
if ( uFlags & CMF_DEFAULTONLY )
return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);
TCHAR menuTitle[MAX_PATH];
// Check if we already added our menu entry.
int count = GetMenuItemCount(hMenu);
for(int i = 0; i < count; ++i)
{
if(GetMenuString(hMenu, i, menuTitle, MAX_PATH, MF_BYPOSITION)) {
if(_stricmp(menuTitle, _T("Test ShellExt")) == 0)
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));
}
}
if(InsertMenu(hMenu, indexMenu, MF_BYPOSITION | MF_HILITE, idCmdFirst, _T("Test ShellExt"))) {
// Tell the shell we added 1 top-level menu item.
return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 1);
}
return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);
}
// IContextMenu members
STDMETHODIMP GetCommandString( UINT idCmd,
UINT uFlags,
UINT FAR*,
LPSTR pszName,
UINT cchMax)
{
USES_CONVERSION;
// Check idCmd, it must be 0 since we have only one menu item.
if (idCmd > 0) return E_INVALIDARG;
// If Explorer is asking for a help string, copy our string into the supplied buffer.
if ( uFlags & GCS_HELPTEXT ) {
LPCTSTR pszText = _T("Test Shell Extension.");
if ( uFlags & GCS_UNICODE ) {
// We need to cast pszName to a Unicode string, and then use the Unicode string copy API.
lstrcpynW ((LPWSTR) pszName, T2CW(pszText), cchMax);
return S_OK;
} else {
// Use the ANSI string copy API to return the help string.
lstrcpynA (pszName, T2CA(pszText), cchMax);
return S_OK;
}
}
return E_INVALIDARG;
}
// IContextMenu members
STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
{
CString files;
for(UINT i = 0; i < selectedItems.size(); i++) {
files.AppendFormat("%s\n", selectedItems);
}
if(0 == HIWORD(lpcmi->lpVerb)) { //if called by command id
WORD idCmd = LOWORD(lpcmi->lpVerb);
// The command ID must be 0 since we only have one menu item.
if(idCmd == 0) {
MessageBox(0, files, "InvokeCommand by ID", 0);
return S_OK;
}
} else { //if called by verb
if( 0 == strcmp("Test ShellExt", lpcmi->lpVerb) ) {
MessageBox(0, files, "InvokeCommand by verb", 0);
return S_OK;
}
}
return E_INVALIDARG;
}
};
BEGIN_OBJECT_MAP(ObjectMap)
OBJECT_ENTRY(CLSID_ShellExt, CShellExt)
END_OBJECT_MAP()
CComModule module;
// DLL Entry Point
extern "C" BOOL APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID)
{
if( dwReason == DLL_PROCESS_ATTACH ) {
module.Init(ObjectMap, hInstance);
DisableThreadLibraryCalls(hInstance);
} else if(dwReason == DLL_PROCESS_DETACH)
module.Term();
return TRUE;
}
// Used to determine whether the DLL can be unloaded by OLE
STDAPI DllCanUnloadNow()
{
return module.GetLockCount() ? S_FALSE : S_OK;
}
// Returns a class factory to create an object of the requested type
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID * ppvOut)
{
return module.GetClassObject(rclsid, riid, ppvOut);
}
// DllRegisterServer - Adds entries to the system registry
STDAPI DllRegisterServer()
{
CRegKey key;
char *dllPath = new char[MAX_PATH];
GetModuleFileName(module.GetModuleInstance(), dllPath, MAX_PATH);
if(key.Open(HKEY_CLASSES_ROOT, _T("CLSID\\")) == ERROR_SUCCESS) {
key.SetKeyValue(regCLSID _T("\\InprocServer32"), dllPath);
key.SetKeyValue(regCLSID _T("\\InprocServer32"), _T("Apartment"), _T("ThreadingModel"));
}
if(key.Open(
HKEY_CLASSES_ROOT, regFiles) == ERROR_SUCCESS) {
key.SetKeyValue(_T("TestShellExt"), regCLSID);
}
if(key.Open(
HKEY_CLASSES_ROOT, regDirectory) == ERROR_SUCCESS) {
key.SetKeyValue(_T("TestShellExt"), regCLSID);
}
if(key.Open(
HKEY_CLASSES_ROOT, regDirectory_Background) == ERROR_SUCCESS) {
key.SetKeyValue(_T("TestShellExt"), regCLSID);
}
if(key.Open(
HKEY_CLASSES_ROOT, regFolder) == ERROR_SUCCESS) {
key.SetKeyValue(_T("TestShellExt"), regCLSID);
}
if(key.Open(
HKEY_CLASSES_ROOT, regAllFilesystemObjects) == ERROR_SUCCESS) {
key.SetKeyValue(_T("TestShellExt"), regCLSID);
}
if(key.Open(
HKEY_LOCAL_MACHINE, regShellExt_Approved) == ERROR_SUCCESS) {
key.SetStringValue(regCLSID, _T("Test ShellExtension"));
}
key.Close();
if(dllPath) delete[] dllPath;
return module.RegisterServer(FALSE);
}
// DllUnregisterServer - Removes entries from the system registry
STDAPI DllUnregisterServer()
{
CRegKey key;
if (key.Open(HKEY_CLASSES_ROOT, _T("CLSID\\")) == ERROR_SUCCESS) {
key.DeleteSubKey(regCLSID);
}
if (key.Open(HKEY_CLASSES_ROOT, regFiles) == ERROR_SUCCESS) {
key.DeleteSubKey(_T("TestShellExt"));
}
if (key.Open(HKEY_CLASSES_ROOT, regDirectory) == ERROR_SUCCESS) {
key.DeleteSubKey(_T("TestShellExt"));
}
if (key.Open(HKEY_CLASSES_ROOT, regDirectory_Background) == ERROR_SUCCESS) {
key.DeleteSubKey(_T("TestShellExt"));
}
if (key.Open(HKEY_CLASSES_ROOT, regFolder) == ERROR_SUCCESS) {
key.DeleteSubKey(_T("TestShellExt"));
}
if (key.Open(HKEY_CLASSES_ROOT, regAllFilesystemObjects) == ERROR_SUCCESS) {
key.DeleteSubKey(_T("TestShellExt"));
}
if(key.Open(HKEY_LOCAL_MACHINE, regShellExt_Approved) == ERROR_SUCCESS) {
key.DeleteValue(regCLSID);
}
key.Close();
return module.UnregisterServer(FALSE);
}للمزيد ...
Add Item To Explorer Context Menu