Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

498 lines
14 KiB

  1. /* This file contains the class factory and the COM related guts of the
  2. CShellExt class. Also the two necessary callbacks that drive the dialog.
  3. Look in the webpg.cpp file for the methods that relate to the actual functionality
  4. of the propery page itself.
  5. */
  6. #include "priv.h"
  7. #include <tchar.h>
  8. //
  9. // Initialize GUIDs (should be done only and at-least once per DLL/EXE)
  10. //
  11. #include <shlguid.h>
  12. #include <shellapi.h>
  13. #include <shlwapi.h>
  14. #include "wrapmb.h"
  15. #include "sink.h"
  16. #include <initguid.h>
  17. #include "eddir.h"
  18. #include "shellext.h"
  19. // Global variables
  20. //
  21. extern UINT g_cRefThisDll; // Reference count of this DLL.
  22. extern HINSTANCE g_hmodThisDll; // Handle to this DLL itself.
  23. //========================================= CShellExtClassFactory
  24. //---------------------------------------------------------------
  25. CShellExtClassFactory::CShellExtClassFactory()
  26. {
  27. ODS(TEXT("CShellExtClassFactory::CShellExtClassFactory()\r\n"));
  28. m_cRef = 0L;
  29. g_cRefThisDll++;
  30. }
  31. //---------------------------------------------------------------
  32. CShellExtClassFactory::~CShellExtClassFactory()
  33. {
  34. g_cRefThisDll--;
  35. }
  36. //---------------------------------------------------------------
  37. STDMETHODIMP CShellExtClassFactory::QueryInterface(REFIID riid,
  38. LPVOID FAR *ppv)
  39. {
  40. ODS(TEXT("CShellExtClassFactory::QueryInterface()\r\n"));
  41. *ppv = NULL;
  42. // Any interface on this object is the object pointer
  43. if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory))
  44. {
  45. *ppv = (LPCLASSFACTORY)this;
  46. AddRef();
  47. return NOERROR;
  48. }
  49. return E_NOINTERFACE;
  50. }
  51. //---------------------------------------------------------------
  52. STDMETHODIMP_(ULONG) CShellExtClassFactory::AddRef()
  53. {
  54. return ++m_cRef;
  55. }
  56. //---------------------------------------------------------------
  57. STDMETHODIMP_(ULONG) CShellExtClassFactory::Release()
  58. {
  59. if (--m_cRef)
  60. return m_cRef;
  61. delete this;
  62. return 0L;
  63. }
  64. //---------------------------------------------------------------
  65. STDMETHODIMP CShellExtClassFactory::CreateInstance(LPUNKNOWN pUnkOuter,
  66. REFIID riid,
  67. LPVOID *ppvObj)
  68. {
  69. ODS(TEXT("CShellExtClassFactory::CreateInstance()\r\n"));
  70. *ppvObj = NULL;
  71. // Shell extensions typically don't support aggregation (inheritance)
  72. if (pUnkOuter)
  73. return CLASS_E_NOAGGREGATION;
  74. // Create the main shell extension object. The shell will then call
  75. // QueryInterface with IID_IShellExtInit--this is how shell extensions are
  76. // initialized.
  77. LPCSHELLEXT pShellExt = new CShellExt(); //Create the CShellExt object
  78. if (NULL == pShellExt)
  79. return E_OUTOFMEMORY;
  80. return pShellExt->QueryInterface(riid, ppvObj);
  81. }
  82. //---------------------------------------------------------------
  83. STDMETHODIMP CShellExtClassFactory::LockServer(BOOL fLock)
  84. {
  85. return NOERROR;
  86. }
  87. //========================================= CShellExt
  88. //---------------------------------------------------------------
  89. // the property page creation/deletion callback procedure
  90. UINT CALLBACK ShellExtPageCallback(HWND hWnd,
  91. UINT uMessage,
  92. LPPROPSHEETPAGE ppsp)
  93. {
  94. switch(uMessage)
  95. {
  96. case PSPCB_CREATE:
  97. return TRUE;
  98. case PSPCB_RELEASE:
  99. {
  100. CShellExt * pExt = (CShellExt *)ppsp->lParam;
  101. if (pExt != NULL)
  102. {
  103. pExt->Release();
  104. }
  105. return TRUE;
  106. }
  107. }
  108. return TRUE;
  109. }
  110. //---------------------------------------------------------------
  111. INT_PTR CALLBACK ShellExtPageDlgProc(HWND hDlg,
  112. UINT uMessage,
  113. WPARAM wParam,
  114. LPARAM lParam)
  115. {
  116. // When the shell creates a dialog box for a property sheet page,
  117. // it passes the pointer to the PROPSHEETPAGE data structure as
  118. // lParam. The dialog procedures of extensions typically store it
  119. // in the DWL_USER of the dialog box window.
  120. //
  121. if ( uMessage == WM_INITDIALOG )
  122. {
  123. SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  124. }
  125. // recover the property sheet page and the asoociated shell extension
  126. // object from the window handle
  127. LPPROPSHEETPAGE psp=(LPPROPSHEETPAGE)GetWindowLongPtr(hDlg, DWLP_USER);
  128. if ( !psp )
  129. return FALSE;
  130. // get the shell extension object
  131. CShellExt * pShellExt = (CShellExt *)(psp->lParam);
  132. if (!pShellExt)
  133. return FALSE;
  134. // let the object do the work
  135. return pShellExt->OnMessage( hDlg, uMessage, wParam, lParam );
  136. }
  137. //---------------------------------------------------------------
  138. //
  139. // FUNCTION: CShellExt::ReplacePage(UINT, LPFNADDPROPSHEETPAGE, LPARAM)
  140. //
  141. // PURPOSE: Called by the shell only for Control Panel property sheet
  142. // extensions
  143. //
  144. // PARAMETERS:
  145. // uPageID - ID of page to be replaced
  146. // lpfnReplaceWith - Pointer to the Shell's Replace function
  147. // lParam - Passed as second parameter to lpfnReplaceWith
  148. //
  149. // RETURN VALUE:
  150. //
  151. // E_FAIL, since we don't support this function. It should never be
  152. // called.
  153. // COMMENTS:
  154. //
  155. STDMETHODIMP CShellExt::ReplacePage(UINT uPageID,
  156. LPFNADDPROPSHEETPAGE lpfnReplaceWith,
  157. LPARAM lParam)
  158. {
  159. ODS(TEXT("CShellExt::ReplacePage()\r\n"));
  160. return E_FAIL;
  161. }
  162. HRESULT ResolveShortcut(HWND hwnd, LPCTSTR lpszLinkFile, LPTSTR lpszPath)
  163. {
  164. HRESULT hres;
  165. IShellLink * psl;
  166. TCHAR szGotPath[MAX_PATH];
  167. TCHAR szDescription[MAX_PATH];
  168. WIN32_FIND_DATA wfd;
  169. *lpszPath = 0; // assume failure
  170. // Get a pointer to the IShellLink interface.
  171. hres = CoCreateInstance(CLSID_ShellLink, NULL,
  172. CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID *)&psl);
  173. if (SUCCEEDED(hres))
  174. {
  175. IPersistFile * ppf;
  176. // Get a pointer to the IPersistFile interface.
  177. hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
  178. if (SUCCEEDED(hres))
  179. {
  180. // Load the shortcut.
  181. hres = ppf->Load(lpszLinkFile, STGM_READ);
  182. if (SUCCEEDED(hres))
  183. {
  184. // Resolve the link.
  185. hres = psl->Resolve(hwnd, SLR_NO_UI);
  186. if (SUCCEEDED(hres))
  187. {
  188. // Get the path to the link target.
  189. hres = psl->GetPath(szGotPath,
  190. MAX_PATH, (WIN32_FIND_DATA *)&wfd,
  191. SLGP_SHORTPATH );
  192. if (SUCCEEDED(hres))
  193. {
  194. // Get the description of the target.
  195. hres = psl->GetDescription(szDescription, MAX_PATH);
  196. if (SUCCEEDED(hres))
  197. lstrcpy(lpszPath, szGotPath);
  198. }
  199. }
  200. }
  201. // Release the pointer to the IPersistFile interface.
  202. ppf->Release();
  203. }
  204. // Release the pointer to the IShellLink interface.
  205. psl->Release();
  206. }
  207. return hres;
  208. }
  209. //---------------------------------------------------------------
  210. //
  211. // FUNCTION: CShellExt::AddPages(LPFNADDPROPSHEETPAGE, LPARAM)
  212. //
  213. // PURPOSE: Called by the shell just before the property sheet is displayed.
  214. //
  215. // PARAMETERS:
  216. // lpfnAddPage - Pointer to the Shell's AddPage function
  217. // lParam - Passed as second parameter to lpfnAddPage
  218. //
  219. // RETURN VALUE:
  220. //
  221. // NOERROR in all cases. If for some reason our pages don't get added,
  222. // the Shell still needs to bring up the Properties... sheet.
  223. //
  224. // COMMENTS:
  225. //
  226. STDMETHODIMP CShellExt::AddPages(LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam)
  227. {
  228. UINT attrib;
  229. PROPSHEETPAGE psp;
  230. // we only add the page if the user has admin priviliges in the metabase
  231. if ( !FIsAdmin() )
  232. {
  233. return NOERROR;
  234. }
  235. // load the title of the property page from the resources
  236. // note the arbitrary limit of 100 characters but enough
  237. // space is allocated for 100 wide characters
  238. TCHAR szTitle[100 * 2];
  239. LoadString( g_hmodThisDll, IDS_PAGE_TITLE, szTitle, 100 );
  240. //
  241. // Create a property sheet page object from a dialog box.
  242. //
  243. // We store a pointer to our class in the psp.lParam, so we
  244. // can access our class members from within the GAKPageDlgProc
  245. //
  246. // If the page needs more instance data, you can append
  247. // arbitrary size of data at the end of this structure,
  248. // and pass it to the CreatePropSheetPage. In such a case,
  249. // the size of entire data structure (including page specific
  250. // data) must be stored in the dwSize field. Note that in
  251. // general you should NOT need to do this, as you can simply
  252. // store a pointer to date in the lParam member.
  253. //
  254. ZeroMemory( &psp, sizeof(psp) );
  255. psp.dwSize = sizeof(psp); // no extra data.
  256. psp.dwFlags = PSP_USEREFPARENT | PSP_USETITLE | PSP_USECALLBACK;
  257. psp.hInstance = g_hmodThisDll;
  258. psp.pszTemplate = MAKEINTRESOURCE(IDD_WEB_SHARE);
  259. psp.hIcon = 0;
  260. psp.pszTitle = szTitle;
  261. psp.pfnDlgProc = ShellExtPageDlgProc;
  262. psp.pcRefParent = &g_cRefThisDll;
  263. psp.pfnCallback = ShellExtPageCallback;
  264. psp.lParam = (LPARAM)this;
  265. m_hpage = CreatePropertySheetPage(&psp);
  266. if (m_hpage)
  267. {
  268. // We should AddRef here because we used this class pointer
  269. // It will be released in ShellExtPageCallback().
  270. AddRef();
  271. if (!lpfnAddPage(m_hpage, lParam))
  272. {
  273. DestroyPropertySheetPage(m_hpage);
  274. }
  275. }
  276. return NOERROR;
  277. }
  278. //---------------------------------------------------------------
  279. CShellExt::CShellExt():
  280. m_fInitializedSink( FALSE ),
  281. m_fInitialized( FALSE ),
  282. m_pMBCom( NULL ),
  283. m_fShutdownMode( FALSE ),
  284. m_pConnPoint( NULL ),
  285. m_pEventSink( NULL ),
  286. m_dwSinkCookie(0),
  287. m_hpage( NULL ),
  288. m_hwnd( NULL ),
  289. m_icon_pws(NULL),
  290. m_icon_iis(NULL),
  291. m_static_share_on_title(NULL),
  292. m_ccombo_server(NULL),
  293. m_cbtn_share(NULL),
  294. m_cbtn_not(NULL),
  295. m_cstatic_alias_title(NULL),
  296. m_cbtn_add(NULL),
  297. m_cbtn_remove(NULL),
  298. m_cbtn_edit(NULL),
  299. m_clist_list(NULL),
  300. m_static_status(NULL),
  301. m_int_share( 0 ),
  302. m_int_server(0),
  303. m_pEditAliasDlg(NULL)
  304. {
  305. ODS(TEXT("CShellExt::CShellExt()\r\n"));
  306. m_cRef = 0L;
  307. m_pDataObj = NULL;
  308. g_cRefThisDll++;
  309. }
  310. //---------------------------------------------------------------
  311. CShellExt::~CShellExt()
  312. {
  313. if (m_pDataObj)
  314. m_pDataObj->Release();
  315. g_cRefThisDll--;
  316. }
  317. //---------------------------------------------------------------
  318. STDMETHODIMP CShellExt::QueryInterface(REFIID riid, LPVOID FAR *ppv)
  319. {
  320. *ppv = NULL;
  321. if (IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown))
  322. {
  323. ODS(TEXT("CShellExt::QueryInterface()==>IID_IShellExtInit\r\n"));
  324. *ppv = (LPSHELLEXTINIT)this;
  325. }
  326. else if (IsEqualIID(riid, IID_IShellPropSheetExt))
  327. {
  328. ODS(TEXT("CShellExt::QueryInterface()==>IShellPropSheetExt\r\n"));
  329. *ppv = (LPSHELLPROPSHEETEXT)this;
  330. }
  331. if (*ppv)
  332. {
  333. AddRef();
  334. return NOERROR;
  335. }
  336. ODS(TEXT("CShellExt::QueryInterface()==>Unknown Interface!\r\n"));
  337. return E_NOINTERFACE;
  338. }
  339. //---------------------------------------------------------------
  340. STDMETHODIMP_(ULONG) CShellExt::AddRef()
  341. {
  342. ODS(TEXT("CShellExt::AddRef()\r\n"));
  343. return ++m_cRef;
  344. }
  345. //---------------------------------------------------------------
  346. STDMETHODIMP_(ULONG) CShellExt::Release()
  347. {
  348. ODS(TEXT("CShellExt::Release()\r\n"));
  349. if (--m_cRef)
  350. return m_cRef;
  351. OnFinalRelease();
  352. delete this;
  353. return 0L;
  354. }
  355. //---------------------------------------------------------------
  356. //
  357. // FUNCTION: CShellExt::Initialize(LPCITEMIDLIST, LPDATAOBJECT, HKEY)
  358. //
  359. // PURPOSE: Called by the shell when initializing a context menu or property
  360. // sheet extension.
  361. //
  362. // PARAMETERS:
  363. // pIDFolder - Specifies the parent folder
  364. // pDataObj - Spefifies the set of items selected in that folder.
  365. // hRegKey - Specifies the type of the focused item in the selection.
  366. //
  367. // RETURN VALUE:
  368. //
  369. // NOERROR in all cases.
  370. //
  371. // COMMENTS: Note that at the time this function is called, we don't know
  372. // (or care) what type of shell extension is being initialized.
  373. // It could be a context menu or a property sheet.
  374. //
  375. STDMETHODIMP CShellExt::Initialize(LPCITEMIDLIST pIDFolder,
  376. LPDATAOBJECT pDataObj,
  377. HKEY hRegKey)
  378. {
  379. BOOL bRes = FALSE;
  380. if (!pDataObj)
  381. {
  382. return(E_INVALIDARG);
  383. }
  384. FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  385. STGMEDIUM medium;
  386. HRESULT hRes = pDataObj->GetData(&fmte, &medium);
  387. if (FAILED(hRes))
  388. {
  389. return(hRes);
  390. }
  391. int count;
  392. if ( (count = DragQueryFile((HDROP)medium.hGlobal, (UINT)(-1), NULL,0)) > 0
  393. && count < 2
  394. )
  395. {
  396. TCHAR szFileName[MAX_PATH];
  397. DragQueryFile((HDROP)medium.hGlobal, 0, szFileName, sizeof(szFileName) * sizeof(TCHAR));
  398. SHFILEINFO shfi;
  399. SHGetFileInfo(szFileName, 0, &shfi, sizeof(SHFILEINFO), SHGFI_ATTRIBUTES);
  400. if (shfi.dwAttributes & SFGAO_LINK)
  401. bRes = FALSE;
  402. else if (shfi.dwAttributes & SFGAO_FILESYSTEM)
  403. {
  404. int drive_number;
  405. TCHAR szRoot[4];
  406. int nType;
  407. if ( -1 != (drive_number = PathGetDriveNumber(szFileName))
  408. && NULL != PathBuildRoot(szRoot, drive_number)
  409. && DRIVE_REMOTE != (nType = GetDriveType(szRoot))
  410. && DRIVE_NO_ROOT_DIR != nType
  411. )
  412. {
  413. bRes = TRUE;
  414. StrCpy(m_szPropSheetFileUserClickedOn, szFileName);
  415. }
  416. }
  417. }
  418. ReleaseStgMedium(&medium);
  419. if (bRes)
  420. {
  421. // Initialize can be called more than once
  422. if (m_pDataObj)
  423. m_pDataObj->Release();
  424. // duplicate the object pointer and registry handle
  425. if (pDataObj)
  426. {
  427. m_pDataObj = pDataObj;
  428. pDataObj->AddRef();
  429. }
  430. return NOERROR;
  431. }
  432. return E_FAIL;
  433. }