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.

1803 lines
55 KiB

  1. // ChainWiz.cpp : Implementation of CChainWiz
  2. #include "stdafx.h"
  3. #include "WizChain.h"
  4. #include "ChainWiz.h"
  5. #include "propsht.h"
  6. #include <commctrl.h>
  7. #include <shellapi.h>
  8. #include <htmlhelp.h>
  9. #include "txttohtm.h"
  10. #include "createtempfile.h"
  11. // From sdnt\shell\comctl32\v6\rcids.h
  12. #define IDD_NEXT 0x3024
  13. // helper(s)
  14. static LPDLGTEMPLATE GetDialogTemplate( HINSTANCE hinst, LPCWSTR wszResource )
  15. {
  16. HRSRC hrsrc = FindResourceW( hinst, wszResource, (LPCWSTR)RT_DIALOG );
  17. if (hrsrc)
  18. {
  19. HGLOBAL hg = LoadResource( hinst, hrsrc );
  20. if( hg )
  21. {
  22. return (LPDLGTEMPLATE)LockResource( hg );
  23. }
  24. }
  25. return NULL;
  26. }
  27. static LPCWSTR DupStringResource( HINSTANCE hinst, LPCWSTR wszResource )
  28. {
  29. if ( NULL == wszResource )
  30. return NULL;
  31. LONG_PTR lid = (LONG_PTR)wszResource;
  32. // first, try a static 256 wchar buffer....
  33. WCHAR wszBuffer[256];
  34. int iLen = LoadStringW( hinst, (UINT)lid, wszBuffer, 256 );
  35. if( iLen <= 0 )
  36. {
  37. // resource not found: should be a string....
  38. if ( IsBadStringPtrW( wszResource, 16384 ))
  39. {
  40. return NULL; // resource not found, and can't read memory
  41. }
  42. return _wcsdup( wszResource );
  43. }
  44. if( iLen < 256 )
  45. {
  46. return _wcsdup( wszBuffer );
  47. }
  48. // else alloc a bigger and bigger buffer until it all fits, then dup
  49. for( int i = 512; i < 16384; i += 256)
  50. {
  51. WCHAR* pw = (WCHAR*)malloc( i * sizeof(WCHAR) );
  52. if( !pw )
  53. {
  54. break; // yikes!
  55. }
  56. else
  57. {
  58. iLen = LoadStringW( hinst, (UINT)lid, pw, i );
  59. if( iLen < i )
  60. {
  61. WCHAR* pwResult = _wcsdup( pw );
  62. free( pw );
  63. return pwResult;
  64. }
  65. free( pw );
  66. }
  67. }
  68. return NULL;
  69. }
  70. void FreeStringResources( PROPSHEETPAGEW* psp )
  71. {
  72. if( psp->pszTitle )
  73. {
  74. free( (void*)psp->pszTitle );
  75. }
  76. if( psp->pszHeaderTitle )
  77. {
  78. free( (void*)psp->pszHeaderTitle );
  79. }
  80. if( psp->pszHeaderSubTitle )
  81. {
  82. free( (void*)psp->pszHeaderSubTitle );
  83. }
  84. }
  85. // thunking stuff
  86. struct CThunkData
  87. {
  88. public:
  89. void* m_sig; // signature (pointer back to self)
  90. CChainWiz* m_pCW;
  91. PROPSHEETPAGEW* m_theirPSP;
  92. WNDPROC m_theirWndProc;
  93. IAddPropertySheets* m_pAPSs; // not AddRef'd
  94. CThunkData( CChainWiz* pCW, PROPSHEETPAGEW* theirPSP, WNDPROC WndProc, IAddPropertySheets* pAPSs )
  95. {
  96. m_sig = (void*)this;
  97. m_theirWndProc = WndProc;
  98. m_pCW = pCW; // need one of these inside my thunking layers
  99. m_pAPSs = pAPSs; // not AddRef'd
  100. // their stuff (variable size!!!)
  101. BYTE* temp = new BYTE[theirPSP->dwSize];
  102. m_theirPSP = (PROPSHEETPAGEW*)temp;
  103. if( temp )
  104. {
  105. MoveMemory( temp, theirPSP, theirPSP->dwSize );
  106. }
  107. }
  108. ~CThunkData( )
  109. {
  110. delete [] (BYTE*)m_theirPSP;
  111. }
  112. };
  113. UINT CALLBACK ChainCallback( HWND hWnd, UINT uMsg, LPPROPSHEETPAGE ppsp )
  114. {
  115. if( !ppsp ) return 0;
  116. // get my data
  117. CThunkData* pTD = (CThunkData*)ppsp->lParam;
  118. if( !pTD ) return 0;
  119. if( pTD->m_theirPSP &&
  120. (pTD->m_theirPSP->dwFlags & PSP_USECALLBACK) &&
  121. (pTD->m_theirPSP->pfnCallback != NULL) )
  122. {
  123. // swap their data and my data
  124. CThunkData td( NULL, ppsp, NULL, NULL );
  125. MoveMemory( ppsp, pTD->m_theirPSP, ppsp->dwSize );
  126. // call their callback
  127. ppsp->pfnCallback( hWnd, uMsg, ppsp );
  128. // change everything back
  129. MoveMemory( ppsp, td.m_theirPSP, ppsp->dwSize );
  130. }
  131. if( uMsg == PSPCB_RELEASE )
  132. {
  133. delete pTD; // delete my thunk data
  134. ppsp->lParam = NULL;
  135. }
  136. return 1;
  137. }
  138. INT_PTR CALLBACK ChainSubclassProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
  139. {
  140. CThunkData* pTD = (CThunkData*)GetPropW( hwndDlg, L"IWizChain" );
  141. if( !pTD || (pTD->m_sig != (void*)pTD) )
  142. {
  143. return FALSE; // this is bad....
  144. }
  145. // special thunking for PSN_WIZBACK, PSN_WIZNEXT
  146. if( uMsg == WM_NOTIFY )
  147. {
  148. NMHDR* pNMHDR = (NMHDR*)lParam;
  149. if( pNMHDR->code == PSN_SETACTIVE )
  150. {
  151. CChainWiz* pCW = pTD->m_pCW;
  152. assert( pCW != NULL );
  153. CPropertyPagePropertyBag* pCPPPBag = pCW->GetPPPBag( );
  154. assert( pCPPPBag != NULL );
  155. IAddPropertySheets* pThisAPSs = pTD->m_pAPSs;
  156. if( pThisAPSs != pCW->GetCurrentComponent( ) )
  157. {
  158. // crossed component boundary:
  159. pCW->SetPreviousComponent( pCW->GetCurrentComponent( ) );
  160. pCW->SetCurrentComponent( pThisAPSs );
  161. IAddPropertySheets* pLastAPSs = pCW->GetPreviousComponent( );
  162. // let previous guy write
  163. if( pLastAPSs )
  164. {
  165. pCPPPBag->SetReadOnly( FALSE );
  166. pCPPPBag->SetOwner( (DWORD)(LONG_PTR)pLastAPSs );
  167. IPropertyPagePropertyBag* pOPPPBag = COwnerPPPBag::Create( pCPPPBag, (DWORD)(LONG_PTR)pLastAPSs );
  168. if( pOPPPBag )
  169. {
  170. pLastAPSs->WriteProperties( pOPPPBag );
  171. pOPPPBag->Release( );
  172. }
  173. }
  174. // let current guy read
  175. if( pThisAPSs )
  176. {
  177. pCPPPBag->SetReadOnly( TRUE );
  178. pCPPPBag->SetOwner( PPPBAG_SYSTEM_OWNER );
  179. IPropertyPagePropertyBag* pOPPPBag = COwnerPPPBag::Create( pCPPPBag, (DWORD)(LONG_PTR)pThisAPSs );
  180. if( pOPPPBag )
  181. {
  182. pThisAPSs->ReadProperties( pOPPPBag );
  183. pOPPPBag->Release( );
  184. }
  185. }
  186. }
  187. }
  188. else if( (pNMHDR->code == PSN_WIZBACK) || (pNMHDR->code == PSN_WIZNEXT) )
  189. {
  190. // MFC hack:
  191. // they don't set the DWL_MSGRESULT like they're supposed to!
  192. // instead, they just return the IDD
  193. // so, I'm gonna put a bogus value up there and check for it
  194. const LONG BOGUS_IDD = -10L;
  195. SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, (LONG_PTR)BOGUS_IDD );
  196. // fixup IDDs from PSN_WIZBACK, PSN_WIZNEXT
  197. LPARAM lparamTemp = CallWindowProc( pTD->m_theirWndProc, hwndDlg, uMsg, wParam, lParam );
  198. // get IDDs (maybe)
  199. LONG_PTR idd = GetWindowLongPtr( hwndDlg, DWLP_MSGRESULT );
  200. if( idd == BOGUS_IDD )
  201. {
  202. idd = lparamTemp; // MFC hack: see above.
  203. SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, idd );
  204. }
  205. // translate as necessary.
  206. switch (idd)
  207. {
  208. case 0:
  209. case -1:
  210. {
  211. break;
  212. }
  213. default:
  214. {
  215. // try to map idd to LPCDLGTEMPLATE
  216. // if it fails, it must have been a LPCDLGTEMPLATE already
  217. if( pTD->m_theirPSP )
  218. {
  219. LPDLGTEMPLATE lpdt = GetDialogTemplate( pTD->m_theirPSP->hInstance, (LPCWSTR)idd );
  220. if( lpdt )
  221. {
  222. LPDLGTEMPLATE lpdt2 = pTD->m_pCW->GetAtlTemplate( lpdt );
  223. if( lpdt2 )
  224. {
  225. SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, (LONG_PTR)lpdt2 );
  226. return (LPARAM)lpdt2;
  227. }
  228. else
  229. {
  230. SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, (LONG_PTR)lpdt );
  231. return (LPARAM)lpdt;
  232. }
  233. }
  234. }
  235. break;
  236. }
  237. }
  238. return lparamTemp;
  239. }
  240. else if( pNMHDR->code == PSN_QUERYCANCEL )
  241. {
  242. CChainWiz* pCW = pTD->m_pCW;
  243. WCHAR wsz[2048];
  244. ::LoadStringW( (HINSTANCE)_Module.GetModuleInstance(), IDS_QUERYCANCEL, wsz, 2048 );
  245. return (IDYES != ::MessageBoxW( hwndDlg, wsz, (LPOLESTR)pCW->GetTitle (), MB_YESNO | MB_ICONWARNING ));
  246. }
  247. }
  248. return CallWindowProc( pTD->m_theirWndProc, hwndDlg, uMsg, wParam, lParam );
  249. }
  250. static LOGFONT g_lf;
  251. static LPARAM g_lp;
  252. INT_PTR CALLBACK ChainDlgProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
  253. {
  254. /*
  255. the first time we ever get into this function and have my CThunkData
  256. (this will be after the WM_SETFONT message, during WM_INITDIALOG),
  257. 1. subclass dlg hwnd
  258. 2. hang my stuff off window prop
  259. 3. setup for atl hook discarding test
  260. 4. call their dlgproc
  261. Do thunking and PPPBag IO inside subclass function
  262. */
  263. if( uMsg == WM_SETFONT )
  264. {
  265. // hang onto this so I can send it before WM_INITDIALOG
  266. HFONT hf = (HFONT)wParam;
  267. GetObject( (HGDIOBJ)hf, sizeof(g_lf), (void*)&g_lf );
  268. g_lp = lParam;
  269. return FALSE;
  270. }
  271. if( uMsg == WM_INITDIALOG )
  272. {
  273. // get my thunking data
  274. PROPSHEETPAGEW* psp = (PROPSHEETPAGEW*)lParam;
  275. CThunkData* pTD = (CThunkData*)psp->lParam;
  276. if( pTD && pTD->m_theirPSP )
  277. {
  278. // 1. subclass dlg hwnd
  279. pTD->m_theirWndProc = (WNDPROC)SetWindowLongPtr( hwndDlg, GWLP_WNDPROC, (LONG_PTR)ChainSubclassProc );
  280. // 2. hang my stuff off window prop
  281. SetPropW( hwndDlg, L"IWizChain", (HANDLE)pTD );
  282. // 3. see 5. below
  283. DLGPROC dlgproc = (DLGPROC)GetWindowLongPtr( hwndDlg, DWLP_DLGPROC );
  284. // 4. call their dlgproc
  285. // first send 'em WM_SETFONT (see above)
  286. HFONT hf = CreateFontIndirect( &g_lf );
  287. if( hf )
  288. {
  289. pTD->m_theirPSP->pfnDlgProc( hwndDlg, WM_SETFONT, (WPARAM)hf, g_lp );
  290. DeleteObject( (HGDIOBJ)hf ); // should I delete this later? or now?
  291. }
  292. // 5.
  293. // atl has this great feature where they blindly subclass the hwndDlg
  294. // and throw the rest of 'em away.
  295. // I can detect this...
  296. if( dlgproc != (DLGPROC)GetWindowLongPtr( hwndDlg, DWLP_DLGPROC ) )
  297. {
  298. // re-subclass
  299. pTD->m_theirPSP->pfnDlgProc = (DLGPROC)SetWindowLongPtr( hwndDlg, DWLP_DLGPROC, (LONG_PTR)ChainDlgProc );
  300. }
  301. // then send 'em the WM_INITDIALOG
  302. return pTD->m_theirPSP->pfnDlgProc( hwndDlg, uMsg, wParam, (LPARAM)pTD->m_theirPSP );
  303. }
  304. else
  305. {
  306. return FALSE;
  307. }
  308. }
  309. CThunkData* pTD = (CThunkData*)GetPropW( hwndDlg, L"IWizChain" );
  310. if( !pTD || (pTD->m_sig != (void*)pTD) || !pTD->m_theirPSP )
  311. {
  312. return FALSE;
  313. }
  314. return pTD->m_theirPSP->pfnDlgProc( hwndDlg, uMsg, wParam, lParam );
  315. }
  316. static void ModifyStyleEx( HWND hwnd, DWORD dwRemove, DWORD dwAdd, UINT nFlags )
  317. {
  318. // cloned from atl
  319. DWORD dwStyle = ::GetWindowLongPtr( hwnd, GWL_EXSTYLE );
  320. DWORD dwNewStyle = (dwStyle & ~dwRemove) | dwAdd;
  321. if( dwStyle == dwNewStyle )
  322. {
  323. return;
  324. }
  325. ::SetWindowLongPtr( hwnd, GWL_EXSTYLE, (LONG_PTR)dwNewStyle );
  326. ::SetWindowPos ( hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | nFlags );
  327. }
  328. static void ShowBorder( HWND hwnd, BOOL bBorder )
  329. {
  330. if( bBorder )
  331. {
  332. ModifyStyleEx( hwnd, 0, WS_EX_CLIENTEDGE, SWP_FRAMECHANGED );
  333. }
  334. else
  335. {
  336. ModifyStyleEx( hwnd, WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED );
  337. }
  338. }
  339. BOOL IsComctrlVersion6orGreater( )
  340. {
  341. BOOL bVersion6 = FALSE;
  342. INITCOMMONCONTROLSEX init;
  343. ZeroMemory( &init, sizeof(init) );
  344. init.dwSize = sizeof(init);
  345. init.dwICC = ICC_LINK_CLASS; // This is the SysLink control in v6
  346. if( InitCommonControlsEx( &init ) )
  347. {
  348. bVersion6 = TRUE;
  349. }
  350. else
  351. {
  352. bVersion6 = FALSE;
  353. }
  354. return bVersion6;
  355. }
  356. INT_PTR CALLBACK FinishDlgProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
  357. {
  358. // Note that this function is not calling DefWindowProc at the end.
  359. // Respect that otherwise things can be screwed up.
  360. CChainWiz* pCW = (CChainWiz*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA );
  361. switch( uMsg )
  362. {
  363. case WM_CLOSE:
  364. {
  365. // This will cover us when the focus is in the edit control and the user hits esc
  366. if( ::GetFocus() == GetDlgItem( hwndDlg, IDC_EDIT1 ) )
  367. {
  368. HWND hWndParent = ::GetParent( hwndDlg );
  369. if( hWndParent )
  370. {
  371. ::SendMessage( hWndParent, PSM_PRESSBUTTON, PSBTN_CANCEL, 0 );
  372. }
  373. }
  374. break;
  375. }
  376. case DM_GETDEFID:
  377. {
  378. // This will cover us when the focus is in the edit control and the user hits Enter
  379. if( ::GetFocus() == GetDlgItem( hwndDlg, IDC_EDIT1 ) )
  380. {
  381. HWND hWndParent = ::GetParent( hwndDlg );
  382. if( hWndParent )
  383. {
  384. ::SendMessage( hWndParent, PSM_PRESSBUTTON, PSBTN_FINISH, 0 );
  385. }
  386. }
  387. break;
  388. }
  389. case WM_INITDIALOG:
  390. {
  391. PROPSHEETPAGEW* psp = (PROPSHEETPAGEW*)lParam;
  392. // get whatever's hanging on psp->lParam
  393. // and hang it on hwndDlg via SetWindowLong
  394. SetWindowLongPtr( hwndDlg, GWLP_USERDATA, (LONG_PTR)psp->lParam );
  395. pCW = reinterpret_cast<CChainWiz*>(psp->lParam);
  396. if( pCW )
  397. {
  398. CString csLink;
  399. BOOL bCommctrlV6 = IsComctrlVersion6orGreater();
  400. RECT rect;
  401. // Get the size of the static control
  402. GetClientRect( GetDlgItem( hwndDlg, IDC_STATIC_3 ), &rect );
  403. // Map rect coordinates to the dialog
  404. MapWindowPoints( GetDlgItem( hwndDlg, IDC_STATIC_3 ), hwndDlg, reinterpret_cast<LPPOINT>(&rect), 2 );
  405. if( bCommctrlV6 )
  406. {
  407. //
  408. // if Comctrl version >= 6, we will stick to the Syslink control
  409. //
  410. pCW->m_hWndLink = CreateWindow( WC_LINK, NULL, WS_CHILD | WS_VISIBLE | WS_TABSTOP,
  411. rect.left, rect.top, (rect.right - rect.left), (rect.bottom - rect.top),
  412. hwndDlg, NULL, NULL, NULL );
  413. }
  414. else
  415. {
  416. // Will use rich edit control for the hyperlink
  417. if( NULL == pCW->m_hModuleRichEdit)
  418. {
  419. TCHAR szSystemDirectory[MAX_PATH + 1];
  420. szSystemDirectory[0] = NULL;
  421. if (GetSystemDirectory(szSystemDirectory, MAX_PATH + 1))
  422. {
  423. if (PathAppend(szSystemDirectory, _T("RichEd20.dll")))
  424. {
  425. pCW->m_hModuleRichEdit = LoadLibrary(szSystemDirectory);
  426. }
  427. }
  428. }
  429. if (NULL != pCW->m_hModuleRichEdit)
  430. {
  431. pCW->m_hWndLink = CreateWindowEx( ES_MULTILINE, RICHEDIT_CLASS, NULL,
  432. WS_VISIBLE | WS_TABSTOP | WS_CHILD | ES_READONLY|ES_LEFT | ES_MULTILINE,
  433. rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
  434. hwndDlg, 0, _Module.GetModuleInstance(), NULL );
  435. if( pCW->m_hWndLink )
  436. {
  437. // We want to recive ENM_LINK notifications
  438. ::SendMessage( pCW->m_hWndLink, EM_SETEVENTMASK, 0, ENM_LINK );
  439. pCW->m_Hotlink.SubclassWindow( pCW->m_hWndLink );
  440. }
  441. }
  442. }
  443. }
  444. break;
  445. }
  446. case WM_COMMAND:
  447. {
  448. if( pCW )
  449. {
  450. switch( HIWORD( wParam ) )
  451. {
  452. default:
  453. {
  454. break;
  455. }
  456. case EN_SETFOCUS:
  457. {
  458. if (LOWORD(wParam) == IDC_EDIT1)
  459. {
  460. HWND hwnd = (HWND)lParam;
  461. _ASSERT( IsWindow( hwnd ) );
  462. ::SendMessage( hwnd, EM_SETSEL, 0, 0 );
  463. }
  464. break;
  465. }
  466. }
  467. }
  468. break;
  469. }
  470. case WM_NOTIFY:
  471. {
  472. if (pCW)
  473. {
  474. // do something with notifies...
  475. NMHDR* pNMHDR = (NMHDR*)lParam;
  476. if( !pNMHDR )
  477. {
  478. return FALSE;
  479. }
  480. switch( pNMHDR->code )
  481. {
  482. case NM_RETURN:
  483. case NM_CLICK:
  484. {
  485. if( pCW->m_hWndLink && pNMHDR->idFrom == GetDlgCtrlID(pCW->m_hWndLink) )
  486. {
  487. pCW->LaunchMoreInfo();
  488. }
  489. break;
  490. }
  491. case EN_LINK:
  492. {
  493. if( pCW->m_hWndLink )
  494. {
  495. if( (WM_LBUTTONDOWN == ((ENLINK*)lParam)->msg) || (WM_CHAR == ((ENLINK*)lParam)->msg) )
  496. {
  497. pCW->LaunchMoreInfo();
  498. }
  499. }
  500. break;
  501. }
  502. case PSN_SETACTIVE:
  503. {
  504. // set font
  505. ::SendMessage ( GetDlgItem( hwndDlg, IDC_STATIC_1 ), WM_SETFONT, (WPARAM)pCW->GetBoldFont(), MAKELPARAM(TRUE, 0) );
  506. // set text
  507. ::SetWindowText( GetDlgItem( hwndDlg, IDC_STATIC_1 ), (LPWSTR)pCW->GetFinishHeader() );
  508. ::SetWindowText( GetDlgItem( hwndDlg, IDC_STATIC_2 ), (LPWSTR)pCW->GetFinishSubHeader() );
  509. // get finish text from each component...
  510. LPOLESTR szFinish = NULL;
  511. LPOLESTR szMoreInfo = NULL;
  512. HRESULT hr;
  513. CString csLink;
  514. hr = pCW->GetAllFinishText( &szFinish, &szMoreInfo );
  515. if( SUCCEEDED(hr) )
  516. {
  517. if( szFinish )
  518. {
  519. // ... and add to edit field
  520. HWND hwnd = GetDlgItem( hwndDlg, IDC_EDIT1 );
  521. if( hwnd )
  522. {
  523. ShowScrollBar ( hwnd, SB_VERT, TRUE );
  524. SetWindowTextW( hwnd, szFinish );
  525. // hide vertical scroll if we don't need it
  526. SCROLLINFO si = {0};
  527. si.cbSize = sizeof(SCROLLINFO);
  528. si.fMask = SIF_ALL;
  529. GetScrollInfo( hwnd, SB_VERT, &si );
  530. if( si.nMax < si.nPage )
  531. {
  532. ShowBorder ( hwnd, FALSE );
  533. ShowScrollBar( hwnd, SB_VERT, FALSE );
  534. }
  535. else
  536. {
  537. ShowBorder( hwnd, TRUE );
  538. }
  539. }
  540. }
  541. if( szMoreInfo )
  542. {
  543. if( csLink.LoadString(IDS_LINK_TEXT_WITHINFO) )
  544. {
  545. if( pCW->m_hWndLink )
  546. {
  547. ::SendMessage( pCW->m_hWndLink, WM_SETTEXT, 0, reinterpret_cast<LPARAM>(static_cast<LPCTSTR>(csLink)) );
  548. pCW->WriteTempFile( szMoreInfo );
  549. }
  550. }
  551. CoTaskMemFree( szMoreInfo );
  552. szMoreInfo = NULL;
  553. }
  554. else
  555. {
  556. if( csLink.LoadString(IDS_LINK_TEXT) )
  557. {
  558. if( pCW->m_hWndLink )
  559. {
  560. ::SendMessage( pCW->m_hWndLink, WM_SETTEXT, 0, reinterpret_cast<LPARAM>(static_cast<LPCTSTR>(csLink)) );
  561. LPTSTR szMoreInfoHtml = NULL;
  562. hr = FinishTextToHTML( szFinish, &szMoreInfoHtml );
  563. if( SUCCEEDED(hr) )
  564. {
  565. pCW->WriteTempFile( szMoreInfoHtml );
  566. if( szMoreInfoHtml )
  567. {
  568. delete [] szMoreInfoHtml;
  569. szMoreInfoHtml = NULL;
  570. }
  571. }
  572. }
  573. }
  574. }
  575. }
  576. //
  577. // We need to disable the Back button on the finish page
  578. // if the wizard asked us to do so...
  579. //
  580. if ((pCW->m_dwWizardStyle) & CHAINWIZ_FINISH_BACKDISABLED)
  581. {
  582. ::SendMessage(::GetParent(hwndDlg), PSM_SETWIZBUTTONS, 0, PSWIZB_FINISH | (~PSWIZB_BACK));
  583. }
  584. else
  585. {
  586. // setup buttons
  587. ::SendMessage( GetParent(hwndDlg), PSM_SETWIZBUTTONS, 0, PSWIZB_BACK | PSWIZB_FINISH );
  588. }
  589. break;
  590. }
  591. default:
  592. {
  593. break;
  594. }
  595. }
  596. } //if( pCW )
  597. break;
  598. } // WM_NOTIFY
  599. default:
  600. {
  601. break;
  602. }
  603. }
  604. return FALSE;
  605. }
  606. struct CDataHolder
  607. {
  608. public:
  609. BSTR m_szHeader;
  610. BSTR m_szText;
  611. HFONT m_hf;
  612. CChainWiz* m_pCW;
  613. CDataHolder( LPOLESTR szHeader, LPOLESTR szText, HFONT hf, CChainWiz* pCW )
  614. {
  615. m_szHeader = SysAllocString( szHeader );
  616. m_szText = SysAllocString( szText );
  617. m_hf = hf;
  618. m_pCW = pCW;
  619. }
  620. ~CDataHolder( )
  621. {
  622. if( m_szHeader )
  623. {
  624. SysFreeString( m_szHeader );
  625. }
  626. if( m_szText )
  627. {
  628. SysFreeString( m_szText );
  629. }
  630. // don't delete hf
  631. }
  632. };
  633. INT_PTR CALLBACK WelcomeDlgProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
  634. {
  635. switch( uMsg )
  636. {
  637. case WM_DESTROY:
  638. {
  639. CDataHolder* pdh = (CDataHolder*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA );
  640. if( pdh )
  641. {
  642. delete pdh;
  643. }
  644. SetWindowLongPtr( hwndDlg, GWLP_USERDATA, 0 );
  645. }
  646. break;
  647. case WM_INITDIALOG:
  648. {
  649. // center on desktop
  650. RECT r1;
  651. RECT r2;
  652. ::GetWindowRect( GetParent(hwndDlg), &r1 );
  653. ::GetWindowRect( GetDesktopWindow(), &r2 );
  654. int x = ((r2.right - r2.left) - (r1.right - r1.left)) / 2;
  655. int y = ((r2.bottom - r2.top) - (r1.bottom - r1.top)) / 2;
  656. ::MoveWindow( GetParent(hwndDlg), x, y, (r1.right - r1.left), (r1.bottom - r1.top), TRUE );
  657. PROPSHEETPAGEW* psp = (PROPSHEETPAGEW*)lParam;
  658. // get whatever's hanging on psp->lParam
  659. // and hang it on hwndDlg via SetWindowLong
  660. SetWindowLongPtr( hwndDlg, GWLP_USERDATA, (LONG_PTR)psp->lParam );
  661. // add the rest of the pages now:
  662. // this allows me to force all the pages to a
  663. // fixed size.
  664. CDataHolder* pdh = (CDataHolder*)psp->lParam;
  665. if( pdh )
  666. {
  667. HWND hwndParent = ::GetParent( hwndDlg );
  668. PropSheet_RemovePage( hwndParent, 1, NULL );
  669. PROPSHEETHEADERW* psh = pdh->m_pCW->GetPropSheetHeader();
  670. for( int i = 2; i < psh->nPages; i++ )
  671. {
  672. PropSheet_AddPage( hwndParent, psh->phpage[i] );
  673. }
  674. }
  675. BOOL bCommctrlV6 = IsComctrlVersion6orGreater();
  676. if( bCommctrlV6 )
  677. {
  678. if( pdh && pdh->m_pCW )
  679. {
  680. HWND hwnd = GetDlgItem( hwndDlg, IDC_STATIC_2 );
  681. RECT rect;
  682. // Get the size of the static control
  683. GetClientRect( hwnd, &rect );
  684. // Map rect coordinates to the dialog
  685. MapWindowPoints( hwnd, hwndDlg, reinterpret_cast<LPPOINT>(&rect), 2 );
  686. pdh->m_pCW->m_hWndWelcomeLink = CreateWindow( WC_LINK, NULL, WS_CHILD | WS_VISIBLE | WS_TABSTOP,
  687. rect.left, rect.top, (rect.right - rect.left), (rect.bottom - rect.top),
  688. hwndDlg, NULL, NULL, NULL );
  689. }
  690. }
  691. break;
  692. }
  693. case WM_NOTIFY:
  694. {
  695. NMHDR* pNMHDR = (NMHDR*)lParam;
  696. if( !pNMHDR )
  697. {
  698. return FALSE;
  699. }
  700. switch( pNMHDR->code )
  701. {
  702. case NM_RETURN:
  703. case NM_CLICK:
  704. {
  705. // No links on the Welcome page for CYS.
  706. break;
  707. }
  708. case PSN_SETACTIVE:
  709. {
  710. CDataHolder* pdh = (CDataHolder*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA );
  711. if( pdh )
  712. {
  713. HWND hwnd;
  714. if( pdh->m_szHeader )
  715. {
  716. hwnd = GetDlgItem( hwndDlg, IDC_STATIC_1 );
  717. if( hwnd )
  718. {
  719. // set font
  720. ::SendMessage ( hwnd, WM_SETFONT, (WPARAM)pdh->m_hf, MAKELPARAM(TRUE, 0) );
  721. // set header text
  722. ::SetWindowTextW( hwnd, (LPWSTR)pdh->m_szHeader );
  723. }
  724. }
  725. if( pdh->m_szText )
  726. {
  727. hwnd = NULL;
  728. if( pdh->m_pCW && pdh->m_pCW->m_hWndWelcomeLink )
  729. {
  730. hwnd = pdh->m_pCW->m_hWndWelcomeLink;
  731. }
  732. else
  733. {
  734. hwnd = GetDlgItem( hwndDlg, IDC_STATIC_2 );
  735. }
  736. if( hwnd )
  737. {
  738. ::SetWindowText( hwnd, pdh->m_szText );
  739. }
  740. }
  741. }
  742. //
  743. // If we show the link on the welcome page, it will have the keyboard focus
  744. // thus pressing enter will activate the link and launch the more info stuff
  745. // To work around this problem, we are telling the wizard (parent window)
  746. // to set the focus to the Next button in this particular case.
  747. //
  748. //
  749. // Make sure the keyboard focus is set to the Next button
  750. //
  751. HWND hWndParent = GetParent(hwndDlg);
  752. if( hWndParent )
  753. {
  754. HWND hWndNext = GetDlgItem( hWndParent, IDD_NEXT );
  755. if( hWndNext )
  756. {
  757. // SendMessage will not work
  758. PostMessage( hWndParent, WM_NEXTDLGCTL, reinterpret_cast<WPARAM> (hWndNext), TRUE );
  759. }
  760. }
  761. ::SendMessage( GetParent(hwndDlg), PSM_SETWIZBUTTONS, 0, PSWIZB_NEXT );
  762. break;
  763. }
  764. default:
  765. {
  766. break;
  767. }
  768. }
  769. break;
  770. } // WM_NOTIFY
  771. default:
  772. {
  773. break;
  774. }
  775. }
  776. return FALSE;
  777. }
  778. INT_PTR CALLBACK DummyDlgProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
  779. {
  780. // we should never get here!!!
  781. return FALSE;
  782. }
  783. /////////////////////////////////////////////////////////////////////////////
  784. // CChainWiz
  785. STDMETHODIMP CChainWiz::Initialize( HBITMAP hbmWatermark, HBITMAP hbmHeader, LPOLESTR szTitle, LPOLESTR szWelcomeHeader, LPOLESTR szWelcomeText, LPOLESTR szFinishHeader, LPOLESTR szFinishIntroText, LPOLESTR szFinishText )
  786. {
  787. // make sure this is called only once.
  788. if( m_psh )
  789. {
  790. return E_UNEXPECTED;
  791. }
  792. // validate parameters
  793. if( hbmWatermark != NULL )
  794. {
  795. if( GetObjectType( (HGDIOBJ)hbmWatermark ) != OBJ_BITMAP )
  796. {
  797. return ERROR_INVALID_PARAMETER;
  798. }
  799. }
  800. if( hbmHeader != NULL )
  801. {
  802. if( GetObjectType( (HGDIOBJ)hbmHeader ) != OBJ_BITMAP )
  803. {
  804. return ERROR_INVALID_PARAMETER;
  805. }
  806. }
  807. if ( !szTitle || !szWelcomeHeader || !szWelcomeText || !szFinishHeader || !szFinishIntroText || !szFinishText )
  808. {
  809. return E_POINTER;
  810. }
  811. HRESULT hr = S_OK;
  812. m_psh = new PROPSHEETHEADERW;
  813. if( !m_psh )
  814. {
  815. hr = E_OUTOFMEMORY;
  816. }
  817. else
  818. {
  819. // save title in case a page doesn't have one.
  820. if (szTitle[0] == 0)
  821. {
  822. szTitle = L" "; // use space instead of empty string (for jmenter)
  823. }
  824. m_szWelcomeTitle = SysAllocString( szTitle );
  825. m_szFinishHeader = SysAllocString( szFinishHeader );
  826. m_szFinishSubHeader = SysAllocString( szFinishIntroText );
  827. m_szFirstFinishTextLine = SysAllocString( szFinishText );
  828. // create wizard (property sheet header) here
  829. ZeroMemory( m_psh, sizeof(PROPSHEETHEADERW) );
  830. m_psh->dwSize = sizeof(PROPSHEETHEADERW);
  831. m_psh->dwFlags |= PSH_WIZARD97;
  832. if( hbmWatermark )
  833. {
  834. m_psh->dwFlags |= (PSH_USEHBMWATERMARK | PSH_WATERMARK);
  835. m_psh->hbmWatermark = hbmWatermark;
  836. }
  837. if( hbmHeader )
  838. {
  839. m_psh->dwFlags |= ( PSH_USEHBMHEADER | PSH_HEADER);
  840. m_psh->hbmHeader = hbmHeader;
  841. }
  842. // make an array of HPROPSHEETPAGE FAR *phpage, to hold all the pages
  843. m_psh->phpage = new HPROPSHEETPAGE[MAXPROPPAGES]; // just handles....
  844. m_psh->nPages = 0; // so far
  845. m_psh->nStartPage = 0; // my Welcome page (see below)
  846. // TODO: do I need these? may need to pass in more params...
  847. // ? HWND hwndParent;
  848. // ? HINSTANCE hInstance;
  849. // not using PFNPROPSHEETCALLBACK pfnCallback;
  850. // create welcome page here from parameters above
  851. PROPSHEETPAGEW psp;
  852. ZeroMemory( &psp, sizeof(psp) );
  853. psp.dwSize = sizeof(psp);
  854. psp.dwFlags = PSP_HIDEHEADER; // welcome page: use watermark
  855. psp.dwFlags |= PSP_USETITLE;
  856. psp.pszTitle = szTitle;
  857. psp.hInstance = (HINSTANCE)_Module.GetModuleInstance();
  858. psp.pszTemplate = (LPCWSTR)MAKEINTRESOURCE(IDD_PROPPAGE_WELCOME);
  859. psp.pfnDlgProc = WelcomeDlgProc;
  860. CDataHolder* pDataHolder = new CDataHolder( szWelcomeHeader, szWelcomeText, m_hf, this );
  861. if( !pDataHolder )
  862. {
  863. hr = E_OUTOFMEMORY;
  864. }
  865. else
  866. {
  867. psp.lParam = (LPARAM)pDataHolder;
  868. // ~CDataHolder is called after first PSN_SETACTIVE notification
  869. psp.pfnCallback = 0;
  870. }
  871. if( SUCCEEDED(hr) )
  872. {
  873. hr = Add( &psp );
  874. }
  875. if( SUCCEEDED(hr) )
  876. {
  877. // add dummy entry to list of APSs
  878. CComPtr<IAddPropertySheets> spDummyAPS;
  879. CComponents* pComponents = new CComponents(spDummyAPS);
  880. spDummyAPS.Attach( CDummyComponent::Create(TRUE) ); // assignment causes AddRef !!!! so use Attach instead (!@$#$%&$%@!!!)
  881. if( !pComponents )
  882. {
  883. hr = E_OUTOFMEMORY;
  884. }
  885. else
  886. {
  887. m_listOfAPSs.push_back( pComponents );
  888. }
  889. }
  890. if( hr == S_OK )
  891. {
  892. // now add a dummy property page so that sizing works right:
  893. // this page will be deleted, first thing, by WelcomeDlgProc.
  894. ZeroMemory( &psp, sizeof(psp) );
  895. psp.dwSize = sizeof(psp);
  896. psp.dwFlags |= PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
  897. psp.pszHeaderTitle = MAKEINTRESOURCE(0);
  898. psp.pszHeaderSubTitle = MAKEINTRESOURCE(0);
  899. psp.hInstance = (HINSTANCE)_Module.GetModuleInstance();
  900. psp.pszTemplate = (LPCWSTR)MAKEINTRESOURCE(IDD_PROPPAGE_DUMMY);
  901. psp.pfnDlgProc = DummyDlgProc;
  902. psp.lParam = 0;
  903. psp.pfnCallback = 0;
  904. hr = Add( &psp );
  905. // TODO: do I need to add to the list of APSs ???
  906. }
  907. }
  908. return hr;
  909. }
  910. STDMETHODIMP CChainWiz::AddWizardComponent( LPOLESTR szClsidOfComponent )
  911. {
  912. // make sure wizard has been created (in Initalize, above)
  913. if( !m_psh ) return E_UNEXPECTED;
  914. // validate parameter(s)
  915. if( !szClsidOfComponent ) return E_POINTER;
  916. // convert string to clsid
  917. CLSID clsid;
  918. HRESULT hr = S_OK;
  919. RPC_STATUS rpcs = CLSIDFromString( szClsidOfComponent, &clsid );
  920. if (rpcs == RPC_S_OK)
  921. {
  922. // create wizard component
  923. IAddPropertySheets* pAPSs = NULL;
  924. hr = CoCreateInstance( clsid, NULL, CLSCTX_INPROC_SERVER, IID_IAddPropertySheets, (void **)&pAPSs);
  925. if( hr == S_OK )
  926. {
  927. SetCurrentComponent( pAPSs );
  928. CAddPropertySheet* pAPS = new CAddPropertySheet(this);
  929. if( !pAPS )
  930. {
  931. hr = E_OUTOFMEMORY;
  932. }
  933. else
  934. {
  935. pAPS->AddRef();
  936. do
  937. {
  938. // call IAddPropertySheets::EnumPropertySheets until S_FALSE,
  939. // adding pages to wizard
  940. hr = pAPSs->EnumPropertySheets( pAPS );
  941. } while( hr == S_OK );
  942. pAPS->Release();
  943. if( hr == S_FALSE )
  944. {
  945. hr = S_OK; // S_FALSE means no more pages (not an error).
  946. }
  947. // hang onto pAPSs in order to:
  948. // 1. keep code in memory so that each pages dlgproc will work
  949. // 2. be able to call pAPSs->ProvideFinishText for finish page
  950. if( hr == S_OK )
  951. {
  952. CComponents* pComponents = new CComponents(pAPSs);
  953. if( !pComponents )
  954. {
  955. hr = E_OUTOFMEMORY;
  956. }
  957. else
  958. {
  959. m_listOfAPSs.push_back( pComponents );
  960. }
  961. }
  962. pAPSs->Release(); // not using this anymore, but have addref'd copies in my listofAPSs
  963. }
  964. SetCurrentComponent( NULL );
  965. }
  966. }
  967. return hr;
  968. }
  969. STDMETHODIMP CChainWiz::DoModal( long* ret )
  970. {
  971. // make sure wizard has been created.
  972. if( !m_psh ) return E_UNEXPECTED;
  973. // validate parameter(s)
  974. if( !ret ) return E_POINTER;
  975. *ret = 0;
  976. // add finish page
  977. PROPSHEETPAGEW psp;
  978. ZeroMemory( &psp, sizeof(psp) );
  979. psp.dwSize = sizeof(psp);
  980. psp.dwFlags = PSP_HIDEHEADER; // finish page: use watermark
  981. psp.hInstance = _Module.GetModuleInstance();
  982. psp.pszTemplate = (LPCWSTR)MAKEINTRESOURCE(IDD_PROPPAGE_FINISH);
  983. psp.pfnDlgProc = FinishDlgProc;
  984. psp.lParam = (LPARAM)this;
  985. HRESULT hr = Add (&psp); // can't continue without a "Finish" button...
  986. { // add dummy entry to list of APSs
  987. CComponents* pComponents = NULL;
  988. CComPtr<IAddPropertySheets> spDummyAPS;
  989. spDummyAPS.Attach (CDummyComponent::Create (FALSE)); // assignment causes AddRef !!!! so use Attach instead (!@$#$%&$%@!!!)
  990. pComponents = new CComponents(spDummyAPS);
  991. if( !pComponents )
  992. {
  993. hr = E_OUTOFMEMORY;
  994. }
  995. else
  996. {
  997. m_listOfAPSs.push_back ( pComponents );
  998. }
  999. }
  1000. if( hr == S_OK )
  1001. {
  1002. // make a copy so I can muck with the count:
  1003. // I need to do this so I can set a fixed size
  1004. // for all the property pages.
  1005. PROPSHEETHEADERW psh;
  1006. memcpy( &psh, m_psh, sizeof(PROPSHEETHEADERW) );
  1007. psh.nPages = 2; // welcome and dummy pages
  1008. *ret = ::PropertySheet( &psh );
  1009. // clean up: so that DoModal can't be called twice
  1010. delete m_psh;
  1011. m_psh = NULL;
  1012. // also, clean up maps
  1013. DestroyMaps();
  1014. if( *ret == -1 )
  1015. {
  1016. hr = GetLastError();
  1017. }
  1018. }
  1019. return hr;
  1020. }
  1021. #ifdef DEBUG
  1022. DLGITEMTEMPLATE* DumpItem( DLGITEMTEMPLATE* pdit )
  1023. {
  1024. TCHAR szBuffer[256];
  1025. wsprintf( szBuffer,
  1026. _T("\n\nDialog Item:\nstyle: 0x%x\ndwExtendedStyle: 0x%x\nx, y: %d, %d\ncx, cy: %d, %d\nid: %d\n"),
  1027. pdit->style,
  1028. pdit->dwExtendedStyle,
  1029. pdit->x, pdit->y,
  1030. pdit->cx, pdit->cy,
  1031. pdit->id );
  1032. OutputDebugString( szBuffer );
  1033. WORD* pw = (WORD*)(pdit + 1);
  1034. // window class:
  1035. // WORD 0xffff => predefined system class (1 more word)
  1036. // anything else => UNICODE string of class
  1037. switch( *pw )
  1038. {
  1039. case 0xffff:
  1040. {
  1041. wsprintf (szBuffer, _T("predefined system class: %d\n"), pw[1] );
  1042. OutputDebugString( szBuffer );
  1043. pw += 2;
  1044. break;
  1045. }
  1046. default:
  1047. {
  1048. OutputDebugString( _T("class: ") );
  1049. OutputDebugStringW( pw );
  1050. pw += wcslen( pw ) + 1;
  1051. OutputDebugString( _T("\n") );
  1052. break;
  1053. }
  1054. }
  1055. // title
  1056. // WORD 0xffff => 1 more word specifying resource id
  1057. // anything else => UNICODE text
  1058. switch( *pw )
  1059. {
  1060. case 0xffff:
  1061. {
  1062. wsprintf( szBuffer, _T("resource id: %d\n"), pw[1] );
  1063. OutputDebugString( szBuffer );
  1064. pw += 2;
  1065. break;
  1066. }
  1067. default:
  1068. {
  1069. OutputDebugString( _T("text: ") );
  1070. OutputDebugStringW( pw );
  1071. pw += wcslen( pw ) + 1;
  1072. OutputDebugString( _T("\n") );
  1073. break;
  1074. }
  1075. }
  1076. // creation data array
  1077. // first word is size of array (in bytes)
  1078. wsprintf( szBuffer, _T("%d bytes of creation data\n"), *pw );
  1079. OutputDebugString( szBuffer );
  1080. pw = 1 + (WORD*)(*pw + (BYTE*)pw);
  1081. // DWORD align
  1082. return (DLGITEMTEMPLATE*)(((DWORD_PTR)pw + 3) & ~DWORD_PTR(3));
  1083. }
  1084. void DumpTemplate( LPDLGTEMPLATE pdt )
  1085. {
  1086. if( ((WORD *)pdt)[1] == 0xFFFF )
  1087. {
  1088. return;
  1089. }
  1090. TCHAR szBuffer[256];
  1091. // dump info about DLGTEMPLATE
  1092. wsprintf( szBuffer,
  1093. _T("\n\nDialog Template:\nstyle: 0x%x\ndwExtendedStyle: 0x%x\ncdit: %d\nx, y: %d, %d\ncx, cy: %d, %d\n"),
  1094. pdt->style,
  1095. pdt->dwExtendedStyle,
  1096. pdt->cdit,
  1097. pdt->x, pdt->y,
  1098. pdt->cx, pdt->cy );
  1099. OutputDebugString( szBuffer );
  1100. WORD* pw = (WORD*)(pdt + 1);
  1101. // menu: 0000 = no menu; ffff = menu id; else Unicode string
  1102. switch( *pw )
  1103. {
  1104. case 0:
  1105. {
  1106. OutputDebugString( _T("no menu\n") );
  1107. pw += 2;
  1108. break;
  1109. }
  1110. case 0xFFFF:
  1111. {
  1112. pw++;
  1113. wsprintf( szBuffer, _T("menu id: %d\n"), *(DWORD*)pw );
  1114. OutputDebugString( szBuffer );
  1115. pw += 2;
  1116. break;
  1117. }
  1118. default:
  1119. {
  1120. OutputDebugStringW( pw );
  1121. pw += wcslen( pw ) + 1;
  1122. OutputDebugString( _T("\n") );
  1123. break;
  1124. }
  1125. }
  1126. // caption string:
  1127. OutputDebugString( _T("caption: ") );
  1128. OutputDebugStringW( pw );
  1129. pw += wcslen( pw ) + 1;
  1130. OutputDebugString( _T("\n") );
  1131. // extra font information
  1132. if (pdt->style & DS_SETFONT)
  1133. {
  1134. // font size
  1135. wsprintf( szBuffer, _T("font size: %d\n"), *pw++ );
  1136. OutputDebugString( szBuffer );
  1137. // typeface
  1138. OutputDebugString( _T("typeface: ") );
  1139. OutputDebugStringW( pw );
  1140. pw += wcslen( pw ) + 1;
  1141. OutputDebugString( _T("\n") );
  1142. }
  1143. // DWORD align
  1144. DLGITEMTEMPLATE* pdit = (DLGITEMTEMPLATE*)(((DWORD_PTR)pw + 3) & ~DWORD_PTR(3));
  1145. // dump all dlg items
  1146. for( WORD i = 0; i < pdt->cdit; i++ )
  1147. {
  1148. pdit = DumpItem( pdit );
  1149. }
  1150. }
  1151. #endif
  1152. INT_PTR CALLBACK SanityDlgProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
  1153. {
  1154. return FALSE;
  1155. }
  1156. HRESULT SanityTest( PROPSHEETPAGEW* psp )
  1157. {
  1158. HRESULT hr = S_OK;
  1159. assert( psp->dwFlags & PSP_DLGINDIRECT );
  1160. LPCDLGTEMPLATE pdt = psp->pResource;
  1161. #ifdef DEBUG
  1162. DumpTemplate( (LPDLGTEMPLATE)pdt );
  1163. #endif
  1164. HWND hwndPage = CreateDialogIndirectParam( psp->hInstance, pdt, GetDesktopWindow(), SanityDlgProc, NULL );
  1165. if( hwndPage )
  1166. {
  1167. DestroyWindow( hwndPage );
  1168. }
  1169. else
  1170. {
  1171. hr = GetLastError();
  1172. if( hr == S_OK )
  1173. {
  1174. hr = E_FAIL;
  1175. }
  1176. }
  1177. return hr;
  1178. }
  1179. HRESULT CChainWiz::Add( PROPSHEETPAGEW* psp )
  1180. {
  1181. if( !psp )
  1182. {
  1183. return E_POINTER;
  1184. }
  1185. if( !psp->hInstance )
  1186. {
  1187. return ERROR_INVALID_PARAMETER;
  1188. }
  1189. // allocate my data to do thunking
  1190. CThunkData* pTD = new CThunkData( this, psp, NULL, m_CurrentComponent );
  1191. if( !pTD )
  1192. {
  1193. return E_OUTOFMEMORY;
  1194. }
  1195. // swap my data for their data
  1196. DWORD dwFlags = psp->dwFlags;
  1197. if( !(dwFlags & PSP_DLGINDIRECT) )
  1198. {
  1199. LPDLGTEMPLATE lpdt = GetDialogTemplate( psp->hInstance, psp->pszTemplate );
  1200. if( lpdt )
  1201. {
  1202. psp->dwFlags |= PSP_DLGINDIRECT;
  1203. LPDLGTEMPLATE lpdt2 = _DialogSplitHelper::SplitDialogTemplate( (LPDLGTEMPLATE)lpdt, NULL );
  1204. if( lpdt2 == lpdt )
  1205. {
  1206. psp->pResource = lpdt;
  1207. }
  1208. else
  1209. {
  1210. psp->pResource = lpdt2;
  1211. // add to map so I can remap resource id to new template ptr
  1212. m_mapOfTemplates[lpdt] = lpdt2;
  1213. }
  1214. }
  1215. }
  1216. psp->dwFlags |= PSP_USECALLBACK | PSP_USETITLE;
  1217. psp->pfnDlgProc = ChainDlgProc;
  1218. psp->lParam = (LPARAM)pTD;
  1219. psp->pfnCallback = ChainCallback;
  1220. // this is not used in wizard pages....
  1221. // remove it just in case comctl32.dll wants to use the hinstance that
  1222. // I'm about to replace, below
  1223. if( psp->dwFlags & PSP_USEICONID )
  1224. {
  1225. psp->dwFlags &= ~PSP_USEICONID;
  1226. }
  1227. // similarly, lock string resources (title, header, subtitle)
  1228. if( !(psp->pszTitle = DupStringResource (psp->hInstance, psp->pszTitle)) )
  1229. {
  1230. psp->pszTitle = _wcsdup (m_szWelcomeTitle); // use default from welcome page
  1231. }
  1232. psp->pszHeaderTitle = DupStringResource( psp->hInstance, psp->pszHeaderTitle );
  1233. psp->pszHeaderSubTitle = DupStringResource( psp->hInstance, psp->pszHeaderSubTitle );
  1234. // in order to get OCXs to be created we need:
  1235. // 1. to register AtlAxWin class (this is done in DllGetClassObject)
  1236. // 2. to pass our hinstance, not their's, as RegisterClass is not system-wide.
  1237. // So, I've fixed up all resource ids to be pointers and so now can
  1238. // replace their hinstance with mine.
  1239. psp->hInstance = (HINSTANCE)_Module.GetModuleInstance();
  1240. // run some sanity checks
  1241. HRESULT hr = SanityTest( psp );
  1242. if( hr != S_OK )
  1243. {
  1244. // oops! something didn't work:
  1245. // change everything back
  1246. FreeStringResources( psp );
  1247. if( pTD->m_theirPSP )
  1248. {
  1249. MoveMemory( psp, pTD->m_theirPSP, pTD->m_theirPSP->dwSize );
  1250. }
  1251. delete pTD; // won't be using this....
  1252. return hr;
  1253. }
  1254. // create the page
  1255. HPROPSHEETPAGE hpsp = CreatePropertySheetPage( psp );
  1256. if( hpsp == NULL )
  1257. {
  1258. hr = GetLastError( );
  1259. if( hr == S_OK ) // no docs on this....
  1260. {
  1261. hr = E_FAIL;
  1262. }
  1263. }
  1264. else
  1265. {
  1266. // all is well
  1267. m_psh->phpage[m_psh->nPages++] = hpsp;
  1268. }
  1269. // change everything back
  1270. FreeStringResources( psp );
  1271. MoveMemory( psp, pTD->m_theirPSP, pTD->m_theirPSP->dwSize );
  1272. return hr;
  1273. }
  1274. HRESULT CChainWiz::GetAllFinishText(LPOLESTR* pstring, LPOLESTR* ppMoreInfoText )
  1275. {
  1276. if( !pstring || !ppMoreInfoText )
  1277. {
  1278. return E_POINTER;
  1279. }
  1280. *pstring = NULL; // in case of errors
  1281. *ppMoreInfoText = NULL;
  1282. if( m_szFinishText )
  1283. {
  1284. CoTaskMemFree( m_szFinishText );
  1285. m_szFinishText = NULL;
  1286. }
  1287. m_szFinishText = (LPOLESTR)CoTaskMemAlloc( 1 * sizeof(OLECHAR) );
  1288. if( !m_szFinishText )
  1289. {
  1290. return E_OUTOFMEMORY;
  1291. }
  1292. m_szFinishText[0] = 0; // so wcscat works
  1293. OLECHAR szCRLF[] = L"\r\n";
  1294. DWORD dwSize = 0;
  1295. DWORD dwSizeMoreInfoText = 0;
  1296. // First line will precede any finish text from wizard components.
  1297. if( m_szFirstFinishTextLine && (0 < _tcslen( m_szFirstFinishTextLine )) )
  1298. {
  1299. dwSize += (sizeof(OLECHAR) * (wcslen( m_szFirstFinishTextLine ) + 1 )) + (sizeof(szCRLF) * 2);
  1300. LPOLESTR szTemp = (LPOLESTR)CoTaskMemRealloc( m_szFinishText, dwSize );
  1301. if( szTemp )
  1302. {
  1303. m_szFinishText = szTemp;
  1304. wcscat( m_szFinishText, m_szFirstFinishTextLine );
  1305. wcscat( m_szFinishText, szCRLF );
  1306. wcscat( m_szFinishText, szCRLF );
  1307. }
  1308. }
  1309. std::list<CComponents*>::iterator iterAPSs = m_listOfAPSs.begin();
  1310. CComponents* pLastComp = *iterAPSs;
  1311. for (CComponents* pComps = *iterAPSs; iterAPSs != m_listOfAPSs.end(); pComps = *++iterAPSs)
  1312. {
  1313. if( pLastComp->GetComponent() == pComps->GetComponent() )
  1314. {
  1315. continue; // look for unique APSs only
  1316. }
  1317. pLastComp = pComps; // for next time
  1318. IAddPropertySheets* pAPSs = pComps->GetComponent();
  1319. // have 'em re-read their properties (esp. read-write properties)
  1320. m_PPPBag->SetReadOnly( TRUE );
  1321. m_PPPBag->SetOwner ( (LONG_PTR)pAPSs );
  1322. IPropertyPagePropertyBag* pOPPPBag = COwnerPPPBag::Create( m_PPPBag, (LONG_PTR)pAPSs );
  1323. if( pOPPPBag )
  1324. {
  1325. pAPSs->ReadProperties( pOPPPBag );
  1326. pOPPPBag->Release();
  1327. }
  1328. m_PPPBag->SetReadOnly( FALSE ); // in case committers want to write
  1329. // get the finish text
  1330. LPOLESTR szFinishPiece = NULL;
  1331. LPOLESTR szMoreInfoPiece = NULL;
  1332. pAPSs->ProvideFinishText( &szFinishPiece, &szMoreInfoPiece );
  1333. if( szFinishPiece )
  1334. {
  1335. dwSize += (sizeof(OLECHAR) * (wcslen( szFinishPiece ) + 1)) + sizeof(szCRLF);
  1336. LPOLESTR szTemp = (LPOLESTR)CoTaskMemRealloc( m_szFinishText, dwSize );
  1337. if (szTemp)
  1338. {
  1339. m_szFinishText = szTemp;
  1340. wcscat( m_szFinishText, szFinishPiece );
  1341. wcscat( m_szFinishText, szCRLF );
  1342. }
  1343. CoTaskMemFree( szFinishPiece );
  1344. }
  1345. if( szMoreInfoPiece )
  1346. {
  1347. dwSizeMoreInfoText += (sizeof(OLECHAR) * (wcslen(szMoreInfoPiece) + 1)) + sizeof(szCRLF);
  1348. LPOLESTR szTemp = (LPOLESTR)CoTaskMemRealloc( *ppMoreInfoText, dwSizeMoreInfoText );
  1349. if( szTemp )
  1350. {
  1351. *ppMoreInfoText = szTemp;
  1352. wcscat( *ppMoreInfoText, szMoreInfoPiece );
  1353. wcscat( *ppMoreInfoText, szCRLF );
  1354. }
  1355. CoTaskMemFree( szMoreInfoPiece );
  1356. }
  1357. }
  1358. *pstring = m_szFinishText;
  1359. return S_OK;
  1360. }
  1361. STDMETHODIMP CChainWiz::get_PropertyBag( IDispatch** pVal )
  1362. {
  1363. if( !pVal ) return E_POINTER;
  1364. *pVal = NULL;
  1365. HRESULT hr = S_OK;
  1366. // don't give anybody a raw bag: wrap it up in an owner bag
  1367. IPropertyPagePropertyBag* pOPPPBag = COwnerPPPBag::Create( m_PPPBag, PPPBAG_SYSTEM_OWNER );
  1368. if( !pOPPPBag )
  1369. {
  1370. hr = E_OUTOFMEMORY;
  1371. }
  1372. else
  1373. {
  1374. hr = pOPPPBag->QueryInterface( IID_IDispatch, (void**)pVal );
  1375. pOPPPBag->Release();
  1376. }
  1377. return hr;
  1378. }
  1379. STDMETHODIMP CChainWiz::get_MoreInfoFileName( BSTR* pbstrMoreInfoFileName )
  1380. {
  1381. if( !pbstrMoreInfoFileName ) return E_POINTER;
  1382. HRESULT hr = S_OK;
  1383. if( NULL == m_bstrTempFileName )
  1384. {
  1385. return E_UNEXPECTED;
  1386. }
  1387. else
  1388. {
  1389. *pbstrMoreInfoFileName = SysAllocString( m_bstrTempFileName );
  1390. if( NULL == *pbstrMoreInfoFileName )
  1391. {
  1392. hr = E_OUTOFMEMORY;
  1393. }
  1394. }
  1395. return hr;
  1396. }
  1397. STDMETHODIMP CChainWiz::put_WizardStyle(VARIANT * pVarWizardStyle)
  1398. {
  1399. if (NULL == pVarWizardStyle)
  1400. {
  1401. return E_POINTER;
  1402. }
  1403. if (VT_UI4 != V_VT(pVarWizardStyle))
  1404. {
  1405. return E_INVALIDARG;
  1406. }
  1407. m_dwWizardStyle = V_UI4(pVarWizardStyle);
  1408. return S_OK;
  1409. }
  1410. HRESULT CChainWiz::WriteTempFile( LPCTSTR pszText )
  1411. {
  1412. if( !pszText ) return E_POINTER;
  1413. HRESULT hr = S_OK;
  1414. HANDLE hFile = NULL;
  1415. TCHAR szTempFileName[MAX_PATH] = {0};
  1416. BOOL bGenerateFileName = FALSE;
  1417. if( NULL == m_bstrTempFileName )
  1418. {
  1419. bGenerateFileName = TRUE;
  1420. }
  1421. else
  1422. {
  1423. szTempFileName[MAX_PATH - 1] = NULL;
  1424. _tcsncpy(szTempFileName, m_bstrTempFileName, MAX_PATH);
  1425. if (NULL != szTempFileName[MAX_PATH - 1])
  1426. {
  1427. hr = E_UNEXPECTED;
  1428. }
  1429. }
  1430. hFile = _CreateTempFile( szTempFileName, _T(".html"), bGenerateFileName );
  1431. if( INVALID_HANDLE_VALUE == hFile )
  1432. {
  1433. hr = HRESULT_FROM_WIN32(GetLastError());
  1434. }
  1435. else
  1436. {
  1437. if( 0 == _tcslen( szTempFileName ) )
  1438. {
  1439. hr = E_UNEXPECTED;
  1440. }
  1441. }
  1442. if( SUCCEEDED(hr) )
  1443. {
  1444. DWORD dwcBytesWritten;
  1445. #ifdef UNICODE
  1446. // write UNICODE signature
  1447. // IE is doing fine without this but, anyway...
  1448. unsigned char sig[2] = { 0xFF, 0xFE };
  1449. if( !WriteFile( hFile, reinterpret_cast<LPVOID>(sig), 2, &dwcBytesWritten, NULL ) )
  1450. {
  1451. hr = HRESULT_FROM_WIN32(GetLastError());
  1452. }
  1453. #endif
  1454. if( SUCCEEDED(hr) )
  1455. {
  1456. if( !WriteFile( hFile, pszText, (sizeof(TCHAR) * _tcslen( pszText )), &dwcBytesWritten, NULL ) )
  1457. {
  1458. hr = HRESULT_FROM_WIN32(GetLastError());
  1459. }
  1460. }
  1461. }
  1462. if (SUCCEEDED(hr))
  1463. {
  1464. m_bstrTempFileName = SysAllocString(szTempFileName);
  1465. if (NULL == m_bstrTempFileName)
  1466. {
  1467. hr = E_OUTOFMEMORY;
  1468. }
  1469. }
  1470. if( hFile )
  1471. {
  1472. CloseHandle( hFile );
  1473. }
  1474. return hr;
  1475. }
  1476. HRESULT CChainWiz::LaunchMoreInfo( )
  1477. {
  1478. HRESULT hr = S_OK;
  1479. if( !m_bstrTempFileName )
  1480. {
  1481. return E_FAIL;
  1482. }
  1483. INT_PTR hRet = (INT_PTR)ShellExecute( NULL, _T("open"), m_bstrTempFileName, NULL, _T("."), SW_SHOW );
  1484. if( 32 >= hRet )
  1485. {
  1486. hr = E_FAIL;
  1487. }
  1488. return hr;
  1489. }