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.

540 lines
13 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. WizList.cpp : implementation file
  5. File History:
  6. JonY Jan-96 created
  7. --*/
  8. #include "stdafx.h"
  9. #include "Mustard.h"
  10. #include "WizList.h"
  11. #include "Listdata.h"
  12. #include "startd.h"
  13. #include <winnetwk.h>
  14. #include <shlobj.h>
  15. #ifdef _DEBUG
  16. #define new DEBUG_NEW
  17. #undef THIS_FILE
  18. static char THIS_FILE[] = __FILE__;
  19. #endif
  20. const USHORT BITMAP_WIDTH = 32;
  21. const USHORT BITMAP_HEIGHT = 32;
  22. const USHORT MAX_PRINTER_NAME = 256 + 2;
  23. const USHORT CELL_HEIGHT = 71;
  24. const USHORT CELL_WIDTH = 300;
  25. typedef BOOL (*BPRINTERSETUP)(HWND, UINT, UINT, LPTSTR, UINT*, LPCTSTR);
  26. /////////////////////////////////////////////////////////////////////////////
  27. // CWizList
  28. CWizList::CWizList()
  29. {
  30. CString fontname;
  31. fontname.LoadString(IDS_FONT_NAME);
  32. CString fontheight;
  33. fontheight.LoadString(IDS_FONT_SIZE);
  34. // regular font
  35. m_pFont = new CFont;
  36. LOGFONT lf;
  37. memset(&lf, 0, sizeof(LOGFONT)); // Clear out structure.
  38. lf.lfHeight = (LONG)_tcstoul(fontheight, NULL, 10);
  39. _tcscpy(lf.lfFaceName, fontname);
  40. lf.lfWeight = 100;
  41. m_pFont->CreateFontIndirect(&lf); // Create the font.
  42. // bold font
  43. m_pFontBold = new CFont;
  44. memset(&lf, 0, sizeof(LOGFONT)); // Clear out structure.
  45. lf.lfHeight = (LONG)_tcstoul(fontheight, NULL, 10);
  46. _tcscpy(lf.lfFaceName, fontname);
  47. lf.lfWeight = 700;
  48. m_pFontBold->CreateFontIndirect(&lf); // Create the font.
  49. m_hPrinterLib = NULL;
  50. }
  51. CWizList::~CWizList()
  52. {
  53. if (m_pFont != NULL) delete m_pFont;
  54. if (m_pFontBold != NULL) delete m_pFontBold;
  55. if (m_hPrinterLib != NULL) FreeLibrary(m_hPrinterLib);
  56. }
  57. BEGIN_MESSAGE_MAP(CWizList, CListBox)
  58. //{{AFX_MSG_MAP(CWizList)
  59. ON_WM_MOUSEMOVE()
  60. ON_WM_LBUTTONDOWN()
  61. ON_CONTROL_REFLECT(LBN_SETFOCUS, OnSetfocus)
  62. //}}AFX_MSG_MAP
  63. END_MESSAGE_MAP()
  64. /////////////////////////////////////////////////////////////////////////////
  65. // CWizList message handlers
  66. void CWizList::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
  67. {
  68. COLORREF crefOldText;
  69. CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
  70. pDC->SetBkMode(OPAQUE);
  71. // save the current font for later
  72. CFont* pOldFont = (CFont*)pDC->SelectObject(m_pFont);
  73. CItemData* pData = (CItemData*)GetItemData(lpDrawItemStruct->itemID);
  74. LPCTSTR pName2 = (const TCHAR*)pData->csDesc;
  75. LPCTSTR pName = (const TCHAR*)pData->csName;
  76. HICON hIcon = pData->hIcon;
  77. HICON hSelIcon = pData->hSelIcon;
  78. int nTop = (lpDrawItemStruct->rcItem.bottom + lpDrawItemStruct->rcItem.top) / 2;
  79. switch (lpDrawItemStruct->itemAction)
  80. {
  81. case ODA_SELECT:
  82. case ODA_DRAWENTIRE:
  83. // paint the left side - then draw text
  84. CRect crRight(50, lpDrawItemStruct->rcItem.top,
  85. lpDrawItemStruct->rcItem.right,
  86. lpDrawItemStruct->rcItem.bottom);
  87. CBrush* pBrush = new CBrush;
  88. pBrush->CreateSolidBrush(GetSysColor(COLOR_WINDOW));
  89. pDC->FillRect(crRight, pBrush);
  90. // paint the right - then draw text
  91. pDC->SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
  92. crRight = CRect(lpDrawItemStruct->rcItem.left, lpDrawItemStruct->rcItem.top,
  93. 50,
  94. lpDrawItemStruct->rcItem.bottom);
  95. pDC->FillRect(crRight, pBrush);
  96. crRight = CRect(lpDrawItemStruct->rcItem.left + 5, lpDrawItemStruct->rcItem.top + 3,
  97. 140,
  98. lpDrawItemStruct->rcItem.bottom);
  99. // Is the item selected?
  100. if (lpDrawItemStruct->itemState & ODS_SELECTED)
  101. {
  102. // Display bitmap
  103. nTop = (lpDrawItemStruct->rcItem.bottom + lpDrawItemStruct->rcItem.top - BITMAP_HEIGHT) / 2;
  104. pDC->DrawIcon(lpDrawItemStruct->rcItem.left + 9, nTop - 9, hSelIcon);
  105. // paint the right - then draw text
  106. crefOldText = pDC->SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT));
  107. pDC->SetBkColor(GetSysColor(COLOR_HIGHLIGHT));
  108. }
  109. else
  110. {
  111. // Display bitmap
  112. nTop = (lpDrawItemStruct->rcItem.bottom + lpDrawItemStruct->rcItem.top - BITMAP_HEIGHT) / 2;
  113. pDC->DrawIcon(lpDrawItemStruct->rcItem.left + 9, nTop - 9, hIcon);
  114. crefOldText = pDC->SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
  115. pDC->SetBkColor(GetSysColor(COLOR_WINDOW));
  116. }
  117. // draw the top (bold) text
  118. pDC->SelectObject(m_pFontBold);
  119. CRect crTop = CRect(60, lpDrawItemStruct->rcItem.top + 8,
  120. lpDrawItemStruct->rcItem.right - 10, lpDrawItemStruct->rcItem.bottom);
  121. pDC->DrawText(pName, _tcslen(pName),
  122. crTop,
  123. DT_WORDBREAK);
  124. // draw the lower text
  125. pDC->SelectObject(m_pFont);
  126. CRect crBottom = CRect(60, lpDrawItemStruct->rcItem.top + 28,
  127. lpDrawItemStruct->rcItem.right - 10, lpDrawItemStruct->rcItem.bottom);
  128. pDC->DrawText(pName2, _tcslen(pName2),
  129. crBottom,
  130. DT_WORDBREAK);
  131. pDC->SelectObject(pOldFont);
  132. pDC->SetTextColor(crefOldText );
  133. delete pBrush;
  134. break;
  135. }
  136. // Restore the original font
  137. pDC->SelectObject(pOldFont);
  138. }
  139. void CWizList::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
  140. {
  141. lpMeasureItemStruct->itemHeight = CELL_HEIGHT;
  142. lpMeasureItemStruct->itemWidth = CELL_WIDTH;
  143. }
  144. void CWizList::OnMouseMove(UINT nFlags, CPoint point)
  145. {
  146. if (((CStartD*)GetParent())->IsActive())
  147. {
  148. USHORT y = (USHORT)(point.y / CELL_HEIGHT);
  149. USHORT usCurSel = (USHORT)GetCurSel();
  150. if (usCurSel != y) SetCurSel(y);
  151. // tell the other guy not to show any selection
  152. m_pOtherGuy->SetCurSel(-1);
  153. }
  154. CListBox::OnMouseMove(nFlags, point);
  155. }
  156. void CWizList::OnLButtonDown(UINT nFlags, CPoint point)
  157. {
  158. USHORT usCurSel = (USHORT)GetCurSel();
  159. // Exit if there's no selection.
  160. if (usCurSel == (USHORT)-1)
  161. return;
  162. CItemData* pData = (CItemData*)GetItemData(usCurSel);
  163. // is this the printer wiz?
  164. if (pData->csAppStart1 == "")
  165. {
  166. try
  167. {
  168. LaunchPrinterWizard();
  169. }
  170. catch (...)
  171. {
  172. TRACE(_T("An exception occurred while attempting to start the Add Printer Wizard.\n"));
  173. }
  174. }
  175. else
  176. {
  177. // otherwise
  178. CString csCmdLine = pData->csAppStart1 + " ";
  179. csCmdLine += pData->csAppStart2;
  180. TCHAR* pCmdLine = csCmdLine.GetBuffer(csCmdLine.GetLength());
  181. STARTUPINFO sInfo;
  182. ZeroMemory(&sInfo, sizeof(sInfo));
  183. sInfo.cb = sizeof(sInfo);
  184. PROCESS_INFORMATION pInfo;
  185. BOOL bProc = CreateProcess(NULL,
  186. pCmdLine,
  187. NULL, NULL,
  188. TRUE,
  189. NORMAL_PRIORITY_CLASS,
  190. NULL, NULL,
  191. &sInfo,
  192. &pInfo);
  193. if (!bProc) AfxMessageBox(IDS_NO_START);
  194. csCmdLine.ReleaseBuffer();
  195. }
  196. // CListBox::OnLButtonDown(nFlags, point);
  197. }
  198. void CWizList::PumpMessages()
  199. {
  200. MSG msg;
  201. // check outstanding messages
  202. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  203. {
  204. if (!IsDialogMessage(&msg))
  205. {
  206. TranslateMessage(&msg);
  207. DispatchMessage(&msg);
  208. }
  209. }
  210. }
  211. BOOL CWizList::LaunchPrinterWizard()
  212. {
  213. CWaitCursor wc;
  214. BOOL bReturn = TRUE;
  215. HRESULT hr;
  216. LPSHELLFOLDER pshf, pshfPrinters;
  217. LPITEMIDLIST pidlPrintFolder, pidlPrintObj;
  218. LPMALLOC pMalloc;
  219. // Get a pointer to the shell's IMalloc interface.
  220. hr = SHGetMalloc(&pMalloc);
  221. if (SUCCEEDED(hr))
  222. {
  223. // Get a pointer to the shell's IShellFolder interface.
  224. hr = SHGetDesktopFolder(&pshf);
  225. if (SUCCEEDED(hr))
  226. {
  227. // Get a PIDL for the Printers folder.
  228. hr = SHGetSpecialFolderLocation(GetSafeHwnd(), CSIDL_PRINTERS, &pidlPrintFolder);
  229. if (SUCCEEDED(hr))
  230. {
  231. // Get a pointer to the IShellFolder interface for the Printer folder.
  232. hr = pshf->BindToObject(pidlPrintFolder, NULL, IID_IShellFolder, (LPVOID*)&pshfPrinters);
  233. if (SUCCEEDED(hr))
  234. {
  235. // Get a PIDL for the Add Printer object in the Printers folder.
  236. hr = GetAddPrinterObject(pshfPrinters, &pidlPrintObj);
  237. if (SUCCEEDED(hr))
  238. {
  239. LPCONTEXTMENU pcm;
  240. // Get a pointer to the Printer folder's IContextMenu interface.
  241. hr = pshfPrinters->GetUIObjectOf(GetSafeHwnd(), 1, (LPCITEMIDLIST*)&pidlPrintObj, IID_IContextMenu, NULL, (LPVOID*)&pcm);
  242. if (SUCCEEDED(hr))
  243. {
  244. // Create a popup menu to hold the items in the context menu.
  245. HMENU hMenu = CreatePopupMenu();
  246. if (hMenu != NULL)
  247. {
  248. // Fill the menu.
  249. hr = pcm->QueryContextMenu(hMenu, 0, 1, 0x7FFF, CMF_EXPLORE);
  250. if (SUCCEEDED(hr))
  251. {
  252. CString strCmd(CMDSTR_NEWFOLDER);
  253. CHAR szCmd[MAX_PATH + 1];
  254. int i, nCmd, nItems = ::GetMenuItemCount(hMenu);
  255. for (i = 0; i < nItems; i++)
  256. {
  257. // Search through the menu to find the language-independent
  258. // identifier for the Add Printer object's Open command.
  259. nCmd = GetMenuItemID(hMenu, i);
  260. hr = pcm->GetCommandString(i, GCS_VERB, NULL, szCmd, MAX_PATH);
  261. TCHAR wStr[255];
  262. memcpy(wStr, szCmd, 255);
  263. if (SUCCEEDED(hr) && strCmd == wStr)
  264. {
  265. CMINVOKECOMMANDINFO cmi;
  266. cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
  267. cmi.fMask = 0;
  268. cmi.hwnd = GetSafeHwnd();
  269. cmi.lpVerb = (LPSTR)MAKEINTRESOURCE(nCmd - 1);
  270. cmi.lpParameters = NULL;
  271. cmi.lpDirectory = NULL;
  272. cmi.nShow = SW_SHOW;
  273. cmi.dwHotKey = 0;
  274. cmi.hIcon = NULL;
  275. // Invoke the Open command.
  276. hr = pcm->InvokeCommand(&cmi);
  277. // Exit the loop.
  278. break;
  279. if (FAILED(hr))
  280. {
  281. TRACE(_T("IContextMenu::InvokeCommand failed.\n"));
  282. bReturn = FALSE;
  283. }
  284. }
  285. else
  286. {
  287. TRACE(_T("IContextMenu::GetCommandString failed.\n"));
  288. bReturn = FALSE;
  289. }
  290. }
  291. pcm->Release();
  292. }
  293. else
  294. {
  295. TRACE(_T("IShellFolder::GetUIObjectOf failed.\n"));
  296. bReturn = FALSE;
  297. }
  298. // Destroy the temporary menu.
  299. if (!DestroyMenu(hMenu))
  300. TRACE(_T("DestroyMenu failed.\n"));
  301. }
  302. else
  303. {
  304. TRACE(_T("CreatePopupMenu failed.\n"));
  305. bReturn = FALSE;
  306. }
  307. }
  308. // Release the IShellFolder interface for the Printers folder.
  309. pshfPrinters->Release();
  310. }
  311. // Free the PIDL for the Add Printer object.
  312. pMalloc->Free(pidlPrintObj);
  313. }
  314. else
  315. {
  316. TRACE(_T("IShellFolder::BindToObject failed.\n"));
  317. bReturn = FALSE;
  318. }
  319. // Free the PIDL for the Printers folder.
  320. pMalloc->Free(pidlPrintFolder);
  321. }
  322. else
  323. {
  324. TRACE(_T("SHGetSpecialFolderLocation failed.\n"));
  325. bReturn = FALSE;
  326. }
  327. // Release the pointer to the shell's IShellFolder interface.
  328. pshf->Release();
  329. }
  330. else
  331. {
  332. TRACE(_T("SHGetDesktopFolder failed.\n"));
  333. bReturn = FALSE;
  334. }
  335. // Release the pointer to the shell's IMalloc interface.
  336. pMalloc->Release();
  337. }
  338. else
  339. {
  340. TRACE(_T("SHGetMalloc failed.\n"));
  341. bReturn = FALSE;
  342. }
  343. return bReturn;
  344. }
  345. HRESULT CWizList::GetAddPrinterObject(LPSHELLFOLDER pshf, LPITEMIDLIST* ppidl)
  346. {
  347. HRESULT hr;
  348. LPENUMIDLIST pEnum;
  349. LPMALLOC pMalloc;
  350. // Get a pointer to the shell's IMalloc interface.
  351. hr = SHGetMalloc(&pMalloc);
  352. if (SUCCEEDED(hr))
  353. {
  354. // Get a pointer to the folder's IEnumIDList interface.
  355. hr = pshf->EnumObjects(GetSafeHwnd(), SHCONTF_NONFOLDERS, &pEnum);
  356. if (SUCCEEDED(hr))
  357. {
  358. STRRET str;
  359. CString strPrintObj, strEnumObj;
  360. // Load the display name for the Add Printer object.
  361. strPrintObj.LoadString(IDS_ADD_PRINTER);
  362. // Enumerate the objects in the Printers folder.
  363. while (pEnum->Next(1, ppidl, NULL) == NOERROR)
  364. {
  365. // Get the display name for the object.
  366. hr = pshf->GetDisplayNameOf((LPCITEMIDLIST)*ppidl, SHGDN_INFOLDER, &str);
  367. if (SUCCEEDED(hr))
  368. {
  369. // Copy the display name to the strEnumObj string.
  370. switch (str.uType)
  371. {
  372. case STRRET_CSTR:
  373. strEnumObj = str.cStr;
  374. break;
  375. case STRRET_OFFSET:
  376. char pStr[255];
  377. strcpy(pStr, (LPCSTR)(((UINT_PTR)*ppidl) + str.uOffset));
  378. TCHAR wStr[255];
  379. mbstowcs(wStr, pStr, 255);
  380. strEnumObj = wStr;
  381. break;
  382. case STRRET_WSTR:
  383. strEnumObj = str.pOleStr;
  384. break;
  385. case 0x04: //STRRET_OFFSETW
  386. strEnumObj = (LPCTSTR)(((UINT_PTR)*ppidl) + str.uOffset);
  387. break;
  388. case 0x05:
  389. {
  390. TCHAR pStr[255];
  391. memcpy(pStr, str.cStr, 255);
  392. strEnumObj = pStr;
  393. break;
  394. }
  395. default:
  396. strEnumObj.Empty();
  397. }
  398. // If we found the correct object, exit the loop.
  399. if (strPrintObj == strEnumObj)
  400. break;
  401. // Free the PIDL returned by IEnumIDList::Next().
  402. pMalloc->Free(*ppidl);
  403. if (FAILED(hr))
  404. {
  405. TRACE(_T("IMalloc::Free failed.\n"));
  406. break;
  407. }
  408. }
  409. else
  410. {
  411. TRACE(_T("IShellFolder::GetDisplayNameOf failed.\n"));
  412. }
  413. }
  414. // Release the IEnumIDList pointer.
  415. pEnum->Release();
  416. }
  417. else
  418. {
  419. TRACE(_T("IShellFolder::EnumObjects failed.\n"));
  420. }
  421. // Release the IMalloc pointer.
  422. pMalloc->Release();
  423. }
  424. return hr;
  425. }
  426. void CWizList::OnSetfocus()
  427. {
  428. // tell the other guy not to show any selection
  429. m_pOtherGuy->SetCurSel(-1);
  430. }