Leaked source code of windows server 2003
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.

553 lines
20 KiB

  1. // shimgvw.cpp : Implementation of DLL Exports.
  2. #include "precomp.h"
  3. #include "resource.h"
  4. #include "cfdefs.h"
  5. #include "advpub.h"
  6. #include "initguid.h"
  7. #include "shimgvw.h"
  8. #include "guids.h"
  9. #include "shutil.h"
  10. #include <gdiplusImaging.h>
  11. #define DECLARE_DEBUG
  12. #define SZ_DEBUGINI "ccshell.ini"
  13. #define SZ_DEBUGSECTION "Shell Image View"
  14. #define SZ_MODULE "SHIMGVW"
  15. #include <debug.h>
  16. #define DECL_CRTFREE
  17. #include <crtfree.h>
  18. #include "prevCtrl.h" // for CPreview
  19. #define IIDSTR_IExtractImage "{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}"
  20. #define REGSTR_APPROVED "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"
  21. LPCSTR const c_rgszDocFileExts[] =
  22. {
  23. ".doc",
  24. ".dot",
  25. ".xls",
  26. ".xlt",
  27. ".obd",
  28. ".obt",
  29. ".ppt",
  30. ".pot",
  31. ".mic",
  32. ".mix",
  33. ".fpx",
  34. ".mpp"
  35. };
  36. LPCSTR const c_rgszHtmlExts[] =
  37. {
  38. ".html",
  39. ".htm",
  40. ".url",
  41. ".mhtml",
  42. ".mht",
  43. ".xml",
  44. ".nws",
  45. ".eml"
  46. };
  47. CComModule _Module;
  48. BEGIN_OBJECT_MAP(ObjectMap)
  49. OBJECT_ENTRY(CLSID_Preview, CPreview)
  50. OBJECT_ENTRY(CLSID_GdiThumbnailExtractor, CGdiPlusThumb)
  51. OBJECT_ENTRY(CLSID_DocfileThumbnailHandler, CDocFileThumb)
  52. OBJECT_ENTRY(CLSID_HtmlThumbnailExtractor, CHtmlThumb)
  53. END_OBJECT_MAP()
  54. CF_TABLE_BEGIN(g_ObjectInfo)
  55. CF_TABLE_ENTRY(&CLSID_ShellImageDataFactory, CImageDataFactory_CreateInstance, COCREATEONLY),
  56. CF_TABLE_ENTRY(&CLSID_PhotoVerbs, CPhotoVerbs_CreateInstance, COCREATEONLY),
  57. CF_TABLE_ENTRY(&CLSID_AutoplayForSlideShow, CAutoplayForSlideShow_CreateInstance, COCREATEONLY),
  58. CF_TABLE_ENTRY(&CLSID_ImagePropertyHandler, CImageData_CreateInstance, COCREATEONLY),
  59. CF_TABLE_ENTRY(&CLSID_ImageRecompress, CImgRecompress_CreateInstance, COCREATEONLY),
  60. CF_TABLE_END(g_ObjectInfo)
  61. /////////////////////////////////////////////////////////////////////////////
  62. // DLL Entry Point
  63. extern "C"
  64. BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
  65. {
  66. if (dwReason == DLL_PROCESS_ATTACH)
  67. {
  68. SHFusionInitializeFromModule(hInstance);
  69. _Module.Init(ObjectMap, hInstance);
  70. DisableThreadLibraryCalls(hInstance);
  71. }
  72. else if (dwReason == DLL_PROCESS_DETACH)
  73. {
  74. _Module.Term();
  75. SHFusionUninitialize();
  76. }
  77. return TRUE;
  78. }
  79. /////////////////////////////////////////////////////////////////////////////
  80. // Used to determine whether the DLL can be unloaded by OLE
  81. STDAPI DllCanUnloadNow(void)
  82. {
  83. return (_Module.GetLockCount()==0) ? S_OK : S_FALSE;
  84. }
  85. // some types can only wallpaper on win32
  86. #ifdef _WIN64
  87. #define IMAGEOPTION_CANWALLPAPER_WIN32 0
  88. #else
  89. #define IMAGEOPTION_CANWALLPAPER_WIN32 IMAGEOPTION_CANWALLPAPER
  90. #endif
  91. #define IMGOPT_ALL (IMAGEOPTION_CANWALLPAPER | IMAGEOPTION_CANROTATE)
  92. #define IMGOPT_ALLW32 (IMAGEOPTION_CANWALLPAPER_WIN32 | IMAGEOPTION_CANROTATE)
  93. #define IMGOPT_NONE 0
  94. /////////////////////////////////////////////////////////////////////////////
  95. // Returns a class factory to create an object of the requested type
  96. typedef struct { LPTSTR szExt; LPTSTR pszContentType; LPTSTR szProgId; LPTSTR szProgram; DWORD dwOpts;} FILETYPEINFO;
  97. // { ".EXT", "progid", old program, IMGOPT
  98. FILETYPEINFO g_rgExtentions[] = {
  99. { TEXT(".bmp"), TEXT("image/bmp"), TEXT("Paint.Picture"), TEXT("mspaint.exe"), IMGOPT_ALL, },
  100. { TEXT(".dib"), TEXT("image/bmp"), TEXT("Paint.Picture"), TEXT("mspaint.exe"), IMGOPT_ALL, },
  101. { TEXT(".emf"), NULL, TEXT("emffile"), TEXT(""), IMGOPT_NONE, },
  102. { TEXT(".gif"), TEXT("image/gif"), TEXT("giffile"), TEXT("iexplore.exe"), IMGOPT_ALLW32 },
  103. { TEXT(".jfif"),TEXT("image/jpeg"), TEXT("pjpegfile"), TEXT("iexplore.exe"), IMGOPT_ALLW32 },
  104. { TEXT(".jpg"), TEXT("image/jpeg"), TEXT("jpegfile"), TEXT("iexplore.exe"), IMGOPT_ALLW32 },
  105. { TEXT(".jpe"), TEXT("image/jpeg"), TEXT("jpegfile"), TEXT("iexplore.exe"), IMGOPT_ALLW32 },
  106. { TEXT(".jpeg"),TEXT("image/jpeg"), TEXT("jpegfile"), TEXT("iexplore.exe"), IMGOPT_ALLW32 },
  107. { TEXT(".png"), TEXT("image/png"), TEXT("pngfile"), TEXT("iexplore.exe"), IMGOPT_ALLW32 },
  108. { TEXT(".tif"), TEXT("image/tiff"), TEXT("TIFImage.Document"), TEXT("KodakPrv.exe"), IMGOPT_NONE, },
  109. { TEXT(".tiff"),TEXT("image/tiff"), TEXT("TIFImage.Document"), TEXT("KodakPrv.exe"), IMGOPT_NONE, },
  110. { TEXT(".wmf"), NULL, TEXT("wmffile"), TEXT(""), IMGOPT_NONE, },
  111. };
  112. const TCHAR c_szBitmapIcon[] = TEXT("shimgvw.dll,1");
  113. const TCHAR c_szDefaultIcon[] = TEXT("shimgvw.dll,2");
  114. const TCHAR c_szJPegIcon[] = TEXT("shimgvw.dll,3");
  115. const TCHAR c_szTifIcon[] = TEXT("shimgvw.dll,4");
  116. // we might have to create a missing Prog ID so we need to know its default info.
  117. typedef struct { LPCTSTR szProgID; int iResId; LPCTSTR szIcon; BOOL fDone; } PROGIDINFO;
  118. // { "ProgID" "Description" "DefaultIcon" done? }
  119. PROGIDINFO g_rgProgIDs[] = {
  120. { TEXT("emffile"), IDS_EMFIMAGE, c_szDefaultIcon, FALSE },
  121. { TEXT("giffile"), IDS_GIFIMAGE, c_szDefaultIcon, FALSE },
  122. { TEXT("jpegfile"), IDS_JPEGIMAGE, c_szJPegIcon, FALSE },
  123. { TEXT("Paint.Picture"), IDS_BITMAPIMAGE, c_szBitmapIcon, FALSE },
  124. { TEXT("pjpegfile"), IDS_JPEGIMAGE, c_szJPegIcon, FALSE },
  125. { TEXT("pngfile"), IDS_PNGIMAGE, c_szDefaultIcon, FALSE },
  126. { TEXT("TIFImage.Document"),IDS_TIFIMAGE, c_szTifIcon, FALSE },
  127. { TEXT("wmffile"), IDS_WMFIMAGE, c_szDefaultIcon, FALSE },
  128. };
  129. BOOL _ShouldSlamVerb(HKEY hkProgid, BOOL fForce, PCWSTR pszKey, PCWSTR pszApp, PCWSTR pszModule)
  130. {
  131. if (!fForce)
  132. {
  133. TCHAR szOld[MAX_PATH*2];
  134. DWORD cbOld = sizeof(szOld);
  135. if (ERROR_SUCCESS == SHGetValue(hkProgid, pszKey, NULL, NULL, szOld, &cbOld) && *szOld)
  136. {
  137. // if we know about this app, then blow it away
  138. if ((*pszApp && StrStrI(szOld, pszApp))
  139. || StrStrI(szOld, pszModule)
  140. || StrStrI(szOld, TEXT("wangimg.exe"))) // NT4 app
  141. {
  142. fForce = TRUE;
  143. }
  144. }
  145. else
  146. {
  147. fForce = TRUE;
  148. }
  149. }
  150. return fForce;
  151. }
  152. BOOL _ExtIsProgid(PCTSTR pszExt, PCTSTR pszProgid, DWORD dwOpts)
  153. {
  154. // default to take-over
  155. BOOL fRet = TRUE;
  156. TCHAR sz[MAX_PATH];
  157. // make sure this is in the openwith list
  158. wnsprintf(sz, ARRAYSIZE(sz), TEXT("%s\\OpenWithProgids"), pszExt);
  159. SHSetValue(HKEY_CLASSES_ROOT, sz, pszProgid, REG_NONE, NULL, NULL);
  160. // make sure the flags are set for our verbs to show up
  161. wnsprintf(sz, ARRAYSIZE(sz), TEXT("SystemFileAssociations\\%s"), pszExt);
  162. SHSetValue(HKEY_CLASSES_ROOT, sz, TEXT("ImageOptionFlags"), REG_DWORD, &dwOpts, sizeof(dwOpts));
  163. SHSetValue(HKEY_CLASSES_ROOT, pszExt, TEXT("PerceivedType"), REG_SZ, TEXT("image"), sizeof(TEXT("image")));
  164. DWORD cb = sizeof(sz);
  165. if (ERROR_SUCCESS == SHGetValue(HKEY_CLASSES_ROOT, pszExt, NULL, NULL, sz, &cb))
  166. {
  167. // empty or match is good
  168. fRet = (!*sz || 0 == StrCmpI(sz, pszProgid));
  169. }
  170. // always remove bogus Trident IExtractImage entries
  171. wnsprintf(sz, ARRAYSIZE(sz), TEXT("%s\\shellex\\{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}"), pszExt);
  172. SHDeleteKey(HKEY_CLASSES_ROOT, sz);
  173. PathRemoveFileSpec(sz);
  174. SHDeleteEmptyKey(HKEY_CLASSES_ROOT, sz);
  175. return fRet;
  176. }
  177. PROGIDINFO *_ShouldSetupProgid(FILETYPEINFO *pfti, BOOL fForce)
  178. {
  179. PROGIDINFO *ppi = NULL;
  180. if (_ExtIsProgid(pfti->szExt, pfti->szProgId, pfti->dwOpts) || fForce)
  181. {
  182. // take it over
  183. SHSetValue(HKEY_CLASSES_ROOT, pfti->szExt, NULL, REG_SZ, pfti->szProgId, CbFromCch(lstrlen(pfti->szProgId)+1));
  184. if (pfti->pszContentType)
  185. {
  186. SHSetValue(HKEY_CLASSES_ROOT, pfti->szExt, TEXT("Content Type"), REG_SZ, pfti->pszContentType, CbFromCch(lstrlen(pfti->pszContentType)+1));
  187. }
  188. // we now know that szProgID is the ProgID for this extention.
  189. // look up the index into the ProgID table to see if we did this one already.
  190. int iProgIdIndex;
  191. for (iProgIdIndex=0; iProgIdIndex<ARRAYSIZE(g_rgProgIDs); iProgIdIndex++)
  192. {
  193. if (0 == StrCmpI(g_rgProgIDs[iProgIdIndex].szProgID, pfti->szProgId))
  194. {
  195. if (!g_rgProgIDs[iProgIdIndex].fDone)
  196. ppi = &g_rgProgIDs[iProgIdIndex];
  197. break;
  198. }
  199. }
  200. }
  201. return ppi;
  202. }
  203. void RegisterFileType(FILETYPEINFO *pfti, BOOL fForce)
  204. {
  205. PROGIDINFO *ppi = _ShouldSetupProgid(pfti, fForce);
  206. if (ppi)
  207. {
  208. // this ProgID is in our table
  209. HKEY hkeyProgId;
  210. LRESULT lres = RegCreateKeyEx(HKEY_CLASSES_ROOT,
  211. pfti->szProgId,
  212. 0, NULL,
  213. REG_OPTION_NON_VOLATILE,
  214. KEY_READ|KEY_WRITE, NULL,
  215. &hkeyProgId, NULL);
  216. if (ERROR_SUCCESS == lres)
  217. {
  218. LPCTSTR pszIcon = ppi->szIcon;
  219. TCHAR szModPath[MAX_PATH];
  220. GetModuleFileName(_Module.GetModuleInstance(), szModPath, ARRAYSIZE(szModPath));
  221. PCWSTR pszModule = PathFindFileName(szModPath);
  222. TCHAR szCmd[MAX_PATH * 2];
  223. // should we slam the default value?
  224. // to progid = "EXT file"
  225. if (_ShouldSlamVerb(hkeyProgId, fForce, L"shell\\open\\command", pfti->szProgram, pszModule))
  226. {
  227. SHDeleteKey(hkeyProgId, TEXT("shell\\open"));
  228. wnsprintf(szCmd, ARRAYSIZE(szCmd), TEXT("rundll32.exe %s,ImageView_Fullscreen %%1"), szModPath);
  229. SHRegSetPath(hkeyProgId, TEXT("shell\\open\\command"), NULL, szCmd, 0);
  230. SHStringFromGUID(CLSID_PhotoVerbs, szCmd, ARRAYSIZE(szCmd));
  231. SHSetValue(hkeyProgId, TEXT("shell\\open\\DropTarget"), TEXT("Clsid"), REG_SZ, szCmd, CbFromCch(lstrlen(szCmd)+1));
  232. wnsprintf(szCmd, ARRAYSIZE(szCmd), TEXT("@%s,%d"), pszModule, -IDS_PREVIEW_CTX);
  233. SHSetValue(hkeyProgId, TEXT("shell\\open"), TEXT("MuiVerb"), REG_SZ, szCmd, CbFromCch(lstrlen(szCmd)+1));
  234. SHRegSetPath(hkeyProgId, TEXT("DefaultIcon"), NULL, pszIcon, 0);
  235. }
  236. if (_ShouldSlamVerb(hkeyProgId, fForce, L"shell\\printto\\command", TEXT("mspaint.exe"), pszModule))
  237. {
  238. SHDeleteKey(hkeyProgId, TEXT("shell\\printto"));
  239. wnsprintf(szCmd, ARRAYSIZE(szCmd), TEXT("rundll32.exe %s,ImageView_PrintTo /pt \"%%1\" \"%%2\" \"%%3\" \"%%4\""), szModPath);
  240. SHRegSetPath(hkeyProgId, TEXT("shell\\printto\\command"), NULL, szCmd, 0);
  241. }
  242. // this will delete print verb
  243. // print is added in selfreg under HKCR\SystemFileAssociations\image\Print
  244. if (_ShouldSlamVerb(hkeyProgId, fForce, L"shell\\print\\command", TEXT("mspaint.exe"), pszModule))
  245. {
  246. SHDeleteKey(hkeyProgId, TEXT("shell\\print"));
  247. }
  248. // Modify the EditFlags: it's okay to run these without prompting...
  249. DWORD dwEditFlags = 0;
  250. DWORD cbEditFlags = sizeof(dwEditFlags);
  251. SHGetValue(hkeyProgId, NULL, TEXT("EditFlags"), NULL, &dwEditFlags, &cbEditFlags);
  252. dwEditFlags |= 0x00010000; // turn on the "okay to run without prompt" flag
  253. SHSetValue(hkeyProgId, NULL, TEXT("EditFlags"), REG_DWORD, &dwEditFlags, sizeof(dwEditFlags));
  254. RegCloseKey(hkeyProgId);
  255. }
  256. ppi->fDone = TRUE;
  257. }
  258. }
  259. HRESULT _CallRegInstall(LPCSTR szSection, BOOL bUninstall)
  260. {
  261. HRESULT hr = E_FAIL;
  262. HINSTANCE hinstAdvPack = LoadLibrary(TEXT("ADVPACK.DLL"));
  263. if (hinstAdvPack)
  264. {
  265. REGINSTALL pfnri = (REGINSTALL)GetProcAddress(hinstAdvPack, "RegInstall");
  266. if (pfnri)
  267. {
  268. STRENTRY seReg[] = {
  269. { "25", "%SystemRoot%" },
  270. { "11", "%SystemRoot%\\system32" },
  271. };
  272. STRTABLE stReg = { ARRAYSIZE(seReg), seReg };
  273. hr = pfnri(_Module.GetModuleInstance(), szSection, &stReg);
  274. if (bUninstall)
  275. {
  276. // ADVPACK will return E_UNEXPECTED if you try to uninstall
  277. // (which does a registry restore) on an INF section that was
  278. // never installed. We uninstall sections that may never have
  279. // been installed, so ignore this error
  280. hr = ((E_UNEXPECTED == hr) ? S_OK : hr);
  281. }
  282. }
  283. FreeLibrary(hinstAdvPack);
  284. }
  285. return hr;
  286. }
  287. void _FixupProgid(PCSTR pszExt, PCSTR pszProgid)
  288. {
  289. HKEY hk;
  290. DWORD dwRet = RegOpenKeyExA(HKEY_CLASSES_ROOT, pszExt, 0, KEY_QUERY_VALUE, &hk);
  291. if (dwRet == ERROR_SUCCESS)
  292. {
  293. // if its empty, then we need to fix it up.
  294. CHAR sz[MAX_PATH];
  295. DWORD cb = sizeof(sz);
  296. if (ERROR_SUCCESS == SHGetValueA(hk, NULL, NULL, NULL, sz, &cb) && !*sz)
  297. {
  298. SHSetValueA(hk, NULL, NULL, REG_SZ, pszProgid, CbFromCchA(lstrlenA(pszProgid)+1));
  299. }
  300. }
  301. }
  302. HRESULT RegisterHandler(const LPCSTR *ppszExts, UINT cExts, LPCSTR pszIID, LPCSTR pszCLSID)
  303. {
  304. for (UINT cKey = 0; cKey < cExts; cKey ++)
  305. {
  306. CHAR szKey[MAX_PATH];
  307. wnsprintfA(szKey, ARRAYSIZE(szKey), "SystemFileAssociations\\%s\\shellex\\%s", *ppszExts, pszIID);
  308. SHDeleteKeyA(HKEY_CLASSES_ROOT, szKey);
  309. SHSetValueA(HKEY_CLASSES_ROOT, szKey, NULL, REG_SZ, pszCLSID, CbFromCch(lstrlenA(pszCLSID)+1));
  310. ppszExts++;
  311. }
  312. return S_OK;
  313. }
  314. HRESULT UnregisterHandler(const LPCSTR *ppszExts, UINT cExts, LPCSTR pszIID, LPCSTR pszCLSID)
  315. {
  316. for (UINT cKey = 0; cKey < cExts; cKey ++)
  317. {
  318. CHAR szKey[MAX_PATH];
  319. CHAR szCLSID[256];
  320. DWORD dwSize = sizeof(szCLSID);
  321. wnsprintfA(szKey, ARRAYSIZE(szKey), "SystemFileAssociations\\%s\\shellex\\%s", *ppszExts, pszIID);
  322. if (ERROR_SUCCESS == SHGetValueA(HKEY_CLASSES_ROOT, szKey, NULL, NULL, &szCLSID, &dwSize))
  323. {
  324. if (!StrCmpIA(szCLSID, pszCLSID))
  325. {
  326. SHDeleteKeyA(HKEY_CLASSES_ROOT, szKey);
  327. }
  328. }
  329. dwSize = sizeof(szCLSID);
  330. wnsprintfA(szKey, ARRAYSIZE(szKey), "%s\\shellex\\%s", *ppszExts, pszIID);
  331. if (ERROR_SUCCESS == SHGetValueA(HKEY_CLASSES_ROOT, szKey, NULL, NULL, &szCLSID, &dwSize))
  332. {
  333. if (!StrCmpIA(szCLSID, pszCLSID))
  334. {
  335. SHDeleteKeyA(HKEY_CLASSES_ROOT, szKey);
  336. }
  337. }
  338. ppszExts++;
  339. }
  340. return S_OK;
  341. }
  342. STDAPI DllRegisterServer(void)
  343. {
  344. // REVIEW: should this be done only in DLLInstall?
  345. for (int i=0; i<ARRAYSIZE(g_rgExtentions); i++)
  346. {
  347. RegisterFileType(g_rgExtentions+i, FALSE);
  348. }
  349. RegisterHandler(c_rgszDocFileExts, ARRAYSIZE(c_rgszDocFileExts), IIDSTR_IExtractImage, CLSIDSTR_DocfileThumbnailHandler);
  350. UnregisterHandler(c_rgszHtmlExts, ARRAYSIZE(c_rgszHtmlExts), IIDSTR_IExtractImage, CLSIDSTR_HtmlThumbnailExtractor);
  351. _CallRegInstall("RegDll", TRUE);
  352. // powerpoint gets freaked by empty extension keys.
  353. _FixupProgid(".ppt", "Powerpoint.Show.7");
  354. _FixupProgid(".pot", "Powerpoint.Template");
  355. // registers object, typelib and all interfaces in typelib
  356. return _Module.RegisterServer(TRUE);
  357. }
  358. STDAPI DllUnregisterServer(void)
  359. {
  360. _Module.UnregisterServer();
  361. UnregisterHandler(c_rgszDocFileExts, ARRAYSIZE(c_rgszDocFileExts), IIDSTR_IExtractImage, CLSIDSTR_DocfileThumbnailHandler);
  362. UnregisterHandler(c_rgszHtmlExts, ARRAYSIZE(c_rgszHtmlExts), IIDSTR_IExtractImage, CLSIDSTR_HtmlThumbnailExtractor);
  363. _CallRegInstall("UnRegDll", TRUE);
  364. return S_OK;
  365. }
  366. STDAPI DllInstall(BOOL bInstall, LPCWSTR pszCmdLine)
  367. {
  368. if (bInstall)
  369. {
  370. BOOL fForce = StrStrIW(pszCmdLine, L"/FORCE") != 0;
  371. for (int i=0; i<ARRAYSIZE(g_rgExtentions); i++)
  372. {
  373. RegisterFileType(g_rgExtentions+i, fForce);
  374. }
  375. }
  376. return S_OK;
  377. }
  378. /////////////////////////////////////////////////////////////////////////////
  379. // DllRegisterServer - Adds entries to the system registry
  380. //
  381. // This array holds information needed for ClassFacory.
  382. // OLEMISC_ flags are used by shembed and shocx.
  383. //
  384. // PERF: this table should be ordered in most-to-least used order
  385. //
  386. #define OIF_ALLOWAGGREGATION 0x0001
  387. // constructor for CObjectInfo.
  388. CObjectInfo::CObjectInfo(CLSID const* pclsidin, LPFNCREATEOBJINSTANCE pfnCreatein, IID const* piidIn,
  389. IID const* piidEventsIn, long lVersionIn, DWORD dwOleMiscFlagsIn,
  390. DWORD dwClassFactFlagsIn)
  391. {
  392. pclsid = pclsidin;
  393. pfnCreateInstance = pfnCreatein;
  394. piid = piidIn;
  395. piidEvents = piidEventsIn;
  396. lVersion = lVersionIn;
  397. dwOleMiscFlags = dwOleMiscFlagsIn;
  398. dwClassFactFlags = dwClassFactFlagsIn;
  399. }
  400. // static class factory (no allocs!)
  401. STDMETHODIMP CClassFactory::QueryInterface(REFIID riid, void **ppvObj)
  402. {
  403. if (IsEqualIID(riid, IID_IClassFactory) || IsEqualIID(riid, IID_IUnknown))
  404. {
  405. *ppvObj = (void *)GET_ICLASSFACTORY(this);
  406. _Module.Lock();
  407. return S_OK;
  408. }
  409. *ppvObj = NULL;
  410. return E_NOINTERFACE;
  411. }
  412. STDMETHODIMP_(ULONG) CClassFactory::AddRef()
  413. {
  414. _Module.Lock();
  415. return 2;
  416. }
  417. STDMETHODIMP_(ULONG) CClassFactory::Release()
  418. {
  419. _Module.Unlock();
  420. return 1;
  421. }
  422. STDMETHODIMP CClassFactory::CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
  423. {
  424. *ppv = NULL;
  425. if (punkOuter && !IsEqualIID(riid, IID_IUnknown))
  426. {
  427. // It is technically illegal to aggregate an object and request
  428. // any interface other than IUnknown. Enforce this.
  429. //
  430. return CLASS_E_NOAGGREGATION;
  431. }
  432. else
  433. {
  434. LPOBJECTINFO pthisobj = (LPOBJECTINFO)this;
  435. if (punkOuter && !(pthisobj->dwClassFactFlags & OIF_ALLOWAGGREGATION))
  436. return CLASS_E_NOAGGREGATION;
  437. IUnknown *punk;
  438. HRESULT hres = pthisobj->pfnCreateInstance(punkOuter, &punk, pthisobj);
  439. if (SUCCEEDED(hres))
  440. {
  441. hres = punk->QueryInterface(riid, ppv);
  442. punk->Release();
  443. }
  444. return hres;
  445. }
  446. }
  447. STDMETHODIMP CClassFactory::LockServer(BOOL fLock)
  448. {
  449. if (fLock)
  450. _Module.Lock();
  451. else
  452. _Module.Unlock();
  453. return S_OK;
  454. }
  455. // Object constructor
  456. STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
  457. {
  458. // handle non-ATL objects first
  459. if (IsEqualIID(riid, IID_IClassFactory) || IsEqualIID(riid, IID_IUnknown))
  460. {
  461. for (LPCOBJECTINFO pcls = g_ObjectInfo; pcls->pclsid; pcls++)
  462. {
  463. if (IsEqualGUID(rclsid, *(pcls->pclsid)))
  464. {
  465. *ppv = (void*)pcls;
  466. _Module.Lock();
  467. return S_OK;
  468. }
  469. }
  470. }
  471. // Try the ATL way....
  472. return _Module.GetClassObject(rclsid, riid, ppv);
  473. }