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.

483 lines
13 KiB

  1. ///////////////////
  2. // (C) COPYRIGHT MICROSOFT CORP., 1998-2002
  3. //
  4. // FILE: SHELLEXT.CPP
  5. //
  6. // DESCRIPTION: Implements IContextMenu and IShellPropSheetExt interfaces for
  7. // the WIA test camera device
  8. //
  9. #include "precomp.h"
  10. #pragma hdrstop
  11. // Define a language-independent name for our menu verb
  12. static const CHAR g_PathVerbA[] = "ChangeRoot";
  13. static const WCHAR g_PathVerbW[] = L"ChangeRoot";
  14. #if !defined(ARRAYSIZE)
  15. #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
  16. #endif
  17. /*****************************************************************************
  18. CShellExt::CShellExt
  19. ******************************************************************************/
  20. CShellExt :: CShellExt ()
  21. {
  22. }
  23. /*****************************************************************************
  24. CShellExt::~CShellExt
  25. ******************************************************************************/
  26. CShellExt::~CShellExt ()
  27. {
  28. }
  29. /*****************************************************************************
  30. CShellExt::Initialize
  31. Called by the shell when the user invokes context menu or property sheet for
  32. one of our items. For context menus the dataobject may include more than one
  33. selected item.
  34. ******************************************************************************/
  35. STDMETHODIMP CShellExt::Initialize (LPCITEMIDLIST pidlFolder,
  36. LPDATAOBJECT lpdobj,
  37. HKEY hkeyProgID)
  38. {
  39. LONG lType = 0;
  40. HRESULT hr = NOERROR;
  41. if (!lpdobj)
  42. {
  43. return E_INVALIDARG;
  44. }
  45. // For singular selections, the WIA namespace should always provide a
  46. // dataobject that also supports IWiaItem
  47. if (FAILED(lpdobj->QueryInterface (IID_IWiaItem, reinterpret_cast<LPVOID*>(&m_pItem))))
  48. {
  49. // failing that, get the list of selected items from the data object
  50. UINT uItems = 0;
  51. LPWSTR szName;
  52. LPWSTR szToken;
  53. IWiaItem *pDevice;
  54. szName = GetNamesFromDataObject (lpdobj, &uItems);
  55. // we only support singular objects
  56. if (uItems != 1)
  57. {
  58. hr = E_FAIL;
  59. }
  60. else
  61. {
  62. // The name is of this format: <device id>::<item name>
  63. szToken = wcstok (szName, L":");
  64. if (!szToken)
  65. {
  66. hr = E_FAIL;
  67. }
  68. // Our extension only supports root items, so make sure there's no item
  69. // name
  70. else if (wcstok (NULL, L":"))
  71. {
  72. hr = E_FAIL;
  73. }
  74. else
  75. {
  76. hr = CreateDeviceFromId (szToken, &m_pItem);
  77. }
  78. }
  79. if (szName)
  80. {
  81. delete [] szName;
  82. }
  83. }
  84. if (SUCCEEDED(hr))
  85. {
  86. m_pItem->GetItemType (&lType);
  87. if (!(lType & WiaItemTypeRoot))
  88. {
  89. hr = E_FAIL; // we only support changing the property on the root item
  90. }
  91. }
  92. return hr;
  93. }
  94. /*****************************************************************************
  95. CShellExt::AddPages
  96. Called by the shell to get our property pages.
  97. ******************************************************************************/
  98. STDMETHODIMP CShellExt::AddPages (LPFNADDPROPSHEETPAGE lpfnAddPage,LPARAM lParam)
  99. {
  100. HPROPSHEETPAGE hpsp;
  101. PROPSHEETPAGE psp;
  102. HRESULT hr = E_FAIL;
  103. // We only have 1 page.
  104. psp.dwSize = sizeof(psp);
  105. psp.dwFlags = PSP_DEFAULT;
  106. psp.hInstance = g_hInst;
  107. psp.pszTemplate = MAKEINTRESOURCE(IDD_DEVICE_PROPPAGE);
  108. psp.pfnDlgProc = PropPageProc;
  109. psp.lParam = reinterpret_cast<LPARAM>(this);
  110. hpsp = CreatePropertySheetPage (&psp);
  111. if (hpsp)
  112. {
  113. hr = (*lpfnAddPage) (hpsp, lParam) ? S_OK:E_FAIL;
  114. if (SUCCEEDED(hr))
  115. {
  116. InternalAddRef (); // the propsheetpage will release us when it is destroyed
  117. }
  118. }
  119. return E_FAIL;
  120. }
  121. /*****************************************************************************
  122. CShellExt::QueryContextMenu
  123. Called by the shell to get our context menu strings for the selected item.
  124. ******************************************************************************/
  125. STDMETHODIMP CShellExt::QueryContextMenu (HMENU hmenu,UINT indexMenu,UINT idCmdFirst,UINT idCmdLast,UINT uFlags)
  126. {
  127. MENUITEMINFO mii = {0};
  128. TCHAR szPathRoot[MAX_PATH];
  129. // insert our only menu item at index indexMenu. Remember the cmd value.
  130. LoadString (g_hInst, ID_CHANGEROOT, szPathRoot, MAX_PATH);
  131. mii.cbSize = sizeof(mii);
  132. mii.fMask = MIIM_STRING | MIIM_ID;
  133. mii.fState = MFS_ENABLED;
  134. mii.wID = idCmdFirst;
  135. mii.dwTypeData = szPathRoot;
  136. m_idCmd = 0; // we only have 1 item.
  137. if (InsertMenuItem (hmenu, indexMenu, TRUE, &mii))
  138. {
  139. return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 1);
  140. }
  141. return E_FAIL;
  142. }
  143. /*****************************************************************************
  144. CShellExt::InvokeCommand
  145. Called by the shell when the user clicks one of our menu items
  146. ******************************************************************************/
  147. STDMETHODIMP CShellExt::InvokeCommand (LPCMINVOKECOMMANDINFO lpici)
  148. {
  149. UINT_PTR idCmd = reinterpret_cast<UINT_PTR>(lpici->lpVerb);
  150. if (idCmd == m_idCmd)
  151. {
  152. return GetNewRootPath (lpici->hwnd);
  153. }
  154. // it wasn't our verb.
  155. return E_FAIL;
  156. }
  157. /*****************************************************************************
  158. CShellExt::GetCommandString
  159. Called by the shell to get our language independent verb name.
  160. ******************************************************************************/
  161. STDMETHODIMP CShellExt::GetCommandString (UINT_PTR idCmd, UINT uType,UINT* pwReserved,LPSTR pszName,UINT cchMax)
  162. {
  163. if (idCmd != m_idCmd)
  164. {
  165. // not our verb
  166. return E_FAIL;
  167. }
  168. switch (uType)
  169. {
  170. case GCS_VALIDATEA:
  171. if (pszName)
  172. {
  173. lstrcpynA (pszName, g_PathVerbA, cchMax);
  174. }
  175. return S_OK;
  176. case GCS_VALIDATEW:
  177. if (pszName)
  178. {
  179. lstrcpynW (reinterpret_cast<LPWSTR>(pszName), g_PathVerbW, cchMax);
  180. }
  181. return S_OK;
  182. case GCS_VERBA:
  183. lstrcpynA (pszName, g_PathVerbA, cchMax);
  184. break;
  185. case GCS_VERBW:
  186. lstrcpynW (reinterpret_cast<LPWSTR>(pszName), g_PathVerbW, cchMax);
  187. break;
  188. default:
  189. return E_FAIL;
  190. }
  191. return NOERROR;
  192. }
  193. /*****************************************************************************
  194. GetSetRootPath
  195. Utility function for setting or retrieving the test camera's root path property
  196. ******************************************************************************/
  197. HRESULT GetSetRootPath (IWiaItem *pCamera, LPTSTR pszPath, int cchMax, BOOL bSet)
  198. {
  199. IWiaPropertyStorage *pps;
  200. HRESULT hr;
  201. PROPVARIANT pv = {0};
  202. PROPSPEC ps;
  203. ps.ulKind = PRSPEC_PROPID;
  204. ps.propid = WIA_DPP_TCAM_ROOT_PATH;
  205. hr = pCamera->QueryInterface (IID_IWiaPropertyStorage, reinterpret_cast<LPVOID*>(&pps));
  206. if (SUCCEEDED(hr))
  207. {
  208. if (!bSet) // retrieval
  209. {
  210. *pszPath = TEXT('\0');
  211. hr = pps->ReadMultiple (1, &ps, &pv);
  212. if (SUCCEEDED(hr))
  213. {
  214. #ifdef UNICODE
  215. lstrcpyn (pszPath, pv.bstrVal, cchMax);
  216. #else
  217. WideCharToMultiByte (CP_ACP, 0,
  218. pv.bstrVal, -1,
  219. pszPath, cchMax,
  220. NULL, NULL);
  221. #endif //UNICODE
  222. PropVariantClear(&pv);
  223. }
  224. }
  225. else // assignment
  226. {
  227. pv.vt = VT_BSTR;
  228. #ifdef UNICODE
  229. pv.bstrVal =SysAllocString ( pszPath);
  230. #else
  231. INT len = lstrlen(pszPath);
  232. LPWSTR pwszVal = new WCHAR[len+1];
  233. if (pwszVal)
  234. {
  235. MultiByteToWideChar (CP_ACP, 0, pszPath, -1, pwszVal, len+1);
  236. pv.bstrVal =SysAllocString ( pwszVal);
  237. delete [] pwszVal;
  238. }
  239. #endif // UNICODE
  240. if (!pv.bstrVal)
  241. {
  242. hr = E_OUTOFMEMORY;
  243. }
  244. if (SUCCEEDED(hr))
  245. {
  246. hr = pps->WriteMultiple (1, &ps, &pv, 2);
  247. }
  248. PropVariantClear(&pv);
  249. }
  250. }
  251. if (pps)
  252. {
  253. pps->Release ();
  254. }
  255. return hr;
  256. }
  257. /*****************************************************************************
  258. CShellExt::PropPageProc
  259. Dialog procedure for the simple property sheet page.
  260. ******************************************************************************/
  261. INT_PTR CALLBACK CShellExt::PropPageProc (HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
  262. {
  263. CShellExt *pThis;
  264. pThis = reinterpret_cast<CShellExt *>(GetWindowLongPtr (hwnd, DWLP_USER));
  265. TCHAR szPath[MAX_PATH] ;
  266. INT_PTR iRet = TRUE;
  267. switch (msg)
  268. {
  269. case WM_INITDIALOG:
  270. pThis = reinterpret_cast<CShellExt *>(reinterpret_cast<LPPROPSHEETPAGE>(lp)->lParam);
  271. SetWindowLongPtr (hwnd, DWLP_USER, reinterpret_cast<LONG_PTR>(pThis));
  272. GetSetRootPath (pThis->m_pItem, szPath, ARRAYSIZE(szPath), FALSE);
  273. SetDlgItemText (hwnd, IDC_IMAGEROOT, szPath);
  274. break;
  275. case WM_COMMAND:
  276. if (LOWORD(wp) == IDC_IMAGEROOT && HIWORD(wp) == EN_CHANGE)
  277. {
  278. SendMessage(GetParent(hwnd),
  279. PSM_CHANGED,
  280. reinterpret_cast<WPARAM>(hwnd), 0);
  281. return TRUE;
  282. }
  283. iRet = FALSE;
  284. break;
  285. case WM_NOTIFY:
  286. {
  287. LONG lCode = PSNRET_NOERROR;
  288. LPPSHNOTIFY psn = reinterpret_cast<LPPSHNOTIFY>(lp);
  289. switch (psn->hdr.code)
  290. {
  291. case PSN_APPLY:
  292. // Set the new root path property
  293. GetDlgItemText (hwnd, IDC_IMAGEROOT, szPath, MAX_PATH);
  294. if (FAILED(GetSetRootPath (pThis->m_pItem, szPath, ARRAYSIZE(szPath), TRUE)))
  295. {
  296. ::ShowMessage (hwnd, IDS_ERRCAPTION, IDS_ERRPROPSET);
  297. lCode = PSNRET_INVALID_NOCHANGEPAGE;
  298. }
  299. break;
  300. case PSN_KILLACTIVE:
  301. // Validate the new path is valid
  302. GetDlgItemText (hwnd, IDC_IMAGEROOT, szPath, MAX_PATH);
  303. if (! (GetFileAttributes(szPath) & FILE_ATTRIBUTE_DIRECTORY))
  304. {
  305. ::ShowMessage (hwnd, IDS_ERRCAPTION, IDS_BADPATH);
  306. lCode = TRUE;
  307. }
  308. break;
  309. default:
  310. iRet = FALSE;
  311. break;
  312. }
  313. SetWindowLongPtr (hwnd, DWLP_MSGRESULT, lCode);
  314. }
  315. break;
  316. case WM_CLOSE:
  317. pThis->InternalRelease ();
  318. break;
  319. default:
  320. iRet = FALSE;
  321. break;
  322. }
  323. return iRet;
  324. }
  325. /*****************************************************************************
  326. BrowseCallback
  327. Sets the default selection in the folder selection dialog to the current
  328. camera image root path
  329. ******************************************************************************/
  330. INT CALLBACK BrowseCallback (HWND hwnd, UINT msg, LPARAM lp, WPARAM wp)
  331. {
  332. IWiaItem *pItem = reinterpret_cast<IWiaItem*>(lp);
  333. if (BFFM_INITIALIZED == msg)
  334. {
  335. TCHAR szPath[MAX_PATH];
  336. // find the current root path
  337. GetSetRootPath (pItem, szPath, ARRAYSIZE(szPath), FALSE);
  338. // send the appropriate message to the dialog
  339. SendMessage (hwnd,
  340. BFFM_SETSELECTION,
  341. reinterpret_cast<LPARAM>(szPath),
  342. TRUE);
  343. }
  344. return 0;
  345. }
  346. /*****************************************************************************
  347. CShellExt::GetNewRootPath
  348. Invoked in response to choosing our context menu item
  349. ******************************************************************************/
  350. HRESULT CShellExt::GetNewRootPath(HWND hwnd)
  351. {
  352. BROWSEINFO bi = {0};
  353. LPITEMIDLIST pidl;
  354. TCHAR szPath[MAX_PATH];
  355. TCHAR szTitle[MAX_PATH];
  356. // Init the dialog with the current path
  357. LoadString (g_hInst, IDS_BROWSETITLE, szTitle, MAX_PATH);
  358. bi.hwndOwner = hwnd;
  359. bi.pidlRoot = NULL;
  360. bi.pszDisplayName = szPath;
  361. bi.lpszTitle = szTitle;
  362. bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_USENEWUI | BIF_EDITBOX;
  363. bi.lpfn = NULL;
  364. pidl = SHBrowseForFolder (&bi);
  365. if (pidl)
  366. {
  367. SHGetPathFromIDList (pidl, szPath);
  368. CoTaskMemFree(pidl);
  369. if (FAILED(GetSetRootPath (m_pItem, szPath, ARRAYSIZE(szPath), TRUE)))
  370. {
  371. ::ShowMessage (hwnd, IDS_ERRCAPTION, IDS_ERRPROPSET);
  372. return S_FALSE;
  373. }
  374. return NOERROR;
  375. }
  376. return S_FALSE; // don't return failure code to the shell.
  377. }