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.

754 lines
15 KiB

  1. //____________________________________________________________________________
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1995 - 1996.
  5. //
  6. // File: psx.cxx
  7. //
  8. // Contents:
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 2/13/1996 RaviR Created
  15. //
  16. //____________________________________________________________________________
  17. #include "..\pch\headers.hxx"
  18. #pragma hdrstop
  19. #include "dbg.h"
  20. #include "macros.h"
  21. #include "resource.h"
  22. //#include "jobidl.hxx"
  23. #include "util.hxx"
  24. //
  25. // extern
  26. //
  27. extern HINSTANCE g_hInstance;
  28. #define HINST_THISDLL g_hInstance
  29. //
  30. // Local constants
  31. //
  32. TCHAR const FAR c_szNULL[] = TEXT("");
  33. TCHAR const FAR c_szStubWindowClass[] = TEXT("JobPropWnd");
  34. const size_t MAX_FILE_PROP_PAGES = 32;
  35. class CHkey
  36. {
  37. public:
  38. CHkey(void) : _h(NULL) {}
  39. CHkey(HKEY h) : _h(h) {}
  40. virtual ~CHkey() { if (_h != NULL) RegCloseKey(_h); }
  41. operator HKEY() { return _h; }
  42. HKEY * operator &() { return &_h; }
  43. HKEY Attach(HKEY h) { HKEY hTemp = _h; _h = h; return hTemp; }
  44. HKEY Detach(void) { HKEY hTemp = _h; _h = NULL; return hTemp; }
  45. void Close(void) { if (_h) RegCloseKey(_h); _h = NULL; }
  46. protected:
  47. HKEY _h;
  48. };
  49. /////////////////////////////////////////////////////////////////////////////
  50. //
  51. // Display properties
  52. //
  53. class CJFPropertyThreadData
  54. {
  55. public:
  56. static CJFPropertyThreadData * Create(LPDATAOBJECT pdtobj,
  57. LPTSTR pszCaption);
  58. ~CJFPropertyThreadData()
  59. {
  60. if (_pdtobj != NULL)
  61. {
  62. _pdtobj->Release();
  63. }
  64. delete _pszCaption;
  65. }
  66. LPDATAOBJECT GetDataObject() { return _pdtobj; }
  67. LPTSTR GetCaption() { return _pszCaption; }
  68. private:
  69. CJFPropertyThreadData() : _pdtobj(NULL), _pszCaption(NULL) {}
  70. LPDATAOBJECT _pdtobj;
  71. LPTSTR _pszCaption;
  72. };
  73. CJFPropertyThreadData *
  74. CJFPropertyThreadData::Create(
  75. LPDATAOBJECT pdtobj,
  76. LPTSTR pszCaption)
  77. {
  78. CJFPropertyThreadData * pData = new CJFPropertyThreadData;
  79. if (pData == NULL)
  80. {
  81. return NULL;
  82. }
  83. pData->_pszCaption = NewDupString(pszCaption);
  84. if (pData->_pszCaption == NULL)
  85. {
  86. delete pData;
  87. return NULL;
  88. }
  89. pData->_pdtobj = pdtobj;
  90. pData->_pdtobj->AddRef();
  91. return pData;
  92. }
  93. DWORD
  94. __stdcall
  95. JFPropertiesThread(
  96. LPVOID pvData)
  97. {
  98. CJFPropertyThreadData *pData = (CJFPropertyThreadData *)pvData;
  99. HRESULT hrOle = OleInitialize(NULL);
  100. __try
  101. {
  102. if (SUCCEEDED(hrOle))
  103. {
  104. JFOpenPropSheet(pData->GetDataObject(), pData->GetCaption());
  105. }
  106. }
  107. __finally
  108. {
  109. delete pData;
  110. if (SUCCEEDED(hrOle))
  111. {
  112. OleUninitialize();
  113. }
  114. ExitThread(0);
  115. }
  116. return 0;
  117. }
  118. //____________________________________________________________________________
  119. //
  120. // Member: CJobsCM::_DisplayJobProperties
  121. //
  122. // Arguments: [hwnd] -- IN
  123. // [pwszJob] -- IN
  124. //
  125. // Returns: HRESULT.
  126. //
  127. // History: 1/11/1996 RaviR Created
  128. //
  129. //____________________________________________________________________________
  130. HRESULT
  131. CJobsCM::_DisplayJobProperties(
  132. HWND hwnd,
  133. CJobID & jid)
  134. {
  135. TRACE_FUNCTION(DisplayJobProperties);
  136. Win4Assert(m_cidl == 1);
  137. HRESULT hr = S_OK;
  138. LPDATAOBJECT pdtobj = NULL;
  139. do
  140. {
  141. hr = JFGetDataObject(hwnd, m_pszFolderPath, m_cidl,
  142. (LPCITEMIDLIST *)m_apidl, (LPVOID *)&pdtobj);
  143. CHECK_HRESULT(hr);
  144. BREAK_ON_FAIL(hr);
  145. CJFPropertyThreadData * pData = NULL;
  146. TCHAR tcName[MAX_PATH];
  147. lstrcpy(tcName, ((PJOBID)m_apidl[0])->GetName());
  148. LPTSTR pszExt = PathFindExtension(tcName);
  149. if (pszExt)
  150. {
  151. *pszExt = TEXT('\0');
  152. }
  153. pData = CJFPropertyThreadData::Create(pdtobj, tcName);
  154. if (pData == NULL)
  155. {
  156. hr = E_OUTOFMEMORY;
  157. CHECK_HRESULT(hr);
  158. break;
  159. }
  160. HANDLE hThread;
  161. DWORD idThread;
  162. hThread = CreateThread(NULL, 0, JFPropertiesThread,
  163. pData, 0, &idThread);
  164. if (hThread)
  165. {
  166. CloseHandle(hThread);
  167. }
  168. else
  169. {
  170. delete pData;
  171. }
  172. } while (0);
  173. if (pdtobj != NULL)
  174. {
  175. pdtobj->Release();
  176. }
  177. return hr;
  178. }
  179. //-----------------------------------------------------------------------------
  180. //
  181. // PSXA
  182. //
  183. // An array of IShellPropSheetExt interface pointers
  184. //
  185. //-----------------------------------------------------------------------------
  186. struct PSXA
  187. {
  188. static PSXA * Alloc(UINT count);
  189. static void Delete(PSXA * pPsxa);
  190. UINT count;
  191. IShellPropSheetExt *intfc[1];
  192. };
  193. PSXA * PSXA::Alloc(UINT count)
  194. {
  195. UINT cb = sizeof(UINT) + sizeof(IShellPropSheetExt *) * count;
  196. PSXA * pPsxa = (PSXA *)new BYTE[cb];
  197. if (pPsxa != NULL)
  198. {
  199. ZeroMemory(pPsxa, cb);
  200. }
  201. return pPsxa;
  202. }
  203. void PSXA::Delete(PSXA * pPsxa)
  204. {
  205. while (pPsxa->count--)
  206. {
  207. if (pPsxa->intfc[pPsxa->count] != NULL)
  208. {
  209. pPsxa->intfc[pPsxa->count]->Release();
  210. }
  211. }
  212. delete [] ((LPBYTE)pPsxa);
  213. }
  214. HRESULT
  215. GetHkeyForJobObject(
  216. HKEY * phkey)
  217. {
  218. //
  219. // Get ProgID for .job files. Get an HKEY for this ProgID.
  220. //
  221. LRESULT lr = ERROR_SUCCESS;
  222. do
  223. {
  224. HKEY hkey = NULL;
  225. lr = RegOpenKeyEx(HKEY_CLASSES_ROOT, TSZ_DOTJOB, 0,
  226. KEY_QUERY_VALUE, &hkey);
  227. if (lr != ERROR_SUCCESS)
  228. {
  229. CHECK_LASTERROR(lr);
  230. break;
  231. }
  232. DWORD dwType = 0;
  233. TCHAR buff[200];
  234. ULONG cb = sizeof(buff);
  235. lr = RegQueryValueEx(hkey, NULL, NULL, &dwType, (LPBYTE)buff, &cb);
  236. RegCloseKey(hkey);
  237. if (lr != ERROR_SUCCESS)
  238. {
  239. CHECK_LASTERROR(lr);
  240. break;
  241. }
  242. hkey = NULL; // reset
  243. lr = RegOpenKeyEx(HKEY_CLASSES_ROOT, buff, 0, KEY_READ, &hkey);
  244. if (lr != ERROR_SUCCESS)
  245. {
  246. CHECK_LASTERROR(lr);
  247. break;
  248. }
  249. *phkey = hkey;
  250. } while (0);
  251. return HRESULT_FROM_WIN32(lr);
  252. }
  253. LPTSTR
  254. I_GetWord(
  255. LPTSTR psz)
  256. {
  257. static TCHAR * s_psz = NULL;
  258. if (psz != NULL)
  259. {
  260. s_psz = psz;
  261. }
  262. psz = s_psz;
  263. // skip the space or comma characters
  264. while (*psz == TEXT(' ') || *psz == TEXT(',')) { ++psz; }
  265. s_psz = psz;
  266. while (*s_psz != TEXT('\0'))
  267. {
  268. if (*s_psz == TEXT(' ') || *s_psz == TEXT(','))
  269. {
  270. *s_psz = TEXT('\0');
  271. ++s_psz;
  272. break;
  273. }
  274. ++s_psz;
  275. }
  276. return psz;
  277. }
  278. inline
  279. HRESULT
  280. I_CLSIDFromString(
  281. LPTSTR pszClsid,
  282. LPCLSID pclsid)
  283. {
  284. #ifdef UNICODE
  285. return CLSIDFromString(pszClsid, pclsid);
  286. #else
  287. WCHAR wBuff[64];
  288. HRESULT hr = AnsiToUnicode(wBuff, pszClsid, 64);
  289. if (FAILED(hr))
  290. {
  291. return hr;
  292. }
  293. return CLSIDFromString(wBuff, pclsid);
  294. #endif
  295. }
  296. inline
  297. BOOL
  298. I_IsPresent(
  299. CLSID aclsid[],
  300. UINT count)
  301. {
  302. for (UINT i=0; i < count; i++)
  303. {
  304. if (IsEqualCLSID(aclsid[i], aclsid[count]))
  305. {
  306. return TRUE;
  307. }
  308. }
  309. return FALSE;
  310. }
  311. HRESULT
  312. GetPropSheetExtArray(
  313. HKEY hkeyIn,
  314. PSXA ** ppPsxa)
  315. {
  316. *ppPsxa = NULL; // init
  317. //
  318. // From HKEY determine the clsids. Bind to each clsid
  319. // and get the IShellPropSheetExt interface ptrs.
  320. //
  321. HRESULT hr = S_OK;
  322. LRESULT lr = ERROR_SUCCESS;
  323. CHkey hkey;
  324. UINT count = 0;
  325. CLSID aclsid[20];
  326. TCHAR szClsid[64];
  327. ULONG SIZEOF_SZCLSID = sizeof(szClsid);
  328. do
  329. {
  330. TCHAR buff[MAX_PATH * 2];
  331. ULONG SIZEOF_BUFF = sizeof(buff);
  332. ULONG cb = SIZEOF_BUFF;
  333. lr = RegOpenKeyEx(hkeyIn, STRREG_SHEX_PROPSHEET, 0, KEY_READ, &hkey);
  334. BREAK_ON_ERROR(lr);
  335. lr = RegQueryValueEx(hkey, NULL, NULL, NULL, (LPBYTE)buff, &cb);
  336. CHECK_LASTERROR(lr);
  337. if (lr == ERROR_SUCCESS & cb > 0)
  338. {
  339. LPTSTR psz = I_GetWord(buff);
  340. CHkey hkeyTemp = NULL;
  341. while (*psz != TEXT('\0'))
  342. {
  343. hkeyTemp.Close();
  344. lr = RegOpenKeyEx(hkey, psz, 0, KEY_READ, &hkeyTemp);
  345. BREAK_ON_ERROR(lr);
  346. cb = SIZEOF_SZCLSID;
  347. lr = RegQueryValueEx(hkeyTemp, NULL, NULL, NULL,
  348. (LPBYTE)szClsid, &cb);
  349. BREAK_ON_ERROR(lr);
  350. hr = I_CLSIDFromString(szClsid, &aclsid[count]);
  351. BREAK_ON_FAIL(hr);
  352. ++count;
  353. psz = I_GetWord(NULL);
  354. }
  355. }
  356. for (int i=0; ; i++)
  357. {
  358. cb = SIZEOF_SZCLSID;
  359. lr = RegEnumKeyEx(hkey, i, szClsid, &cb,
  360. NULL, NULL, NULL, NULL);
  361. BREAK_ON_ERROR(lr);
  362. // Is it a classid?
  363. hr = I_CLSIDFromString(szClsid, &aclsid[count]);
  364. if (FAILED(hr)) // no - see if the value is a classid
  365. {
  366. CHkey hkey3;
  367. lr = RegOpenKeyEx(hkey, szClsid, 0, KEY_READ, &hkey3);
  368. if (lr == ERROR_SUCCESS)
  369. {
  370. cb = SIZEOF_SZCLSID;
  371. lr = RegQueryValueEx(hkey3, NULL, NULL, NULL,
  372. (LPBYTE)szClsid, &cb);
  373. if (lr == ERROR_SUCCESS)
  374. {
  375. hr = I_CLSIDFromString(szClsid, &aclsid[count]);
  376. }
  377. }
  378. }
  379. if (SUCCEEDED(hr))
  380. {
  381. // is it already present ?
  382. if (I_IsPresent(aclsid, count) == FALSE)
  383. {
  384. ++count;
  385. }
  386. }
  387. }
  388. } while (0);
  389. if (count <= 0)
  390. {
  391. DEBUG_OUT((DEB_USER1, "No pages to display.\n"));
  392. return E_FAIL;
  393. }
  394. do
  395. {
  396. //
  397. // Now create the IShellPropSheetExt interface ptrs.
  398. //
  399. PSXA * pPsxa = PSXA::Alloc(count);
  400. if (pPsxa == NULL)
  401. {
  402. hr = E_OUTOFMEMORY;
  403. CHECK_HRESULT(hr);
  404. break;
  405. }
  406. for (UINT k=0; k < count; k++)
  407. {
  408. hr = CoCreateInstance(aclsid[k], NULL, CLSCTX_ALL,
  409. IID_IShellPropSheetExt, (void **)&pPsxa->intfc[pPsxa->count]);
  410. CHECK_HRESULT(hr);
  411. if (SUCCEEDED(hr))
  412. {
  413. ++pPsxa->count;
  414. }
  415. }
  416. if (pPsxa->count > 0)
  417. {
  418. *ppPsxa = pPsxa;
  419. hr = S_OK;
  420. }
  421. else
  422. {
  423. hr = E_FAIL;
  424. }
  425. } while (0);
  426. return hr;
  427. }
  428. //
  429. // This function is a callback function from property sheet page extensions.
  430. //
  431. BOOL CALLBACK I_AddPropSheetPage(HPROPSHEETPAGE hpage, LPARAM lParam)
  432. {
  433. PROPSHEETHEADER * ppsh = (PROPSHEETHEADER *)lParam;
  434. if (ppsh->nPages < MAX_FILE_PROP_PAGES)
  435. {
  436. ppsh->phpage[ppsh->nPages++] = hpage;
  437. return TRUE;
  438. }
  439. return FALSE;
  440. }
  441. LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
  442. {
  443. switch(iMessage)
  444. {
  445. case WM_CREATE:
  446. break;
  447. case WM_DESTROY:
  448. break;
  449. case WM_NOTIFY:
  450. break;
  451. // case STUBM_SETDATA:
  452. // SetWindowLongPtr(hWnd, 0, wParam);
  453. // break;
  454. //
  455. // case STUBM_GETDATA:
  456. // return GetWindowLongPtr(hWnd, 0);
  457. default:
  458. return DefWindowProc(hWnd, iMessage, wParam, lParam) ;
  459. break;
  460. }
  461. return 0L;
  462. }
  463. HWND I_CreateStubWindow(void)
  464. {
  465. WNDCLASS wndclass;
  466. if (!GetClassInfo(HINST_THISDLL, c_szStubWindowClass, &wndclass))
  467. {
  468. wndclass.style = 0;
  469. wndclass.lpfnWndProc = WndProc;
  470. wndclass.cbClsExtra = 0;
  471. wndclass.cbWndExtra = 0;
  472. wndclass.hInstance = HINST_THISDLL;
  473. wndclass.hIcon = NULL;
  474. wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  475. wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  476. wndclass.lpszMenuName = NULL;
  477. wndclass.lpszClassName = c_szStubWindowClass;
  478. if (!RegisterClass(&wndclass))
  479. return NULL;
  480. }
  481. return CreateWindowEx(WS_EX_TOOLWINDOW, c_szStubWindowClass, c_szNULL,
  482. WS_OVERLAPPED, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0,
  483. NULL, NULL, HINST_THISDLL, NULL);
  484. }
  485. HRESULT
  486. JFOpenPropSheet(
  487. LPDATAOBJECT pdtobj,
  488. LPTSTR pszCaption)
  489. {
  490. HRESULT hr = S_OK;
  491. CHkey hkey;
  492. PSXA * pPsxa = NULL;
  493. PROPSHEETHEADER psh;
  494. HPROPSHEETPAGE ahpage[MAX_FILE_PROP_PAGES];
  495. do
  496. {
  497. //
  498. // Get HKEY for the .job class object
  499. //
  500. hr = GetHkeyForJobObject(&hkey);
  501. BREAK_ON_FAIL(hr);
  502. //
  503. // Get the IShellPropSheetExt interface ptrs for classes wishing to
  504. // add pages.
  505. //
  506. hr = GetPropSheetExtArray(hkey, &pPsxa);
  507. BREAK_ON_FAIL(hr);
  508. // For each IShellPropSheetExt interface ptr initialize(IShellExtInit)
  509. // and call the AddPages.
  510. psh.dwSize = sizeof(psh);
  511. psh.dwFlags = PSH_PROPTITLE;
  512. psh.hwndParent = I_CreateStubWindow();
  513. psh.hInstance = g_hInstance;
  514. psh.hIcon = NULL;
  515. psh.pszCaption = pszCaption;
  516. //psh.pszCaption = MAKEINTRESOURCE(IDS_JOB_PSH_CAPTION);
  517. psh.nPages = 0; // incremented in callback
  518. psh.nStartPage = 0;
  519. psh.phpage = ahpage;
  520. IShellExtInit * pShExtInit = NULL;
  521. for (UINT n=0; n < pPsxa->count; n++)
  522. {
  523. hr = pPsxa->intfc[n]->QueryInterface(IID_IShellExtInit,
  524. (void **)&pShExtInit);
  525. CHECK_HRESULT(hr);
  526. if (SUCCEEDED(hr))
  527. {
  528. hr = pShExtInit->Initialize(NULL, pdtobj, hkey);
  529. CHECK_HRESULT(hr);
  530. pShExtInit->Release();
  531. if (SUCCEEDED(hr))
  532. {
  533. hr = pPsxa->intfc[n]->AddPages(I_AddPropSheetPage,
  534. (LPARAM)&psh);
  535. CHECK_HRESULT(hr);
  536. }
  537. }
  538. }
  539. PSXA::Delete(pPsxa);
  540. // create a modeless property sheet.
  541. // Open the property sheet, only if we have some pages.
  542. if (psh.nPages > 0)
  543. {
  544. _try
  545. {
  546. hr = E_FAIL;
  547. if (PropertySheet(&psh) >= 0) // IDOK or IDCANCEL (< 0 is error)
  548. {
  549. hr = S_OK;
  550. }
  551. DEBUG_OUT((DEB_USER1, "PropertySheet returned.\n"));
  552. }
  553. _except(EXCEPTION_EXECUTE_HANDLER)
  554. {
  555. hr = E_FAIL;
  556. CHECK_HRESULT(hr);
  557. }
  558. }
  559. } while (0);
  560. if (psh.hwndParent)
  561. {
  562. DestroyWindow(psh.hwndParent);
  563. }
  564. return hr;
  565. }