[转载]在鼠标右键添加"注册dll"的程序源码 :: FreeDebug Matrix
来源: BlogBus 原始链接: http://www.blogbus.com:80/blogbus/blog/diary.php?diaryid=55301 存档链接: https://web.archive.org/web/20040928080856id_/http://www.blogbus.com:80/blogbus/blog/diary.php?diaryid=55301
FreeDebug Matrix 尘世上的事务驳杂离奇,看得我眼花缭乱,样样都浅尝辄止,并依我心意记于此,博世人一笑耳~~~ 永久域名: http://freedebug.51.net http://freedebug.blogbus.com <<<[转贴]在Win2003中使用Windows XP样式的方法 | 首页 | 简明批处理教程>>> [转载]在鼠标右键添加"注册dll"的程序源码 This time is about shell extensions. Because I am tired to open a console every time when I want to register the Debug dll as shell extension, I was thinking that's a good idea to right-click the dll to register/unregister. So here we are! (as stupid Dexters's sister, DeeDee, said once). You will find here few things you cannot find in MSDN or in other articles.
- GUID. You can obtain this sinister number running one of the uuidgen or guidgen tools. This is CLSID_DLLRegisterer.
- The main file, where the DLL's entry point DllMain resides, is dllregshex.cpp. I prefer to load resources at start and free them at end, especially when are in little number. So, the routines _LoadResources and _UnloadResources do this. The other two interesting routines are DllRegisterServer and DllUnregisterServer. If you use one, be polite to the user and use the twin (I have seen may Reg, but few Unreg). That's when you did not choose another way (as a .reg file, for example, or separate install/uninstall programs). So, what's happening registering a dll as shell context extension? You have to create the entry in CLSID key and to create under this the 'samename' key and the thread model key (I read somewhere that only 'Apartment' is accepted for context extensions - is really true?). STDAPI DllRegisterServer(void) { HINSTANCE hInst = g_hmodThisDll; int i; HKEY hKey; LRESULT lResult; DWORD dwDisp; TCHAR szSubKey[MAX_PATH]; TCHAR szCLSID[MAX_PATH]; TCHAR szModule[MAX_PATH]; LPWSTR pwszShellExt; StringFromIID(CLSID_DLLRegisterer, &pwszShellExt); if (pwszShellExt) { WideCharToLocal(szCLSID, pwszShellExt, ARRAYSIZE(szCLSID)); LPMALLOC pMalloc; CoGetMalloc(1, &pMalloc); if(pMalloc) { pMalloc->Free(pwszShellExt); pMalloc->Release(); } } GetModuleFileName(hInst, szModule, ARRAYSIZE(szModule)); REGSTRUCT ShExClsidEntries[] = { HKEY_CLASSES_ROOT, TEXT("CLSID\%s"), NULL, TEXT(DLLREGUNREGNAME), HKEY_CLASSES_ROOT, TEXT("CLSID\%s\InProcServer32"), NULL, TEXT("%s"), HKEY_CLASSES_ROOT, TEXT("CLSID\%s\InProcServer32"), TEXT("ThreadingModel"), TEXT("Apartment"), NULL, NULL, NULL, NULL }; for(i = 0; ShExClsidEntries[i].hRootKey; i++) { wsprintf(szSubKey, ShExClsidEntries[i].lpszSubKey, szCLSID); lResult = RegCreateKeyEx(ShExClsidEntries[i].hRootKey, szSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, &dwDisp); if(NOERROR == lResult) { TCHAR szData[MAX_PATH]; wsprintf(szData, ShExClsidEntries[i].lpszData, szModule); lResult = RegSetValueEx(hKey, ShExClsidEntries[i].lpszValueName, 0, REG_SZ, (LPBYTE)szData, lstrlen(szData) + 1); RegCloseKey(hKey); } else return SELFREG_E_CLASS; } The other entries bind the desired extension (in our case, the DLLs) to our CLSID: REGSTRUCT OtherShExEntries[] = { HKEY_LOCAL_MACHINE, TEXT("software\classes\clsid\"DLLREGUNREGNAME), NULL, TEXT("%s"), HKEY_CLASSES_ROOT, TEXT("dllfile\shellex\ContextMenuHandlers\"DLLREGUNREGNAME), NULL, TEXT("%s"), NULL, NULL, NULL, NULL }; for (i = 0; OtherShExEntries[i].hRootKey; i++) { wsprintf(szSubKey, OtherShExEntries[i].lpszSubKey, szCLSID); lResult = RegCreateKeyEx(OtherShExEntries[i].hRootKey, szSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, &dwDisp); if(NOERROR == lResult) { TCHAR szData[MAX_PATH]; wsprintf(szData, OtherShExEntries[i].lpszData, szCLSID); lResult = RegSetValueEx(hKey, OtherShExEntries[i].lpszValueName, 0, REG_SZ, (LPBYTE)szData, lstrlen(szData) + 1); RegCloseKey(hKey); } else return SELFREG_E_CLASS; } A special mention when Windows is NT: register the extension as 'Approved': OSVERSIONINFO osvi; osvi.dwOSVersionInfoSize = sizeof(osvi); GetVersionEx(&osvi); if (VER_PLATFORM_WIN32_NT == osvi.dwPlatformId) { lstrcpy( szSubKey, TEXT("Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved")); lResult = RegCreateKeyEx(HKEY_LOCAL_MACHINE, szSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, &dwDisp); if(NOERROR == lResult) { TCHAR szData[MAX_PATH]; lstrcpy(szData, DLLREGUNREGNAME); lResult = RegSetValueEx(hKey, szCLSID, 0, REG_SZ, (LPBYTE)szData, lstrlen(szData) + 1); RegCloseKey(hKey); } else return SELFREG_E_CLASS; } return S_OK; } The unregister routine performs the inverse way. The rest is history: AddRef, Release, QueryInterface.
- The utils file (dllreg_util.cpp) contains conversion routines. This UNICODE job really kills me, I simply copied one of the 1000 other ways to deal with it.
- The menu file (dllreg_ctxm.cpp) contains 3 standard routines: QueryContextMenu, which builds the added popup menu and his options, InvokeCommand and GetCommandString - this will show you a simple text on Explorer' status bar. Nothing unusual. #include "dllreg_xhdr.h" #include "dllregshex.h" #include "dllreg_util.h" #include "resource.h" extern UINT g_cRefThisDll; extern HINSTANCE g_hmodThisDll; extern HBITMAP hBmp_Install; extern HBITMAP hBmp_Uninstall; extern HBITMAP hBmp_About; extern HMENU hSubMenu; // IContextMenu STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) { _UNUSED_PARAMETER(idCmdLast); UINT idCmd = idCmdFirst; char *szMenuText_Popup = "Shell e&xtension"; char *szMenuText_Install = "&Install"; char *szMenuText_Uninstall = "&Uninstall"; char *szMenuText_About = "&About..."; BOOL bAppendItems = TRUE; if((uFlags & 0x000F) == CMF_NORMAL) bAppendItems = TRUE; else if (uFlags & CMF_VERBSONLY) bAppendItems = TRUE; else if (uFlags & CMF_EXPLORE) bAppendItems = TRUE; else bAppendItems = FALSE; if(bAppendItems) { InsertMenu(hMenu, indexMenu++, MF_SEPARATOR | MF_BYPOSITION, 0, NULL); HMENU hSubMenu = CreateMenu(); if(hSubMenu) { InsertMenu(hSubMenu, 0, MF_STRING | MF_BYPOSITION, idCmd++, szMenuText_Install); SetMenuItemBitmaps(hSubMenu, 0, MF_BYPOSITION, hBmp_Install, hBmp_Install); InsertMenu(hSubMenu, 1, MF_STRING | MF_BYPOSITION, idCmd++, szMenuText_Uninstall); SetMenuItemBitmaps(hSubMenu, 1, MF_BYPOSITION, hBmp_Uninstall, hBmp_Uninstall); InsertMenu(hSubMenu, 2, MF_SEPARATOR | MF_BYPOSITION, 0, NULL); InsertMenu(hSubMenu, 3, MF_STRING | MF_BYPOSITION, idCmd++, szMenuText_About); SetMenuItemBitmaps(hSubMenu, 3, MF_BYPOSITION, hBmp_About, hBmp_About); } InsertMenu(hMenu, indexMenu++, MF_STRING | MF_POPUP | MF_BYPOSITION, (UINT_PTR)hSubMenu, szMenuText_Popup); InsertMenu(hMenu, indexMenu++, MF_SEPARATOR | MF_BYPOSITION, 0, NULL); return ResultFromShort(idCmd - idCmdFirst); } return NOERROR; } STDMETHODIMP CShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) { HRESULT hr = E_INVALIDARG; if (!HIWORD(lpcmi->lpVerb)) { UINT idCmd = LOWORD(lpcmi->lpVerb); switch (idCmd) { case 0: hr = DoInstall(lpcmi->hwnd, lpcmi->lpDirectory, lpcmi->lpVerb, lpcmi->lpParameters, lpcmi->nShow); break; case 1: hr = DoUninstall(lpcmi->hwnd, lpcmi->lpDirectory, lpcmi->lpVerb, lpcmi->lpParameters, lpcmi->nShow); break; case 2: hr = DoAbout(lpcmi->hwnd, lpcmi->lpDirectory, lpcmi->lpVerb, lpcmi->lpParameters, lpcmi->nShow); break; default: break; } } return hr; } STDMETHODIMP CShellExt::GetCommandString(UINT idCmd, UINT uFlags, UINT FAR *reserved, LPSTR pszName, UINT cchMax) { _UNUSED_PARAMETER(reserved); _UNUSED_PARAMETER(uFlags); *pszName = 0; cchMax = 40; char psz[40]; switch (idCmd) { case 0: LoadString(g_hmodThisDll, IDCMD_INSTALL, psz, cchMax); break; case 1: LoadString(g_hmodThisDll, IDCMD_UNINSTALL, psz, cchMax); break; case 2: LoadString(g_hmodThisDll, IDCMD_ABOUT, psz, cchMax); break; default: break; } wcscpy((unsigned short *)pszName, _WCSTR(psz)); return NOERROR; }
- The most interesting stuff is contained in file dllreg_job.cpp, and this is the _GetFullFileName function. The others are handled in one routine, which simply format a command line using the regsvr32.exe tool (_DoRegisterJob) STDMETHODIMP CShellExt::_GetFullFileName() { HRESULT hr = S_FALSE; // // IEnumFORMATETC. Needed for format enumeration. // IEnumFORMATETC *pefEtc = 0; hr = m_pDataObj->EnumFormatEtc(DATADIR_GET, &pefEtc); if(SUCCEEDED(hr)) { hr = pefEtc->Reset(); // Reset enumeration. if(SUCCEEDED(hr)) { // // FORMATETC. Needed for get data about object. // FORMATETC fEtc; ULONG ulFetched = 0L; while(TRUE) { hr = pefEtc->Next(1, &fEtc, &ulFetched); if(FAILED(hr) || (ulFetched <= 0)) break; // // 'Arm' format and 'launch' to obtain STGMEDIUM... // fEtc.cfFormat = CF_HDROP; fEtc.dwAspect = DVASPECT_CONTENT; fEtc.lindex = -1; fEtc.ptd = NULL; fEtc.tymed = TYMED_HGLOBAL; // // IDataObject : GetData. Returned as TYMED_HGLOBAL. // STGMEDIUM stgM; hr = m_pDataObj->GetData(&fEtc, &stgM); if(SUCCEEDED(hr)) { if(stgM.tymed == TYMED_HGLOBAL) { // m_ppszFileUserClickedOn[0] = '\0'; UINT nFileCount = DragQueryFile((HDROP)stgM.hGlobal, (UINT)INVALID_HANDLE_VALUE, NULL, 0); if(nFileCount >= 1) { if(m_ppszFileUserClickedOn) { DeleteFileData(); } m_ppszFileUserClickedOn = new LPTSTR[nFileCount]; for(register UINT x = 0; x < nFileCount; x++) { m_ppszFileUserClickedOn[x] = new TCHAR[_MAX_PATH + 1]; // one file only; eliminate this and improve code to allow // multiple-DLL file (un)registering DragQueryFile((HDROP)stgM.hGlobal, x, m_ppszFileUserClickedOn[x], _MAX_PATH + 1); } m_xFileCount = nFileCount; } } } } } } if(pefEtc) pefEtc->Release(); return hr; } FreeDebug @ 2003-12-04 10:46 引用Trackback(0) | 编辑 评论 发表评论 最后更新 [转帖][精华]我是怎么玩死google的 简明批处理教程 论坛回帖范例 ZT [转载]简单介绍如何在自己的Blog 上添加定制的搜索引擎 做网页如何改变IE地址栏的显示IE图标 vk键值对应码表 [转载]在鼠标右键添加"注册dll"的程序源码 [转贴]在Win2003中使用Windows XP样式的方法 通过四舍五入保留n位小数 领导来了