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.

550 lines
18 KiB

  1. /*******************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORPORATION, 1998-2000
  4. *
  5. * TITLE: MINTRANS.CPP
  6. *
  7. * VERSION: 1.0
  8. *
  9. * AUTHOR: ShaunIv
  10. *
  11. * DATE: 12/6/1999
  12. *
  13. * DESCRIPTION:
  14. *
  15. *******************************************************************************/
  16. #include "precomp.h"
  17. #pragma hdrstop
  18. #include <initguid.h>
  19. #include <wiaregst.h>
  20. #include <shlguid.h>
  21. #include "shellext.h"
  22. #include "shlobj.h"
  23. #include "resource.h" // resource ids
  24. #include "itranhlp.h"
  25. #include "mintrans.h"
  26. #include "comctrlp.h"
  27. #include "shlwapip.h"
  28. #include "acqmgrcw.h"
  29. namespace
  30. {
  31. //
  32. // Define constants for dwords stored in the registry
  33. #define ACTION_RUNAPP 0
  34. #define ACTION_AUTOSAVE 1
  35. #define ACTION_NOTHING 2
  36. #define ACTION_MAX 2
  37. static const TCHAR c_szConnectionSettings[] = TEXT("OnConnect\\%ls");
  38. struct CMinimalTransferSettings
  39. {
  40. DWORD dwAction;
  41. BOOL bDeleteImages;
  42. CSimpleString strFolderPath;
  43. CComPtr<IWiaTransferHelper> pXfer;
  44. BOOL bSaveInDatedDir;
  45. };
  46. #ifndef REGSTR_VALUE_USEDATE
  47. #define REGSTR_VALUE_USEDATE TEXT("UseDate")
  48. #endif
  49. /*******************************************************************************
  50. ConstructDatedFolderPath
  51. Concatenate the date to an existing folder name
  52. *******************************************************************************/
  53. static
  54. CSimpleString
  55. ConstructDatedFolderPath(
  56. const CSimpleString &strOriginal
  57. )
  58. {
  59. CSimpleString strPath = strOriginal;
  60. //
  61. // Get the current date and format it as a string
  62. //
  63. SYSTEMTIME SystemTime;
  64. TCHAR szDate[MAX_PATH] = TEXT("");
  65. GetLocalTime( &SystemTime );
  66. GetDateFormat( LOCALE_USER_DEFAULT, 0, &SystemTime, CSimpleString(IDS_DATEFORMAT,g_hInstance), szDate, ARRAYSIZE(szDate) );
  67. //
  68. // Make sure there is a trailing backslash
  69. //
  70. if (!strPath.MatchLastCharacter( TEXT('\\')))
  71. {
  72. strPath += CSimpleString(TEXT("\\"));
  73. }
  74. //
  75. // Append the date
  76. //
  77. strPath += szDate;
  78. return strPath;
  79. }
  80. /////////////////////////////////////////////////////////////////////////////
  81. // CPersistCallback and helpers
  82. /*******************************************************************************
  83. CheckAndCreateFolder
  84. Make sure the target path exists or can be created. Failing that, prompt the
  85. user for a folder.
  86. *******************************************************************************/
  87. void
  88. CheckAndCreateFolder (CSimpleString &strFolderPath)
  89. {
  90. // Convert to a full path name. If strFolderPath is not a full path,
  91. // we want it to be a subfolder of My Pictures
  92. TCHAR szFullPath[MAX_PATH] = TEXT("");
  93. SHGetFolderPath (NULL, CSIDL_MYPICTURES, NULL, 0, szFullPath);
  94. LPTSTR szUnused;
  95. BOOL bPrompt = false;
  96. if (*szFullPath)
  97. {
  98. SetCurrentDirectory (szFullPath);
  99. }
  100. GetFullPathName (strFolderPath, ARRAYSIZE(szFullPath), szFullPath, &szUnused);
  101. strFolderPath = szFullPath;
  102. // make sure the folder exists
  103. DWORD dw = GetFileAttributes(strFolderPath);
  104. if (dw == 0xffffffff)
  105. {
  106. bPrompt = !CAcquisitionManagerControllerWindow::RecursiveCreateDirectory( strFolderPath );
  107. }
  108. else if (!(dw & FILE_ATTRIBUTE_DIRECTORY))
  109. {
  110. bPrompt = TRUE;
  111. }
  112. // Ask the user for a valid folder
  113. if (bPrompt)
  114. {
  115. BROWSEINFO bi;
  116. TCHAR szPath[MAX_PATH] = TEXT("\0");
  117. LPITEMIDLIST pidl;
  118. TCHAR szTitle[200];
  119. LoadString (g_hInstance,
  120. IDS_MINTRANS_FOLDERPATH_CAPTION,
  121. szTitle,
  122. 200);
  123. ZeroMemory (&bi, sizeof(bi));
  124. bi.hwndOwner = NULL;
  125. bi.lpszTitle = szTitle;
  126. bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_USENEWUI;
  127. pidl = SHBrowseForFolder (&bi);
  128. if (pidl)
  129. {
  130. SHGetPathFromIDList (pidl, szPath);
  131. }
  132. strFolderPath = szPath;
  133. }
  134. }
  135. /*******************************************************************************
  136. GetSaveSettings
  137. Find out what the user configured us to do with the images
  138. *******************************************************************************/
  139. void
  140. GetSaveSettings (CMinimalTransferSettings &settings, BSTR bstrDeviceId)
  141. {
  142. CSimpleReg regSettings(HKEY_CURRENT_USER,
  143. REGSTR_PATH_USER_SETTINGS,
  144. true,
  145. KEY_READ);
  146. // Default to My Pictures/no delete if registry settings not there
  147. TCHAR szMyPictures[MAX_PATH];
  148. SHGetFolderPath (NULL, CSIDL_MYPICTURES, NULL, 0, szMyPictures);
  149. settings.bDeleteImages = 0;
  150. settings.strFolderPath = const_cast<LPCTSTR>(szMyPictures);
  151. settings.dwAction = ACTION_RUNAPP;
  152. settings.bSaveInDatedDir = FALSE;
  153. // BUGBUG: Should we prompt the user if the registry path
  154. // isn't set?
  155. if (regSettings.OK())
  156. {
  157. CSimpleString strSubKey;
  158. strSubKey.Format (c_szConnectionSettings, bstrDeviceId);
  159. CSimpleReg regActions (regSettings, strSubKey, true, KEY_READ);
  160. settings.bDeleteImages = regActions.Query (REGSTR_VALUE_AUTODELETE, 0);
  161. settings.strFolderPath = regActions.Query (REGSTR_VALUE_SAVEFOLDER,
  162. CSimpleString(szMyPictures));
  163. settings.dwAction = regActions.Query (REGSTR_VALUE_CONNECTACT,
  164. ACTION_AUTOSAVE);
  165. settings.bSaveInDatedDir = (regActions.Query(REGSTR_VALUE_USEDATE,0) != 0);
  166. if (settings.bSaveInDatedDir)
  167. {
  168. settings.strFolderPath = ConstructDatedFolderPath( settings.strFolderPath );
  169. }
  170. }
  171. }
  172. // For the short term, have an array of format/extension pairs
  173. struct MYFMTS
  174. {
  175. const GUID *pFmt;
  176. LPCWSTR pszExt;
  177. } FMTS [] =
  178. {
  179. {&WiaImgFmt_BMP, L".bmp"},
  180. {&WiaImgFmt_JPEG, L".jpg"},
  181. {&WiaImgFmt_FLASHPIX, L".fpx"},
  182. {&WiaImgFmt_TIFF, L".tif"},
  183. {NULL, L""}
  184. };
  185. /*******************************************************************************
  186. GetDropTarget
  187. Get an IDropTarget interface for the given folder
  188. *******************************************************************************/
  189. HRESULT
  190. GetDropTarget (IShellFolder *pDesktop, LPCTSTR szPath, IDropTarget **ppDrop)
  191. {
  192. HRESULT hr;
  193. LPITEMIDLIST pidl;
  194. CSimpleStringWide strPath = CSimpleStringConvert::WideString (CSimpleString(szPath));
  195. CComPtr<IShellFolder> psf;
  196. hr = pDesktop->ParseDisplayName(NULL,
  197. NULL,
  198. const_cast<LPWSTR>(static_cast<LPCWSTR>(strPath)),
  199. NULL,
  200. &pidl,
  201. NULL);
  202. if (SUCCEEDED(hr))
  203. {
  204. hr = pDesktop->BindToObject(const_cast<LPCITEMIDLIST>(pidl),
  205. NULL,
  206. IID_IShellFolder,
  207. reinterpret_cast<LPVOID*>(&psf));
  208. if (SUCCEEDED(hr))
  209. {
  210. hr = psf->CreateViewObject (NULL,
  211. IID_IDropTarget,
  212. reinterpret_cast<LPVOID*>(ppDrop));
  213. }
  214. }
  215. return hr;
  216. }
  217. /*******************************************************************************
  218. FreePidl
  219. Called when the array of pidls is destroyed, to free the pidls
  220. *******************************************************************************/
  221. INT
  222. FreePidl (LPITEMIDLIST pidl, IMalloc *pMalloc)
  223. {
  224. pMalloc->Free (pidl);
  225. return 1;
  226. }
  227. HRESULT
  228. SaveItemsFromFolder (IShellFolder *pRoot, CSimpleString &strPath, BOOL bDelete)
  229. {
  230. CComPtr<IEnumIDList> pEnum;
  231. LPITEMIDLIST pidl;
  232. HRESULT hr = S_FALSE;
  233. CComPtr<IMalloc> pMalloc;
  234. if (SUCCEEDED(SHGetMalloc (&pMalloc)))
  235. {
  236. CComPtr<IShellFolder> pDesktop;
  237. if (SUCCEEDED(SHGetDesktopFolder (&pDesktop)))
  238. {
  239. // enum the non-folder objects first
  240. if (SUCCEEDED(pRoot->EnumObjects (NULL,
  241. SHCONTF_FOLDERS | SHCONTF_NONFOLDERS ,
  242. &pEnum)))
  243. {
  244. HDPA dpaItems;
  245. dpaItems = DPA_Create(10);
  246. while (NOERROR == pEnum->Next(1, &pidl, NULL))
  247. {
  248. DPA_AppendPtr (dpaItems, pidl);
  249. }
  250. //
  251. // Now create the array of pidls and get the IDataObject
  252. //
  253. INT nSize = DPA_GetPtrCount (dpaItems);
  254. if (nSize > 0)
  255. {
  256. LPITEMIDLIST *aidl = new LPITEMIDLIST[nSize];
  257. if (aidl)
  258. {
  259. CComPtr<IDataObject> pdo;
  260. for (INT i=0;i<nSize;i++)
  261. {
  262. aidl[i] = reinterpret_cast<LPITEMIDLIST>(DPA_FastGetPtr(dpaItems, i));
  263. }
  264. hr = pRoot->GetUIObjectOf (NULL,
  265. nSize,
  266. const_cast<LPCITEMIDLIST*>(aidl),
  267. IID_IDataObject,
  268. NULL,
  269. reinterpret_cast<LPVOID*>(&pdo));
  270. if (SUCCEEDED(hr))
  271. {
  272. CComPtr<IDropTarget> pDrop;
  273. CComQIPtr<IAsyncOperation, &IID_IAsyncOperation> pasync(pdo);
  274. if (pasync.p)
  275. {
  276. pasync->SetAsyncMode(FALSE);
  277. }
  278. CheckAndCreateFolder (strPath);
  279. if (strPath.Length())
  280. {
  281. //
  282. // Get an IDropTarget for the destination folder
  283. // and do the drag/drop
  284. //
  285. hr = GetDropTarget (pDesktop,
  286. strPath,
  287. &pDrop);
  288. }
  289. else
  290. {
  291. hr = S_FALSE;
  292. }
  293. if (S_OK == hr)
  294. {
  295. DWORD dwKeyState;
  296. if (bDelete)
  297. {
  298. // the "move" keys
  299. dwKeyState = MK_SHIFT | MK_LBUTTON;
  300. }
  301. else
  302. { // the copy keys
  303. dwKeyState = MK_CONTROL|MK_LBUTTON;
  304. }
  305. hr = SHSimulateDrop (pDrop,
  306. pdo,
  307. dwKeyState,
  308. NULL,
  309. NULL);
  310. }
  311. }
  312. }
  313. else
  314. {
  315. hr = E_OUTOFMEMORY;
  316. }
  317. }
  318. else
  319. {
  320. hr = S_FALSE; // no images to download
  321. }
  322. DPA_DestroyCallback (dpaItems,
  323. reinterpret_cast<PFNDPAENUMCALLBACK>(FreePidl),
  324. reinterpret_cast<LPVOID>(pMalloc.p));
  325. }
  326. }
  327. }
  328. return hr;
  329. }
  330. /*******************************************************************************
  331. SaveItems
  332. This function uses IShellFolder and IDataObject interfaces to simulate
  333. a drag/drop operation from the WIA virtual folder for the given device.
  334. *******************************************************************************/
  335. #define STR_WIASHEXT TEXT("wiashext.dll")
  336. static
  337. HRESULT
  338. SaveItems (BSTR strDeviceId, CMinimalTransferSettings &settings)
  339. {
  340. WIA_PUSH_FUNCTION((TEXT("SaveItems( %ws, ... )"), strDeviceId ));
  341. CComPtr<IShellFolder>pRoot;
  342. HRESULT hr = SHGetDesktopFolder (&pRoot);
  343. if (SUCCEEDED(hr))
  344. {
  345. //
  346. // Get the system directory, which is where wiashext.dll lives
  347. //
  348. TCHAR szShellExtensionPath[MAX_PATH] = {0};
  349. if (GetSystemDirectory( szShellExtensionPath, ARRAYSIZE(szShellExtensionPath)))
  350. {
  351. //
  352. // Make sure the path variable is long enough to hold this path
  353. //
  354. if (lstrlen(szShellExtensionPath) + lstrlen(STR_WIASHEXT) + lstrlen(TEXT("\\")) < ARRAYSIZE(szShellExtensionPath))
  355. {
  356. //
  357. // Concatenate the backslash and module name to the system path
  358. //
  359. lstrcat( szShellExtensionPath, TEXT("\\") );
  360. lstrcat( szShellExtensionPath, STR_WIASHEXT );
  361. //
  362. // Load the DLL
  363. //
  364. HINSTANCE hInstanceShellExt = LoadLibrary(szShellExtensionPath);
  365. if (hInstanceShellExt)
  366. {
  367. //
  368. // Get the pidl making function
  369. //
  370. WIAMAKEFULLPIDLFORDEVICE pfnMakeFullPidlForDevice = reinterpret_cast<WIAMAKEFULLPIDLFORDEVICE>(GetProcAddress(hInstanceShellExt, "MakeFullPidlForDevice"));
  371. if (pfnMakeFullPidlForDevice)
  372. {
  373. //
  374. // Get the pidl
  375. //
  376. LPITEMIDLIST pidlDevice = NULL;
  377. hr = pfnMakeFullPidlForDevice( strDeviceId, &pidlDevice );
  378. if (SUCCEEDED(hr))
  379. {
  380. //
  381. // Bind to the folder for this device
  382. //
  383. CComPtr<IShellFolder> pDevice;
  384. hr = pRoot->BindToObject (const_cast<LPCITEMIDLIST> (pidlDevice), NULL, IID_IShellFolder, reinterpret_cast<LPVOID*>(&pDevice));
  385. if (SUCCEEDED(hr))
  386. {
  387. hr = SaveItemsFromFolder (pDevice, settings.strFolderPath, settings.bDeleteImages);
  388. if (S_OK == hr && settings.bDeleteImages)
  389. {
  390. //
  391. // DoDeleteAllItems will pop up a dialog to confirm the delete.
  392. //
  393. DoDeleteAllItems (strDeviceId, NULL);
  394. }
  395. }
  396. else
  397. {
  398. WIA_PRINTHRESULT((hr,TEXT("BindToObject failed!")));
  399. }
  400. CComPtr<IMalloc> pMalloc;
  401. if (SUCCEEDED(SHGetMalloc(&pMalloc)) && pMalloc)
  402. {
  403. pMalloc->Free(pidlDevice);
  404. }
  405. }
  406. else
  407. {
  408. WIA_PRINTHRESULT((hr,TEXT("MakeFullPidlForDevice failed!")));
  409. }
  410. }
  411. else
  412. {
  413. hr = HRESULT_FROM_WIN32(GetLastError());
  414. WIA_PRINTHRESULT((hr,TEXT("GetProcAddress for MakeFullPidlForDevice failed!")));
  415. }
  416. FreeLibrary(hInstanceShellExt);
  417. }
  418. else
  419. {
  420. hr = HRESULT_FROM_WIN32(GetLastError());
  421. WIA_PRINTHRESULT((hr,TEXT("Unable to load wiashext.dll!")));
  422. }
  423. }
  424. else
  425. {
  426. hr = E_FAIL;
  427. WIA_PRINTHRESULT((hr,TEXT("Buffer size was too small")));
  428. }
  429. }
  430. else
  431. {
  432. hr = HRESULT_FROM_WIN32(GetLastError());
  433. WIA_PRINTHRESULT((hr,TEXT("Unable to get system folder!")));
  434. }
  435. }
  436. else
  437. {
  438. WIA_PRINTHRESULT((hr,TEXT("SHGetDesktopFolder failed!")));
  439. }
  440. return hr;
  441. }
  442. } // End namespace MinimalTransfer
  443. LRESULT
  444. MinimalTransferThreadProc (BSTR bstrDeviceId)
  445. {
  446. if (bstrDeviceId)
  447. {
  448. CMinimalTransferSettings settings;
  449. HRESULT hr = CoInitialize(NULL);
  450. if (SUCCEEDED(hr))
  451. {
  452. GetSaveSettings (settings, bstrDeviceId);
  453. // Bail if the default action is donothing or if the user cancelled
  454. // the browse for folder
  455. if (settings.dwAction == ACTION_AUTOSAVE)
  456. {
  457. hr = SaveItems (bstrDeviceId, settings);
  458. // Show the folder the user saved to
  459. if (NOERROR == hr)
  460. {
  461. SHELLEXECUTEINFO sei;
  462. ZeroMemory (&sei, sizeof(sei));
  463. sei.cbSize = sizeof(sei);
  464. sei.lpDirectory = settings.strFolderPath;
  465. sei.nShow = SW_SHOW;
  466. ShellExecuteEx (&sei);
  467. }
  468. else if (FAILED(hr))
  469. {
  470. WIA_PRINTHRESULT((hr,TEXT("SaveItems failed!")));
  471. // we can rely on SaveItems reporting errors to the user
  472. }
  473. }
  474. CoUninitialize();
  475. }
  476. #ifndef DBG_GENERATE_PRETEND_EVENT
  477. WIA_TRACE((TEXT("Module::m_nLockCnt: %d"),_Module.m_nLockCnt));
  478. _Module.Unlock();
  479. #endif
  480. SysFreeString(bstrDeviceId);
  481. }
  482. return 0;
  483. }