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

/*******************************************************************************
*
* (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;
}