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.

625 lines
17 KiB

  1. /*****************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORPORATION, 2000
  4. *
  5. * TITLE: dll.cpp
  6. *
  7. * VERSION: 1.0, stolen from netplwiz
  8. *
  9. * AUTHOR: RickTu
  10. *
  11. * DATE: 10/12/00
  12. *
  13. * DESCRIPTION: DLL main & class factory code
  14. *
  15. *****************************************************************************/
  16. #include "precomp.h"
  17. #pragma hdrstop
  18. // shell/lib files look for this instance variable
  19. HINSTANCE g_hInst = 0;
  20. LONG g_cLocks = 0;
  21. ATOM g_cPreviewClassWnd = 0;
  22. // guids for our stuff
  23. // some guids are in shguidp.lib. We need to move them out of the shell depot into printscan at some point
  24. const GUID IID_ISetWaitEventForTesting = {0xd61e2fe1, 0x4af8, 0x4dbd, {0xb8, 0xad, 0xe7, 0xe0, 0x7a, 0xdc, 0xf9, 0x0f}};
  25. // DLL lifetime stuff
  26. STDAPI_(BOOL) DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved)
  27. {
  28. switch (dwReason)
  29. {
  30. case DLL_PROCESS_ATTACH:
  31. g_hInst = hinstDLL;
  32. SHFusionInitializeFromModuleID( hinstDLL, 123 );
  33. WIA_DEBUG_CREATE(hinstDLL);
  34. WIA_TRACE((TEXT("DLL_PROCESS_ATTACH called on photowiz.dll")));
  35. CPreviewWindow::s_RegisterClass(hinstDLL);
  36. break;
  37. case DLL_PROCESS_DETACH:
  38. WIA_TRACE((TEXT("DLL_PROCESS_DETACH called on photowiz.dll")));
  39. if (g_cPreviewClassWnd)
  40. {
  41. UnregisterClass( (LPCTSTR)g_cPreviewClassWnd, hinstDLL );
  42. }
  43. SHFusionUninitialize();
  44. WIA_REPORT_LEAKS();
  45. WIA_DEBUG_DESTROY();
  46. break;
  47. case DLL_THREAD_ATTACH:
  48. // WIA_TRACE((TEXT("DLL_THREAD_ATTACH called on photowiz.dll")));
  49. break;
  50. case DLL_THREAD_DETACH:
  51. // WIA_TRACE((TEXT("DLL_THREAD_DETACH called on photowiz.dll")));
  52. break;
  53. }
  54. return TRUE;
  55. }
  56. STDAPI DllInstall(BOOL bInstall, LPCWSTR pszCmdLine)
  57. {
  58. return S_OK;
  59. }
  60. STDAPI DllCanUnloadNow()
  61. {
  62. HRESULT hr = (g_cLocks == 0) ? S_OK:S_FALSE;
  63. WIA_PUSH_FUNCTION_MASK((TRACE_REF_COUNTS, TEXT("DllCanUnloadNowRef, ref count is %d, hr = 0x%x"),g_cLocks,hr));
  64. WIA_RETURN_HR(hr);
  65. }
  66. STDAPI_(void) DllAddRef(void)
  67. {
  68. InterlockedIncrement(&g_cLocks);
  69. WIA_PUSH_FUNCTION_MASK((TRACE_REF_COUNTS, TEXT("DllAddRef, new ref count is %d"),g_cLocks));
  70. }
  71. STDAPI_(void) DllRelease(void)
  72. {
  73. InterlockedDecrement(&g_cLocks);
  74. WIA_PUSH_FUNCTION_MASK((TRACE_REF_COUNTS, TEXT("DllRelease, new ref count is %d"),g_cLocks));
  75. }
  76. /*****************************************************************************
  77. _CallRegInstall
  78. Helper function to allow us to invoke our .inf for installation...
  79. *****************************************************************************/
  80. HRESULT _CallRegInstall(LPCSTR szSection, BOOL bUninstall)
  81. {
  82. HRESULT hr = E_FAIL;
  83. HINSTANCE hinstAdvPack = NULL;
  84. //
  85. // Get system32 directory..
  86. //
  87. TCHAR szAdvPackPath[ MAX_PATH ];
  88. UINT uDirLen = lstrlen( TEXT("\\system32\\advpack.dll")+1 );
  89. UINT uRes;
  90. *szAdvPackPath = 0;
  91. uRes = GetSystemWindowsDirectory( szAdvPackPath, MAX_PATH - uDirLen );
  92. if (uRes && (uRes <= (MAX_PATH-uDirLen)))
  93. {
  94. lstrcat( szAdvPackPath, TEXT("\\system32\\advpack.dll") );
  95. hinstAdvPack = LoadLibrary( szAdvPackPath );
  96. }
  97. if (hinstAdvPack)
  98. {
  99. REGINSTALL pfnri = (REGINSTALL)GetProcAddress(hinstAdvPack, "RegInstall");
  100. if (pfnri)
  101. {
  102. STRENTRY seReg[] = {
  103. { "25", "%SystemRoot%" },
  104. { "11", "%SystemRoot%\\system32" },
  105. };
  106. STRTABLE stReg = { ARRAYSIZE(seReg), seReg };
  107. hr = pfnri(g_hInst, szSection, &stReg);
  108. if (bUninstall)
  109. {
  110. // ADVPACK will return E_UNEXPECTED if you try to uninstall
  111. // (which does a registry restore) on an INF section that was
  112. // never installed. We uninstall sections that may never have
  113. // been installed, so ignore this error
  114. hr = ((E_UNEXPECTED == hr) ? S_OK : hr);
  115. }
  116. }
  117. FreeLibrary(hinstAdvPack);
  118. }
  119. return hr;
  120. }
  121. STDAPI DllRegisterServer()
  122. {
  123. _CallRegInstall("UnregDll", TRUE);
  124. return _CallRegInstall("RegDll", FALSE);
  125. }
  126. STDAPI DllUnregisterServer()
  127. {
  128. return _CallRegInstall("UnregDll", TRUE);
  129. }
  130. HMODULE GetThreadHMODULE( LPTHREAD_START_ROUTINE pfnThreadProc )
  131. {
  132. MEMORY_BASIC_INFORMATION mbi;
  133. if (VirtualQuery(pfnThreadProc, &mbi, sizeof(mbi)))
  134. {
  135. TCHAR szModule[MAX_PATH];
  136. if (GetModuleFileName((HMODULE)mbi.AllocationBase, szModule, ARRAYSIZE(szModule)))
  137. {
  138. return LoadLibrary(szModule);
  139. }
  140. }
  141. return NULL;
  142. }
  143. STDAPI PPWCoInitialize(void)
  144. {
  145. HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
  146. if (FAILED(hr))
  147. {
  148. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
  149. }
  150. return hr;
  151. }
  152. /*****************************************************************************
  153. ClassFactory code
  154. <Notes>
  155. *****************************************************************************/
  156. //
  157. // This array holds information needed for ClassFacory.
  158. // OLEMISC_ flags are used by shembed and shocx.
  159. //
  160. // PERF: this table should be ordered in most-to-least used order
  161. //
  162. #define OIF_ALLOWAGGREGATION 0x0001
  163. CF_TABLE_BEGIN(g_ObjectInfo)
  164. CF_TABLE_ENTRY( &CLSID_PrintPhotosDropTarget, CPrintPhotosDropTarget_CreateInstance, COCREATEONLY),
  165. CF_TABLE_ENTRY( &CLSID_PrintPhotosWizard, CPrintPhotosWizard_CreateInstance, COCREATEONLY),
  166. CF_TABLE_END(g_ObjectInfo)
  167. // constructor for CObjectInfo.
  168. CObjectInfo::CObjectInfo(CLSID const* pclsidin, LPFNCREATEOBJINSTANCE pfnCreatein, IID const* piidIn,
  169. IID const* piidEventsIn, long lVersionIn, DWORD dwOleMiscFlagsIn,
  170. DWORD dwClassFactFlagsIn)
  171. {
  172. pclsid = pclsidin;
  173. pfnCreateInstance = pfnCreatein;
  174. piid = piidIn;
  175. piidEvents = piidEventsIn;
  176. lVersion = lVersionIn;
  177. dwOleMiscFlags = dwOleMiscFlagsIn;
  178. dwClassFactFlags = dwClassFactFlagsIn;
  179. }
  180. // static class factory (no allocs!)
  181. STDMETHODIMP CClassFactory::QueryInterface(REFIID riid, void **ppvObj)
  182. {
  183. WIA_PUSH_FUNCTION_MASK((TRACE_CF, TEXT("CClassFactory::QueryInterface")));
  184. if (IsEqualIID(riid, IID_IClassFactory) || IsEqualIID(riid, IID_IUnknown))
  185. {
  186. *ppvObj = (void *)GET_ICLASSFACTORY(this);
  187. DllAddRef();
  188. WIA_TRACE((TEXT("returning our class factory & S_OK")));
  189. return NOERROR;
  190. }
  191. *ppvObj = NULL;
  192. WIA_ERROR((TEXT("returning E_NOINTERFACE")));
  193. return E_NOINTERFACE;
  194. }
  195. STDMETHODIMP_(ULONG) CClassFactory::AddRef()
  196. {
  197. WIA_PUSH_FUNCTION_MASK((TRACE_CF, TEXT("CClassFactory::AddRef")));
  198. DllAddRef();
  199. return 2;
  200. }
  201. STDMETHODIMP_(ULONG) CClassFactory::Release()
  202. {
  203. WIA_PUSH_FUNCTION_MASK((TRACE_CF, TEXT("CClassFactory::Release")));
  204. DllRelease();
  205. return 1;
  206. }
  207. STDMETHODIMP CClassFactory::CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
  208. {
  209. WIA_PUSH_FUNCTION_MASK((TRACE_CF, TEXT("CClassFactory::CreateInstance")));
  210. *ppv = NULL;
  211. if (punkOuter && !IsEqualIID(riid, IID_IUnknown))
  212. {
  213. // It is technically illegal to aggregate an object and request
  214. // any interface other than IUnknown. Enforce this.
  215. //
  216. WIA_ERROR((TEXT("we don't support aggregation, returning CLASS_E_NOAGGREGATION")));
  217. return CLASS_E_NOAGGREGATION;
  218. }
  219. else
  220. {
  221. LPOBJECTINFO pthisobj = (LPOBJECTINFO)this;
  222. if (punkOuter && !(pthisobj->dwClassFactFlags & OIF_ALLOWAGGREGATION))
  223. {
  224. WIA_ERROR((TEXT("we don't support aggregation, returning CLASS_E_NOAGGREGATION")));
  225. return CLASS_E_NOAGGREGATION;
  226. }
  227. IUnknown *punk;
  228. HRESULT hres = pthisobj->pfnCreateInstance(punkOuter, &punk, pthisobj);
  229. if (SUCCEEDED(hres))
  230. {
  231. hres = punk->QueryInterface(riid, ppv);
  232. punk->Release();
  233. }
  234. //_ASSERT(FAILED(hres) ? *ppv == NULL : TRUE);
  235. WIA_RETURN_HR(hres);
  236. }
  237. }
  238. STDMETHODIMP CClassFactory::LockServer(BOOL fLock)
  239. {
  240. WIA_PUSH_FUNCTION_MASK((TRACE_CF, TEXT("CClassFactory::LockServer")));
  241. if (fLock)
  242. DllAddRef();
  243. else
  244. DllRelease();
  245. return S_OK;
  246. }
  247. STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
  248. {
  249. WIA_PUSH_FUNCTION_MASK((TRACE_CF, TEXT("DllGetClassObject")));
  250. HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
  251. *ppv = NULL;
  252. if (IsEqualIID(riid, IID_IClassFactory) || IsEqualIID(riid, IID_IUnknown))
  253. {
  254. for (LPCOBJECTINFO pcls = g_ObjectInfo; pcls->pclsid; pcls++)
  255. {
  256. if (IsEqualGUID(rclsid, *(pcls->pclsid)))
  257. {
  258. *ppv = (void*)pcls;
  259. DllAddRef(); // class factory holds DLL ref count
  260. hr = S_OK;
  261. }
  262. }
  263. }
  264. #ifdef ATL_ENABLED
  265. if (hr == CLASS_E_CLASSNOTAVAILABLE)
  266. hr = AtlGetClassObject(rclsid, riid, ppv);
  267. #endif
  268. WIA_RETURN_HR(hr);
  269. }
  270. STDMETHODIMP UsePPWForPrintTo( LPCMINVOKECOMMANDINFO pCMI, IDataObject * pdo )
  271. {
  272. WIA_PUSH_FUNCTION_MASK((TRACE_PRINTTO, TEXT("UsePPWForPrintTo")));
  273. HRESULT hr = E_INVALIDARG;
  274. CSimpleString strPrinterName;
  275. if (pCMI &&
  276. ((pCMI->cbSize == sizeof(CMINVOKECOMMANDINFO)) || (pCMI->cbSize == sizeof(CMINVOKECOMMANDINFOEX))) &&
  277. pdo)
  278. {
  279. //
  280. // Keep a reference on the data object while we do our thing...
  281. //
  282. pdo->AddRef();
  283. //
  284. // Get printer to use...
  285. //
  286. if ( (pCMI->cbSize == sizeof(CMINVOKECOMMANDINFO)) ||
  287. (pCMI->cbSize == sizeof(CMINVOKECOMMANDINFOEX) && (!(pCMI->fMask & CMIC_MASK_UNICODE)))
  288. )
  289. {
  290. //
  291. // printer name is first token on the line, but it might be quoted...
  292. //
  293. CHAR szPrinterName[ MAX_PATH ];
  294. LPCSTR p = pCMI->lpParameters;
  295. INT i = 0;
  296. if (p)
  297. {
  298. //
  299. // skip beginning "'s, if any
  300. //
  301. while (*p && (*p == '\"'))
  302. {
  303. p++;
  304. }
  305. //
  306. // Copy first param, which would be printer name...
  307. //
  308. while ( *p && (*p != '\"'))
  309. {
  310. szPrinterName[i++] = *p;
  311. p++;
  312. }
  313. szPrinterName[i] = 0;
  314. }
  315. //
  316. // Convert into CSimpleString...
  317. strPrinterName.Assign(CSimpleStringConvert::NaturalString(CSimpleStringAnsi(szPrinterName)));
  318. }
  319. else if ((pCMI->cbSize == sizeof(CMINVOKECOMMANDINFOEX)) && (pCMI->fMask & CMIC_MASK_UNICODE))
  320. {
  321. LPCMINVOKECOMMANDINFOEX pCMIEX = (LPCMINVOKECOMMANDINFOEX) pCMI;
  322. WCHAR szwPrinterName[ MAX_PATH ];
  323. LPCWSTR p = pCMIEX->lpParametersW;
  324. INT i = 0;
  325. if (p)
  326. {
  327. //
  328. // skip beginning "'s, if any
  329. //
  330. while (*p && (*p == L'\"'))
  331. {
  332. p++;
  333. }
  334. //
  335. // Copy first param, which would be printer name...
  336. //
  337. while ( *p && (*p != L'\"'))
  338. {
  339. szwPrinterName[i++] = *p;
  340. p++;
  341. }
  342. szwPrinterName[i] = 0;
  343. }
  344. //
  345. // Convert into CSimpleString...
  346. strPrinterName.Assign(CSimpleStringConvert::NaturalString(CSimpleStringWide(szwPrinterName)));
  347. }
  348. WIA_TRACE((TEXT("UsePPWForPrintTo - printer name to use is [%s]"),strPrinterName.String()));
  349. //
  350. // Create wizard object in UI less mode...
  351. //
  352. CWizardInfoBlob * pWizInfo = new CWizardInfoBlob( pdo, FALSE, TRUE );
  353. if (pWizInfo)
  354. {
  355. //
  356. // create full page print template...
  357. //
  358. WIA_TRACE((TEXT("UsePPWForPrintTo - constructing full page template")));
  359. pWizInfo->ConstructPrintToTemplate();
  360. //
  361. // Get a list of items...
  362. //
  363. WIA_TRACE((TEXT("UsePPWForPrintTo - adding items to print to pWizInfo")));
  364. pWizInfo->AddAllPhotosFromDataObject();
  365. //
  366. // Mark all items as selected for printing...
  367. //
  368. LONG nItemCount = pWizInfo->CountOfPhotos(FALSE);
  369. WIA_TRACE((TEXT("UsePPWForPrintTo - there are %d photos to be marked for printing"),nItemCount));
  370. //
  371. // Loop through all the photos and add them...
  372. //
  373. CListItem * pItem = NULL;
  374. for (INT i=0; i < nItemCount; i++)
  375. {
  376. //
  377. // Get the item in question
  378. //
  379. pItem = pWizInfo->GetListItem(i,FALSE);
  380. if (pItem)
  381. {
  382. pItem->SetSelectionState(TRUE);
  383. }
  384. }
  385. //
  386. // Set up for printing...
  387. //
  388. pWizInfo->SetPrinterToUse( strPrinterName.String() );
  389. HANDLE hPrinter = NULL;
  390. if (OpenPrinter( (LPTSTR)strPrinterName.String(), &hPrinter, NULL ) && hPrinter)
  391. {
  392. LONG lSize = DocumentProperties( NULL, hPrinter, (LPTSTR)strPrinterName.String(), NULL, NULL, 0 );
  393. if (lSize)
  394. {
  395. DEVMODE * pDevMode = (DEVMODE *) new BYTE[ lSize ];
  396. if (pDevMode)
  397. {
  398. if (IDOK == DocumentProperties( NULL, hPrinter, (LPTSTR)strPrinterName.String(), NULL, pDevMode, DM_OUT_BUFFER ))
  399. {
  400. WIA_TRACE((TEXT("UsePPWForPrintTo - setting devmode to use")));
  401. pWizInfo->SetDevModeToUse( pDevMode );
  402. }
  403. delete [] pDevMode;
  404. }
  405. }
  406. }
  407. if (hPrinter)
  408. {
  409. ClosePrinter(hPrinter);
  410. }
  411. //
  412. // Create HDC for the printer...
  413. //
  414. HDC hDC = CreateDC( TEXT("WINSPOOL"), pWizInfo->GetPrinterToUse(), NULL, pWizInfo->GetDevModeToUse() );
  415. if (hDC)
  416. {
  417. DOCINFO di = {0};
  418. di.cbSize = sizeof(DOCINFO);
  419. //
  420. // turn on ICM for this hDC
  421. //
  422. WIA_TRACE((TEXT("UsePPWForPrintTo - setting ICM mode on for hDC")));
  423. SetICMMode( hDC, ICM_ON );
  424. //
  425. // Lets use the template name for the document name...
  426. //
  427. CSimpleString strTitle;
  428. CTemplateInfo * pTemplateInfo = NULL;
  429. if (SUCCEEDED(pWizInfo->GetTemplateByIndex( 0 ,&pTemplateInfo)) && pTemplateInfo)
  430. {
  431. pTemplateInfo->GetTitle( &strTitle );
  432. }
  433. //
  434. // Let's remove the ':' at the end if there is one
  435. //
  436. INT iLen = strTitle.Length();
  437. if (iLen && (strTitle[(INT)iLen-1] == TEXT(':')))
  438. {
  439. strTitle.Truncate(iLen);
  440. }
  441. di.lpszDocName = strTitle;
  442. WIA_TRACE((TEXT("UsePPWForPrintTo - calling StartDoc")));
  443. if (StartDoc( hDC, &di ) > 0)
  444. {
  445. //
  446. // Loop through until we've printed all the photos...
  447. //
  448. INT iPageCount = 0;
  449. if (SUCCEEDED(hr = pWizInfo->GetCountOfPrintedPages( 0, &iPageCount )))
  450. {
  451. WIA_TRACE((TEXT("UsePPWForPrintTo - iPageCount is %d"),iPageCount));
  452. for (INT iPage = 0; iPage < iPageCount; iPage++)
  453. {
  454. //
  455. // Print the page...
  456. //
  457. if (StartPage( hDC ) > 0)
  458. {
  459. WIA_TRACE((TEXT("UsePPWForPrintTo - printing page %d"),iPage));
  460. hr = pWizInfo->RenderPrintedPage( 0, iPage, hDC, NULL, (float)0.0, NULL );
  461. EndPage( hDC );
  462. }
  463. else
  464. {
  465. WIA_ERROR((TEXT("UsePPWForPrintTo - StartPage failed w/GLE = %d"),GetLastError()));
  466. }
  467. }
  468. }
  469. WIA_TRACE((TEXT("UsePPWForPrintTo - calling EndDoc")));
  470. EndDoc( hDC );
  471. }
  472. DeleteDC( hDC );
  473. }
  474. delete pWizInfo;
  475. }
  476. pdo->Release();
  477. }
  478. WIA_RETURN_HR(hr);
  479. }