|
|
/*******************************************************************************
* * (C) COPYRIGHT MICROSOFT CORPORATION, 1998-2000 * * TITLE: MINTRANS.CPP * * VERSION: 1.0 * * AUTHOR: ShaunIv * * DATE: 12/6/1999 * * DESCRIPTION: * *******************************************************************************/ #include "precomp.h"
#pragma hdrstop
#include <initguid.h>
#include <wiaregst.h>
#include <shlguid.h>
#include "shellext.h"
#include "shlobj.h"
#include "resource.h" // resource ids
#include "itranhlp.h"
#include "mintrans.h"
#include "comctrlp.h"
#include "shlwapip.h"
#include "acqmgrcw.h"
namespace {
//
// Define constants for dwords stored in the registry
#define ACTION_RUNAPP 0
#define ACTION_AUTOSAVE 1
#define ACTION_NOTHING 2
#define ACTION_MAX 2
static const TCHAR c_szConnectionSettings[] = TEXT("OnConnect\\%ls");
struct CMinimalTransferSettings { DWORD dwAction; BOOL bDeleteImages; CSimpleString strFolderPath; CComPtr<IWiaTransferHelper> pXfer; BOOL bSaveInDatedDir; };
#ifndef REGSTR_VALUE_USEDATE
#define REGSTR_VALUE_USEDATE TEXT("UseDate")
#endif
/*******************************************************************************
ConstructDatedFolderPath
Concatenate the date to an existing folder name
*******************************************************************************/ static CSimpleString ConstructDatedFolderPath( const CSimpleString &strOriginal ) { CSimpleString strPath = strOriginal;
//
// Get the current date and format it as a string
//
SYSTEMTIME SystemTime; TCHAR szDate[MAX_PATH] = TEXT(""); GetLocalTime( &SystemTime ); GetDateFormat( LOCALE_USER_DEFAULT, 0, &SystemTime, CSimpleString(IDS_DATEFORMAT,g_hInstance), szDate, ARRAYSIZE(szDate) );
//
// Make sure there is a trailing backslash
//
if (!strPath.MatchLastCharacter( TEXT('\\'))) { strPath += CSimpleString(TEXT("\\")); }
//
// Append the date
//
strPath += szDate;
return strPath; }
/////////////////////////////////////////////////////////////////////////////
// CPersistCallback and helpers
/*******************************************************************************
CheckAndCreateFolder
Make sure the target path exists or can be created. Failing that, prompt the user for a folder.
*******************************************************************************/ void CheckAndCreateFolder (CSimpleString &strFolderPath) {
// Convert to a full path name. If strFolderPath is not a full path,
// we want it to be a subfolder of My Pictures
TCHAR szFullPath[MAX_PATH] = TEXT(""); SHGetFolderPath (NULL, CSIDL_MYPICTURES, NULL, 0, szFullPath); LPTSTR szUnused; BOOL bPrompt = false; if (*szFullPath) { SetCurrentDirectory (szFullPath); } GetFullPathName (strFolderPath, ARRAYSIZE(szFullPath), szFullPath, &szUnused); strFolderPath = szFullPath; // make sure the folder exists
DWORD dw = GetFileAttributes(strFolderPath);
if (dw == 0xffffffff) { bPrompt = !CAcquisitionManagerControllerWindow::RecursiveCreateDirectory( strFolderPath ); } else if (!(dw & FILE_ATTRIBUTE_DIRECTORY)) { bPrompt = TRUE; }
// Ask the user for a valid folder
if (bPrompt) { BROWSEINFO bi; TCHAR szPath[MAX_PATH] = TEXT("\0"); LPITEMIDLIST pidl; TCHAR szTitle[200]; LoadString (g_hInstance, IDS_MINTRANS_FOLDERPATH_CAPTION, szTitle, 200); ZeroMemory (&bi, sizeof(bi)); bi.hwndOwner = NULL; bi.lpszTitle = szTitle; bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_USENEWUI; pidl = SHBrowseForFolder (&bi); if (pidl) { SHGetPathFromIDList (pidl, szPath); } strFolderPath = szPath; } }
/*******************************************************************************
GetSaveSettings
Find out what the user configured us to do with the images
*******************************************************************************/
void GetSaveSettings (CMinimalTransferSettings &settings, BSTR bstrDeviceId) {
CSimpleReg regSettings(HKEY_CURRENT_USER, REGSTR_PATH_USER_SETTINGS, true, KEY_READ);
// Default to My Pictures/no delete if registry settings not there
TCHAR szMyPictures[MAX_PATH]; SHGetFolderPath (NULL, CSIDL_MYPICTURES, NULL, 0, szMyPictures); settings.bDeleteImages = 0; settings.strFolderPath = const_cast<LPCTSTR>(szMyPictures); settings.dwAction = ACTION_RUNAPP; settings.bSaveInDatedDir = FALSE;
// BUGBUG: Should we prompt the user if the registry path
// isn't set?
if (regSettings.OK()) {
CSimpleString strSubKey; strSubKey.Format (c_szConnectionSettings, bstrDeviceId); CSimpleReg regActions (regSettings, strSubKey, true, KEY_READ); settings.bDeleteImages = regActions.Query (REGSTR_VALUE_AUTODELETE, 0); settings.strFolderPath = regActions.Query (REGSTR_VALUE_SAVEFOLDER, CSimpleString(szMyPictures)); settings.dwAction = regActions.Query (REGSTR_VALUE_CONNECTACT, ACTION_AUTOSAVE); settings.bSaveInDatedDir = (regActions.Query(REGSTR_VALUE_USEDATE,0) != 0); if (settings.bSaveInDatedDir) { settings.strFolderPath = ConstructDatedFolderPath( settings.strFolderPath ); } }
}
// For the short term, have an array of format/extension pairs
struct MYFMTS { const GUID *pFmt; LPCWSTR pszExt; } FMTS [] = { {&WiaImgFmt_BMP, L".bmp"}, {&WiaImgFmt_JPEG, L".jpg"}, {&WiaImgFmt_FLASHPIX, L".fpx"}, {&WiaImgFmt_TIFF, L".tif"}, {NULL, L""} };
/*******************************************************************************
GetDropTarget
Get an IDropTarget interface for the given folder
*******************************************************************************/ HRESULT GetDropTarget (IShellFolder *pDesktop, LPCTSTR szPath, IDropTarget **ppDrop) { HRESULT hr; LPITEMIDLIST pidl; CSimpleStringWide strPath = CSimpleStringConvert::WideString (CSimpleString(szPath)); CComPtr<IShellFolder> psf; hr = pDesktop->ParseDisplayName(NULL, NULL, const_cast<LPWSTR>(static_cast<LPCWSTR>(strPath)), NULL, &pidl, NULL); if (SUCCEEDED(hr)) { hr = pDesktop->BindToObject(const_cast<LPCITEMIDLIST>(pidl), NULL, IID_IShellFolder, reinterpret_cast<LPVOID*>(&psf)); if (SUCCEEDED(hr)) { hr = psf->CreateViewObject (NULL, IID_IDropTarget, reinterpret_cast<LPVOID*>(ppDrop)); } } return hr; }
/*******************************************************************************
FreePidl Called when the array of pidls is destroyed, to free the pidls *******************************************************************************/ INT FreePidl (LPITEMIDLIST pidl, IMalloc *pMalloc) { pMalloc->Free (pidl); return 1; }
HRESULT SaveItemsFromFolder (IShellFolder *pRoot, CSimpleString &strPath, BOOL bDelete) { CComPtr<IEnumIDList> pEnum; LPITEMIDLIST pidl; HRESULT hr = S_FALSE;
CComPtr<IMalloc> pMalloc; if (SUCCEEDED(SHGetMalloc (&pMalloc))) {
CComPtr<IShellFolder> pDesktop; if (SUCCEEDED(SHGetDesktopFolder (&pDesktop))) { // enum the non-folder objects first
if (SUCCEEDED(pRoot->EnumObjects (NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS , &pEnum))) { HDPA dpaItems;
dpaItems = DPA_Create(10); while (NOERROR == pEnum->Next(1, &pidl, NULL)) { DPA_AppendPtr (dpaItems, pidl);
} //
// Now create the array of pidls and get the IDataObject
//
INT nSize = DPA_GetPtrCount (dpaItems); if (nSize > 0) { LPITEMIDLIST *aidl = new LPITEMIDLIST[nSize]; if (aidl) { CComPtr<IDataObject> pdo; for (INT i=0;i<nSize;i++) { aidl[i] = reinterpret_cast<LPITEMIDLIST>(DPA_FastGetPtr(dpaItems, i)); } hr = pRoot->GetUIObjectOf (NULL, nSize, const_cast<LPCITEMIDLIST*>(aidl), IID_IDataObject, NULL, reinterpret_cast<LPVOID*>(&pdo)); if (SUCCEEDED(hr)) { CComPtr<IDropTarget> pDrop; CComQIPtr<IAsyncOperation, &IID_IAsyncOperation> pasync(pdo); if (pasync.p) { pasync->SetAsyncMode(FALSE); } CheckAndCreateFolder (strPath); if (strPath.Length()) {
//
// Get an IDropTarget for the destination folder
// and do the drag/drop
//
hr = GetDropTarget (pDesktop, strPath, &pDrop); } else { hr = S_FALSE; } if (S_OK == hr) { DWORD dwKeyState; if (bDelete) { // the "move" keys
dwKeyState = MK_SHIFT | MK_LBUTTON; } else { // the copy keys
dwKeyState = MK_CONTROL|MK_LBUTTON; } hr = SHSimulateDrop (pDrop, pdo, dwKeyState, NULL, NULL); } } } else { hr = E_OUTOFMEMORY; } } else { hr = S_FALSE; // no images to download
} DPA_DestroyCallback (dpaItems, reinterpret_cast<PFNDPAENUMCALLBACK>(FreePidl), reinterpret_cast<LPVOID>(pMalloc.p)); } } } return hr; }
/*******************************************************************************
SaveItems
This function uses IShellFolder and IDataObject interfaces to simulate a drag/drop operation from the WIA virtual folder for the given device.
*******************************************************************************/
#define STR_WIASHEXT TEXT("wiashext.dll")
static HRESULT SaveItems (BSTR strDeviceId, CMinimalTransferSettings &settings) { WIA_PUSH_FUNCTION((TEXT("SaveItems( %ws, ... )"), strDeviceId )); CComPtr<IShellFolder>pRoot; HRESULT hr = SHGetDesktopFolder (&pRoot); if (SUCCEEDED(hr)) { //
// Get the system directory, which is where wiashext.dll lives
//
TCHAR szShellExtensionPath[MAX_PATH] = {0}; if (GetSystemDirectory( szShellExtensionPath, ARRAYSIZE(szShellExtensionPath))) { //
// Make sure the path variable is long enough to hold this path
//
if (lstrlen(szShellExtensionPath) + lstrlen(STR_WIASHEXT) + lstrlen(TEXT("\\")) < ARRAYSIZE(szShellExtensionPath)) { //
// Concatenate the backslash and module name to the system path
//
lstrcat( szShellExtensionPath, TEXT("\\") ); lstrcat( szShellExtensionPath, STR_WIASHEXT );
//
// Load the DLL
//
HINSTANCE hInstanceShellExt = LoadLibrary(szShellExtensionPath); if (hInstanceShellExt) { //
// Get the pidl making function
//
WIAMAKEFULLPIDLFORDEVICE pfnMakeFullPidlForDevice = reinterpret_cast<WIAMAKEFULLPIDLFORDEVICE>(GetProcAddress(hInstanceShellExt, "MakeFullPidlForDevice")); if (pfnMakeFullPidlForDevice) { //
// Get the pidl
//
LPITEMIDLIST pidlDevice = NULL; hr = pfnMakeFullPidlForDevice( strDeviceId, &pidlDevice ); if (SUCCEEDED(hr)) { //
// Bind to the folder for this device
//
CComPtr<IShellFolder> pDevice; hr = pRoot->BindToObject (const_cast<LPCITEMIDLIST> (pidlDevice), NULL, IID_IShellFolder, reinterpret_cast<LPVOID*>(&pDevice)); if (SUCCEEDED(hr)) {
hr = SaveItemsFromFolder (pDevice, settings.strFolderPath, settings.bDeleteImages); if (S_OK == hr && settings.bDeleteImages) { //
// DoDeleteAllItems will pop up a dialog to confirm the delete.
//
DoDeleteAllItems (strDeviceId, NULL); } } else { WIA_PRINTHRESULT((hr,TEXT("BindToObject failed!"))); }
CComPtr<IMalloc> pMalloc; if (SUCCEEDED(SHGetMalloc(&pMalloc)) && pMalloc) { pMalloc->Free(pidlDevice); } } else { WIA_PRINTHRESULT((hr,TEXT("MakeFullPidlForDevice failed!"))); } } else { hr = HRESULT_FROM_WIN32(GetLastError()); WIA_PRINTHRESULT((hr,TEXT("GetProcAddress for MakeFullPidlForDevice failed!"))); } FreeLibrary(hInstanceShellExt); } else { hr = HRESULT_FROM_WIN32(GetLastError()); WIA_PRINTHRESULT((hr,TEXT("Unable to load wiashext.dll!"))); } } else { hr = E_FAIL; WIA_PRINTHRESULT((hr,TEXT("Buffer size was too small"))); } } else { hr = HRESULT_FROM_WIN32(GetLastError()); WIA_PRINTHRESULT((hr,TEXT("Unable to get system folder!"))); } } else { WIA_PRINTHRESULT((hr,TEXT("SHGetDesktopFolder failed!"))); } return hr; }
} // End namespace MinimalTransfer
LRESULT MinimalTransferThreadProc (BSTR bstrDeviceId) { if (bstrDeviceId) { CMinimalTransferSettings settings;
HRESULT hr = CoInitialize(NULL); if (SUCCEEDED(hr)) { GetSaveSettings (settings, bstrDeviceId); // Bail if the default action is donothing or if the user cancelled
// the browse for folder
if (settings.dwAction == ACTION_AUTOSAVE) { hr = SaveItems (bstrDeviceId, settings); // Show the folder the user saved to
if (NOERROR == hr) { SHELLEXECUTEINFO sei; ZeroMemory (&sei, sizeof(sei)); sei.cbSize = sizeof(sei); sei.lpDirectory = settings.strFolderPath; sei.nShow = SW_SHOW; ShellExecuteEx (&sei); } else if (FAILED(hr)) { WIA_PRINTHRESULT((hr,TEXT("SaveItems failed!"))); // we can rely on SaveItems reporting errors to the user
} } CoUninitialize(); } #ifndef DBG_GENERATE_PRETEND_EVENT
WIA_TRACE((TEXT("Module::m_nLockCnt: %d"),_Module.m_nLockCnt)); _Module.Unlock(); #endif
SysFreeString(bstrDeviceId); } return 0; }
|