ShellExtImpl.cpp
上传用户:lswyart
上传日期:2008-06-12
资源大小:3441k
文件大小:12k
源码类别:

杀毒

开发平台:

Visual C++

  1. //-----------------------------------------------------------------------------
  2. // Name:        ShellExtImpl.cpp
  3. // Product:     ClamWin Antivirus
  4. //
  5. // Author:      alch [alch at users dot sourceforge dot net]
  6. //
  7. // Created:     2004/19/03
  8. // Copyright:   Copyright alch (c) 2004
  9. // Licence:     
  10. //   This program is free software; you can redistribute it and/or modify
  11. //   it under the terms of the GNU General Public License as published by
  12. //   the Free Software Foundation; either version 2 of the License, or
  13. //   (at your option) any later version.
  14. // 
  15. //   This program is distributed in the hope that it will be useful,
  16. //   but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18. //   GNU General Public License for more details.
  19. // 
  20. //   You should have received a copy of the GNU General Public License
  21. //   along with this program; if not, write to the Free Software
  22. //   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  23. //-----------------------------------------------------------------------------
  24. #include <windows.h>
  25. #include <tchar.h>
  26. #include <stdio.h>
  27. #include <shlobj.h>
  28. #include "ShellExt.h"
  29. #define ResultFromShort(i)  ResultFromScode(MAKE_SCODE(SEVERITY_SUCCESS, 0, (USHORT)(i)))
  30. extern HINSTANCE g_hmodThisDll; // Handle to this DLL itself.
  31. int _tcsreplace(LPTSTR sz, TCHAR chr,  TCHAR repl_chr) 
  32. {
  33.     int count = 0;              
  34.     for (; *sz!=_T(''); sz++)             
  35.         if (*sz == chr) {        
  36.             *sz = repl_chr;      
  37.             count++;            
  38.         }
  39.     return count;               
  40. }
  41. //
  42. //  FUNCTION: CShellExt::Initialize(LPCITEMIDLIST, LPDATAOBJECT, HKEY)
  43. //
  44. //  PURPOSE: Called by the shell when initializing a context menu or property
  45. //           sheet extension.
  46. //
  47. //  PARAMETERS:
  48. //    pIDFolder - Specifies the parent folder
  49. //    pDataObj  - Spefifies the set of items selected in that folder.
  50. //    hRegKey   - Specifies the type of the focused item in the selection.
  51. //
  52. //  RETURN VALUE:
  53. //
  54. //    NOERROR in all cases.
  55. //
  56. //  COMMENTS:   Note that at the time this function is called, we don't know 
  57. //              (or care) what type of shell extension is being initialized.  
  58. //              It could be a context menu or a property sheet.
  59. //
  60. STDMETHODIMP CShellExt::Initialize(LPCITEMIDLIST pIDFolder,
  61.                                    LPDATAOBJECT pDataObj,
  62.                                    HKEY hRegKey)
  63. {
  64. HRESULT hres = E_FAIL;
  65. STGMEDIUM medium;
  66. FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  67. TCHAR szPath[MAX_PATH];
  68. INT len, numFiles;
  69. // Initialize can be called more than once
  70. if (m_pDataObj)
  71. m_pDataObj->Release();
  72. // duplicate the object pointer and registry handle
  73. if (pDataObj)
  74. {
  75. m_pDataObj = pDataObj;
  76. pDataObj->AddRef();
  77. }
  78. // use the given IDataObject to get a list of filenames (CF_HDROP)
  79. hres = pDataObj->GetData(&fmte, &medium);
  80. if(FAILED(hres))
  81. return E_FAIL;
  82. // find out how many files the user selected
  83. // not more than 250 though, otherwise explorer crashes
  84. numFiles = DragQueryFile((HDROP)medium.hGlobal, (UINT)-1, NULL, 0);
  85. if(numFiles > 250)
  86. return E_FAIL;
  87. // free old path (just in case)
  88. if(m_szPath)
  89. {
  90.         delete [] m_szPath;
  91.       m_szPath = NULL;
  92.     }
  93. // allocate memory for our combined path
  94. // add length of [ --path=""]
  95. INT cbPath = (MAX_PATH + 10) * numFiles;
  96. m_szPath = new TCHAR[cbPath];
  97. m_szPath[0] = _T('');
  98. for(int i = 0; i < numFiles; i++)
  99. {
  100. DragQueryFile((HDROP)medium.hGlobal, i, szPath, sizeof(szPath));
  101. // check the long path validity for a unicode build
  102. #if defined UNICODE || defined _UNICODE
  103. {
  104. CHAR atemp[MAX_PATH];
  105. BOOL invalid;
  106. if(!WideCharToMultiByte(CP_OEMCP, WC_NO_BEST_FIT_CHARS, szPath, -1, 
  107.          atemp, sizeof(atemp), NULL, &invalid) || invalid)
  108.      {
  109.      WCHAR wtemp[MAX_PATH];
  110.      // unicode name is not directly tranleatable to ascii, use the shortname instead          
  111.         if(GetShortPathNameW(szPath, wtemp, sizeof(wtemp)) > 0)
  112.        wcscpy(szPath, wtemp);
  113.      }    
  114. }
  115. #endif
  116. // convert  to / so cygwin doesn't go crazy (particularly over UNC names)
  117. _tcsreplace(szPath, _T('\'), _T('/'));
  118. len = _tcslen(szPath);
  119. // remove last slash from the scanning path
  120.         if(szPath[len-1] == _T('/'))
  121.             szPath[len-1] = _T('');
  122.         _tcsncat(m_szPath, _T(" --path=""), cbPath);
  123.         _tcsncat(m_szPath, szPath, cbPath);
  124.         _tcsncat(m_szPath, _T("""), cbPath);
  125. }
  126. ::ReleaseStgMedium(&medium);
  127. return NOERROR;
  128. }
  129. //
  130. //  FUNCTION: CShellExt::QueryContextMenu(HMENU, UINT, UINT, UINT, UINT)
  131. //
  132. //  PURPOSE: Called by the shell just before the context menu is displayed.
  133. //           This is where you add your specific menu items.
  134. //
  135. //  PARAMETERS:
  136. //    hMenu      - Handle to the context menu
  137. //    indexMenu  - Index of where to begin inserting menu items
  138. //    idCmdFirst - Lowest value for new menu ID's
  139. //    idCmtLast  - Highest value for new menu ID's
  140. //    uFlags     - Specifies the context of the menu event
  141. //
  142. //  RETURN VALUE:
  143. //
  144. //
  145. //  COMMENTS:
  146. //
  147. // The menu text
  148. STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu,UINT indexMenu,UINT idCmdFirst,UINT idCmdLast,UINT uFlags)
  149. {
  150. UINT idCmd = idCmdFirst;
  151. HRESULT hr = E_INVALIDARG;
  152. // Seperator
  153. ::InsertMenu(hMenu, indexMenu++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);
  154. ::InsertMenu(hMenu, indexMenu++, MF_STRING|MF_BYPOSITION, idCmd++, _T("Scan with ClamWin Free Antivirus"));
  155. // Seperator
  156. ::InsertMenu(hMenu, indexMenu++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);
  157. return ResultFromShort(idCmd-idCmdFirst); //Must return number of menu
  158. //items we added.
  159. }
  160. BOOL CShellExt::Scan(HWND hwnd)
  161. {
  162.     DWORD len;
  163.     if(!m_szPath || !_tcslen(m_szPath))
  164.     {
  165.         MessageBox(hwnd, _T("Error: Unable to retrieve Path."), _T("ClamWin Free Antivirus"), MB_OK | MB_ICONERROR);
  166.         return FALSE;
  167.     }            
  168.     
  169.     DWORD dwType, cbData;
  170.     DWORD szCmdSize = MAX_PATH*3 + _tcslen(m_szPath);
  171.     PTCHAR szCmd = new TCHAR[szCmdSize];
  172.     TCHAR szClamWinPath[MAX_PATH] = _T("");
  173.     TCHAR szParams[MAX_PATH*2] = _T("");
  174.     TCHAR szPathExpanded[MAX_PATH], szParamsExpanded[MAX_PATH*2];
  175.     // get path to ClamWin
  176.     // Try registry first
  177.     HKEY hKey;
  178.     // try in hkey_current_user
  179.     if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software\ClamWin"), 0, KEY_READ, &hKey)) 
  180.     {
  181.         cbData = sizeof(szClamWinPath);
  182.         RegQueryValueEx(hKey, _T("Path"), NULL, &dwType, (PBYTE)szClamWinPath, &cbData);
  183.         CloseHandle(hKey);
  184.     }
  185.     // try in hkey_local_machine if failed
  186.     if (!_tcslen(szClamWinPath) && 
  187.      (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\ClamWin"), 0, KEY_READ, &hKey)))
  188.     {
  189.         cbData = sizeof(szClamWinPath);
  190.         RegQueryValueEx(hKey, _T("Path"), NULL, &dwType, (PBYTE)szClamWinPath, &cbData);
  191.         CloseHandle(hKey);
  192.     }
  193.     if(!_tcslen(szClamWinPath))
  194.     {
  195.         // could not retrieve from registry    
  196.         // try in the same folder as the shell extension
  197.         TCHAR szModule[MAX_PATH];
  198.         if(GetModuleFileName(NULL, szModule, sizeof(szModule)))
  199.         {
  200.             // get folder name    
  201.             _tsplitpath(szModule, NULL, szClamWinPath, NULL, NULL);            
  202.         }
  203.     }
  204.     len = _tcslen(szClamWinPath);
  205.     if(!len)
  206.     {
  207.         MessageBox(hwnd, _T("Error: Unable to retrieve path to ClamWin. Please reinstall ClamWin Free Antivirus"), _T("ClamWin Free Antivirus"), MB_OK | MB_ICONERROR);
  208.         delete [] szCmd;
  209.         return FALSE;
  210.     }
  211.     // Expand Env
  212.     ExpandEnvironmentStrings(szClamWinPath, szPathExpanded, sizeof(szPathExpanded));
  213.     len = _tcslen(szPathExpanded);
  214.     // remove trailing slash
  215.     if(szPathExpanded[len-1] == _T('\'))
  216.         szPathExpanded[len-1] = _T('');
  217.     _sntprintf(szCmd, szCmdSize, _T(""%s\%s" --mode=scanner %s"), 
  218.                 szPathExpanded, _T("ClamWin.exe"), m_szPath);
  219.                                        
  220.     // read  optional params from registry
  221.     if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, 
  222.                 _T("Classes\CLSID\{65713842-C410-4f44-8383-BFE01A398C90}\InProcServer32"), 0, KEY_READ, &hKey) || 
  223.         ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
  224.                 _T("Classes\CLSID\{65713842-C410-4f44-8383-BFE01A398C90}\InProcServer32"), 0, KEY_READ, &hKey))
  225.     {
  226.         cbData = sizeof(szParams);
  227.         RegQueryValueEx(hKey, _T("params"), NULL, &dwType, (PBYTE)szParams, &cbData);
  228.         CloseHandle(hKey);      
  229.         // append params if exist
  230.         if (szParams[0] != _T('')) 
  231.         {
  232.             // Expand Env
  233.             ExpandEnvironmentStrings(szParams, szParamsExpanded, sizeof(szParamsExpanded));
  234.             _tcsncat(szCmd, _T(" "), sizeof(szCmd));
  235.             _tcsncat(szCmd, szParamsExpanded, sizeof(szCmd));
  236.         }
  237.     }        
  238.                 
  239.     STARTUPINFO si;
  240.     PROCESS_INFORMATION pi;
  241.     ZeroMemory( &si, sizeof(si) );
  242.     si.cb = sizeof(si);
  243.     ZeroMemory( &pi, sizeof(pi) );
  244.     // Start the child process. 
  245.     if( !CreateProcess( NULL, // No module name (use command line). 
  246.         szCmd,            // Command line. 
  247.         NULL,             // Process handle not inheritable. 
  248.         NULL,             // Thread handle not inheritable. 
  249.         FALSE,            // Set handle inheritance to FALSE. 
  250.         0,                // No creation flags. 
  251.         NULL,             // Use parent's environment block. 
  252.         NULL,             // Use parent's starting directory. 
  253.         &si,              // Pointer to STARTUPINFO structure.
  254.         &pi )             // Pointer to PROCESS_INFORMATION structure.
  255.     )    
  256.     {
  257.         TCHAR szMsg[MAX_PATH*2];
  258.         _sntprintf(szMsg, sizeof(szMsg), _T("Error: Unable to execute command %s."), szCmd);
  259.         MessageBox(hwnd, szMsg, _T("ClamWin Free Antivirus"), MB_OK | MB_ICONERROR);        
  260.         delete [] szCmd;
  261.         return FALSE;
  262.     }
  263.     delete [] szCmd;
  264.     // Close process and thread handles. 
  265.     CloseHandle( pi.hProcess );
  266.     CloseHandle( pi.hThread );
  267.     
  268.     return TRUE;        
  269. }
  270. //
  271. //  FUNCTION: CShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO)
  272. //
  273. //  PURPOSE: Called by the shell after the user has selected on of the
  274. //           menu items that was added in QueryContextMenu().
  275. //
  276. //  PARAMETERS:
  277. //    lpcmi - Pointer to an CMINVOKECOMMANDINFO structure
  278. //
  279. //  RETURN VALUE: HRESULT code signifying success or failure;NOERROR if no error
  280. //
  281. //
  282. //  COMMENTS:
  283. //
  284. STDMETHODIMP CShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
  285. {
  286. HRESULT hr = E_INVALIDARG;
  287. //If HIWORD(lpcmi->lpVerb) then we have been called programmatically
  288. //and lpVerb is a command that should be invoked.  Otherwise, the shell
  289. //has called us, and LOWORD(lpcmi->lpVerb) is the menu ID the user has
  290. //selected.  Actually, it's (menu ID - idCmdFirst) from QueryContextMenu().
  291. if (!HIWORD(lpcmi->lpVerb))
  292. {
  293. UINT idCmd = LOWORD(lpcmi->lpVerb);
  294. switch (idCmd)
  295. {
  296. case 0:
  297.     Scan(lpcmi->hwnd);     
  298. break;
  299. }
  300. hr = NOERROR;
  301. }
  302. return hr;
  303. }
  304. //
  305. //  FUNCTION: CShellExt::GetCommandString(UINT idCmd,UINT uFlags,UINT FAR *reserved,LPSTR pszName,UINT cchMax)
  306. //
  307. //  PURPOSE: Called by the shell to retreive the cononical command name
  308. //  or help text for a menu item added by a context menu extension handler
  309. //
  310. //  PARAMETERS:
  311. //   idCmd - Menu item ID offset
  312. //    uFlags - Value specifying the type of information to retreive
  313. //    *reserved - Pointer to reserved value
  314. //    pszName - Pointer to buffer to receive name string or help text
  315. //    cchMax - Buffer size
  316. //
  317. //  RETURN VALUE: HRESULT code signifying success or failure;NOERROR if no error
  318. //
  319. //
  320. //  COMMENTS:
  321. //
  322. STDMETHODIMP CShellExt::GetCommandString(UINT idCmd,UINT uFlags,UINT FAR *reserved,LPSTR pszName,UINT cchMax)
  323. {
  324. switch (idCmd)
  325. {
  326. case 0:
  327. if (GCS_HELPTEXTW == uFlags)
  328. wcsncpy((LPWSTR)pszName, L"ClamWin Free Antivirus", cchMax);
  329. else if (GCS_HELPTEXTA == uFlags)
  330. strncpy(pszName, "ClamWin Free Antivirus", cchMax);
  331. break;
  332.    }
  333. return NOERROR;
  334. }