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.
4072 lines
133 KiB
4072 lines
133 KiB
/*******************************************************************************
|
|
*
|
|
* (C) COPYRIGHT MICROSOFT CORP., 1997
|
|
*
|
|
* TITLE: Helpers.Cpp
|
|
*
|
|
* VERSION: 2.0
|
|
*
|
|
* AUTHOR: ReedB
|
|
*
|
|
* DATE: 12 Mar, 1999
|
|
*
|
|
* DESCRIPTION:
|
|
* Helpers for WIA device manager.
|
|
*
|
|
*******************************************************************************/
|
|
#include "precomp.h"
|
|
#include "stiexe.h"
|
|
|
|
#include <wiadef.h>
|
|
#include <icm.h>
|
|
|
|
#include "wiamindr.h"
|
|
#include "devinfo.h"
|
|
|
|
#define WIA_DECLARE_MANAGED_PROPS
|
|
#include "helpers.h"
|
|
#include "shpriv.h"
|
|
#include "sticfunc.h"
|
|
|
|
extern "C"
|
|
{
|
|
//
|
|
// From Terminal services
|
|
//
|
|
#include <winsta.h>
|
|
#include <syslib.h>
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* LockWiaDevice
|
|
*
|
|
* Wrapper to request Lock Manager to lock device.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pIWiaMiniDrv - Pointer to mini-driver interface.
|
|
* pIWiaItem - Pointer to the wia item
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Status
|
|
*
|
|
* History:
|
|
*
|
|
* 3/1/1999 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HRESULT _stdcall LockWiaDevice(IWiaItem *pIWiaItem)
|
|
{
|
|
DBG_FN(::LockWiaDevice);
|
|
|
|
HRESULT hr = WIA_ERROR_OFFLINE;
|
|
LONG lFlags = 0;
|
|
CWiaItem *pItem = (CWiaItem*) pIWiaItem;
|
|
|
|
if (pItem->m_pActiveDevice) {
|
|
hr = pItem->m_pActiveDevice->m_DrvWrapper.WIA_drvLockWiaDevice(
|
|
(BYTE*) pItem,
|
|
lFlags,
|
|
&(pItem->m_lLastDevErrVal));
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* UnLockWiaDevice
|
|
*
|
|
* Wrapper to request Lock Manager to unlock device.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pIWiaMiniDrv - Pointer to mini-driver interface.
|
|
* pIWiaItem - Pointer to the wia item
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Status
|
|
*
|
|
* History:
|
|
*
|
|
* 3/1/1999 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HRESULT _stdcall UnLockWiaDevice(IWiaItem *pIWiaItem)
|
|
{
|
|
DBG_FN(::UnLockWiaDevice);
|
|
|
|
HRESULT hr = WIA_ERROR_OFFLINE;
|
|
LONG lFlags = 0;
|
|
LONG lDevErrVal;
|
|
CWiaItem *pItem = (CWiaItem*) pIWiaItem;
|
|
|
|
if (pItem->m_pActiveDevice) {
|
|
hr = pItem->m_pActiveDevice->m_DrvWrapper.WIA_drvUnLockWiaDevice(
|
|
(BYTE*) pItem,
|
|
lFlags,
|
|
&(pItem->m_lLastDevErrVal));
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* ValidateWiaItem
|
|
*
|
|
* Validate a CWiaItem.
|
|
*
|
|
* Arguments:
|
|
*
|
|
*
|
|
* Return Value:
|
|
*
|
|
* None
|
|
*
|
|
* History:
|
|
*
|
|
* 3/1/1999 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HRESULT _stdcall ValidateWiaItem(
|
|
IWiaItem *pIWiaItem)
|
|
{
|
|
DBG_FN(::ValidateWiaItem);
|
|
HRESULT hr = E_POINTER;
|
|
|
|
if (pIWiaItem) {
|
|
|
|
CWiaItem *pWiaItem = (CWiaItem*)pIWiaItem;
|
|
|
|
if (!IsBadReadPtr(pWiaItem, sizeof(CWiaItem))) {
|
|
if (pWiaItem->m_ulSig == CWIAITEM_SIG) {
|
|
return S_OK;
|
|
}
|
|
else {
|
|
DBG_ERR(("ValidateWiaItem, invalid signature: %X", pWiaItem->m_ulSig));
|
|
hr = E_INVALIDARG;
|
|
}
|
|
}
|
|
else {
|
|
DBG_ERR(("ValidateWiaItem, NULL WIA item pointer"));
|
|
}
|
|
}
|
|
else {
|
|
DBG_ERR(("ValidateWiaItem, NULL WIA item pointer"));
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* ValidateWiaDrvItemAccess
|
|
*
|
|
* Validate a CWiaDrvItem.
|
|
*
|
|
* Arguments:
|
|
*
|
|
*
|
|
* Return Value:
|
|
*
|
|
* None
|
|
*
|
|
* History:
|
|
*
|
|
* 3/1/1999 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HRESULT _stdcall ValidateWiaDrvItemAccess(
|
|
CWiaDrvItem *pWiaDrvItem)
|
|
{
|
|
DBG_FN(::ValidateWiaDrvItemAccess);
|
|
HRESULT hr = S_OK;
|
|
|
|
if (pWiaDrvItem) {
|
|
|
|
//
|
|
// Verify access to the driver item.
|
|
//
|
|
if (IsBadReadPtr(pWiaDrvItem, sizeof(CWiaDrvItem))) {
|
|
DBG_ERR(("ValidateWiaDrvItemAccess, bad pointer, pWiaDrvItem: %X", pWiaDrvItem));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Get the driver item flags.
|
|
//
|
|
|
|
LONG lItemFlags;
|
|
|
|
pWiaDrvItem->GetItemFlags(&lItemFlags);
|
|
|
|
//
|
|
// Verify the item has been initialized and was inserted in the
|
|
// driver item tree at one time.
|
|
//
|
|
|
|
if (lItemFlags == WiaItemTypeFree) {
|
|
DBG_ERR(("ValidateWiaDrvItemAccess, application attempting access of unintialized or free item: %0x08X", pWiaDrvItem));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (lItemFlags & WiaItemTypeDeleted) {
|
|
DBG_ERR(("ValidateWiaDrvItemAccess, application attempting access of deleted item: %0x08X", pWiaDrvItem));
|
|
return WIA_ERROR_ITEM_DELETED;
|
|
}
|
|
|
|
if (lItemFlags & WiaItemTypeDisconnected) {
|
|
DBG_ERR(("ValidateWiaDrvItemAccess, application attempting access of disconnected item: %0x08X", pWiaDrvItem));
|
|
return WIA_ERROR_OFFLINE;
|
|
}
|
|
|
|
hr = S_OK;
|
|
}
|
|
else {
|
|
DBG_ERR(("ValidateWiaDrvItemAccess, Bad pWiaDrvItem pointer"));
|
|
hr = E_INVALIDARG;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* GetNameFromWiaPropId
|
|
*
|
|
* Map a WIA property ID to it's corresponding string name.
|
|
*
|
|
* Arguments:
|
|
*
|
|
*
|
|
* Return Value:
|
|
*
|
|
* None
|
|
*
|
|
* History:
|
|
*
|
|
* 3/1/1999 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#define MAP_SIZE (sizeof(g_wiaPropIdToName) / sizeof(WIA_PROPID_TO_NAME))
|
|
|
|
LPOLESTR GetNameFromWiaPropId(PROPID propid)
|
|
{
|
|
for (INT i = 0; g_wiaPropIdToName[i].propid != 0; i++) {
|
|
if (propid == g_wiaPropIdToName[i].propid) {
|
|
return g_wiaPropIdToName[i].pszName;
|
|
}
|
|
}
|
|
|
|
return g_wiaPropIdToName[i].pszName;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
* ReportReadWriteMultipleError
|
|
*
|
|
* Report errors that occur during ReadMultiple and WriteMultiple calls.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* hr - Result from ReadMultiple or WriteMultiple call.
|
|
* pszWhere - Where the API was called from (function/method name).
|
|
* pszWhat - Optional, which Read/WriteMultiple, used if more than
|
|
* one Read/WriteMultiple called in function/method.
|
|
* bRead - TRUE for ReadMultiple.
|
|
* cpspec - Count of PROPSPEC's in rgpspec.
|
|
* rgpspec - Array of PROPSPEC's.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* None
|
|
*
|
|
* History:
|
|
*
|
|
* 3/1/1999 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void _stdcall ReportReadWriteMultipleError(
|
|
HRESULT hr,
|
|
LPSTR pszWhere,
|
|
LPSTR pszWhat,
|
|
BOOL bRead,
|
|
ULONG cpspec,
|
|
const PROPSPEC propspec[])
|
|
{
|
|
DBG_FN(::ReportReadWriteMultipleError);
|
|
if (SUCCEEDED(hr)) {
|
|
if (hr == S_FALSE) {
|
|
if (bRead) {
|
|
if (pszWhat) {
|
|
DBG_ERR(("%s, ReadMultiple property not found, %s", pszWhere, pszWhat));
|
|
}
|
|
else {
|
|
DBG_ERR(("%s, ReadMultiple property not found", pszWhere));
|
|
}
|
|
}
|
|
else {
|
|
if (pszWhat) {
|
|
DBG_ERR(("%s, WriteMultiple returned S_FALSE, %s", pszWhere, pszWhat));
|
|
}
|
|
else {
|
|
DBG_ERR(("%s, WriteMultiple returned S_FALSE", pszWhere));
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
return; // No error.
|
|
}
|
|
}
|
|
else {
|
|
if (bRead) {
|
|
DBG_ERR(("%s, ReadMultiple failed, %s Error 0x%X", pszWhere, pszWhat ? pszWhat : "(null)", hr));
|
|
}
|
|
else {
|
|
DBG_ERR(("%s, WriteMultiple failed, %s Error 0x%X", pszWhere, pszWhat ? pszWhat : "(null)", hr));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Output specification information.
|
|
//
|
|
|
|
if (cpspec == 0) {
|
|
DBG_ERR((" count of PROPSPEC's is zero"));
|
|
}
|
|
else if (cpspec == 1) {
|
|
if (propspec[0].ulKind == PRSPEC_PROPID) {
|
|
DBG_ERR((" property ID: %d, property name: %S", propspec[0].propid, GetNameFromWiaPropId(propspec[0].propid)));
|
|
}
|
|
else if (propspec[0].ulKind == PRSPEC_LPWSTR) {
|
|
DBG_ERR((" property name: %S", propspec[0].lpwstr));
|
|
}
|
|
else {
|
|
DBG_ERR((" bad property specification"));
|
|
}
|
|
}
|
|
else {
|
|
DBG_ERR((" count of PROPSPEC's is: %d", cpspec));
|
|
for (UINT i = 0; i < cpspec; i++) {
|
|
if (propspec[i].ulKind == PRSPEC_PROPID) {
|
|
DBG_ERR((" property ID: %d, property name: %S", propspec[i].propid, GetNameFromWiaPropId(propspec[i].propid)));
|
|
}
|
|
else if (propspec[i].ulKind == PRSPEC_LPWSTR) {
|
|
DBG_ERR((" index: %d, property name: %S", i, propspec[i].lpwstr));
|
|
}
|
|
else {
|
|
DBG_ERR((" index: %d, bad property specification", i));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ReadPropStr
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
HRESULT _stdcall ReadPropStr(
|
|
PROPID propid,
|
|
IPropertyStorage *pIPropStg,
|
|
BSTR *pbstr)
|
|
{
|
|
DBG_FN(::ReadPropStr);
|
|
HRESULT hr;
|
|
PROPSPEC PropSpec[1];
|
|
PROPVARIANT PropVar[1];
|
|
UINT cbSize;
|
|
|
|
*pbstr = NULL;
|
|
memset(PropVar, 0, sizeof(PropVar));
|
|
PropSpec[0].ulKind = PRSPEC_PROPID;
|
|
PropSpec[0].propid = propid;
|
|
hr = pIPropStg->ReadMultiple(1, PropSpec, PropVar);
|
|
if (SUCCEEDED(hr)) {
|
|
if (PropVar[0].pwszVal) {
|
|
*pbstr = SysAllocString(PropVar[0].pwszVal);
|
|
}
|
|
else {
|
|
*pbstr = SysAllocString(L"");
|
|
}
|
|
if (*pbstr == NULL) {
|
|
DBG_ERR(("ReadPropStr, SysAllocString failed"));
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
PropVariantClear(PropVar);
|
|
}
|
|
else {
|
|
DBG_ERR(("ReadPropStr, ReadMultiple of propid: %d, failed", propid));
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT _stdcall ReadPropStr(
|
|
PROPID propid,
|
|
IWiaPropertyStorage *pIWiaPropStg,
|
|
BSTR *pbstr)
|
|
{
|
|
DBG_FN(::ReadPropStr);
|
|
HRESULT hr;
|
|
PROPSPEC PropSpec[1];
|
|
PROPVARIANT PropVar[1];
|
|
UINT cbSize;
|
|
|
|
*pbstr = NULL;
|
|
memset(PropVar, 0, sizeof(PropVar));
|
|
PropSpec[0].ulKind = PRSPEC_PROPID;
|
|
PropSpec[0].propid = propid;
|
|
hr = pIWiaPropStg->ReadMultiple(1, PropSpec, PropVar);
|
|
if (SUCCEEDED(hr)) {
|
|
if (PropVar[0].pwszVal) {
|
|
*pbstr = SysAllocString(PropVar[0].pwszVal);
|
|
}
|
|
else {
|
|
*pbstr = SysAllocString(L"");
|
|
}
|
|
if (*pbstr == NULL) {
|
|
DBG_ERR(("ReadPropStr, SysAllocString failed"));
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
PropVariantClear(PropVar);
|
|
}
|
|
else {
|
|
DBG_ERR(("ReadPropStr, ReadMultiple of propid: %d, failed", propid));
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT _stdcall ReadPropStr(IUnknown *pDevice, PROPID propid, BSTR *pbstr)
|
|
{
|
|
DBG_FN(::ReadPropStr);
|
|
HRESULT hr;
|
|
PROPVARIANT pv[1];
|
|
PROPSPEC ps[1];
|
|
IWiaPropertyStorage *pIWiaPropStg;
|
|
|
|
*pbstr = NULL;
|
|
hr = pDevice->QueryInterface(IID_IWiaPropertyStorage, (void**)&pIWiaPropStg);
|
|
if (SUCCEEDED(hr)) {
|
|
PropVariantInit(pv);
|
|
ps[0].ulKind = PRSPEC_PROPID;
|
|
ps[0].propid = propid;
|
|
|
|
hr = pIWiaPropStg->ReadMultiple(1, ps, pv);
|
|
if (hr == S_OK) {
|
|
*pbstr = SysAllocString(pv[0].pwszVal);
|
|
} else {
|
|
DBG_ERR(("ReadPropStr, ReadMultiple for propid: %d, failed", propid));
|
|
}
|
|
PropVariantClear(pv);
|
|
pIWiaPropStg->Release();
|
|
} else {
|
|
DBG_ERR(("ReadPropStr, QI for IWiaPropertyStorage failed"));
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ReadPropLong
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
HRESULT _stdcall ReadPropLong(PROPID propid, IPropertyStorage *pIPropStg, LONG *plval)
|
|
{
|
|
DBG_FN(::ReadPropLong);
|
|
HRESULT hr;
|
|
PROPSPEC PropSpec[1];
|
|
PROPVARIANT PropVar[1];
|
|
UINT cbSize;
|
|
|
|
memset(PropVar, 0, sizeof(PropVar));
|
|
PropSpec[0].ulKind = PRSPEC_PROPID;
|
|
PropSpec[0].propid = propid;
|
|
hr = pIPropStg->ReadMultiple(1, PropSpec, PropVar);
|
|
if (SUCCEEDED(hr)) {
|
|
*plval = PropVar[0].lVal;
|
|
}
|
|
else {
|
|
DBG_ERR(("ReadPropLong, ReadMultiple of propid: %d, failed", propid));
|
|
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT _stdcall ReadPropLong(IUnknown *pDevice, PROPID propid, LONG *plval)
|
|
{
|
|
DBG_FN(::ReadPropLong);
|
|
HRESULT hr;
|
|
PROPVARIANT pv[1];
|
|
PROPSPEC ps[1];
|
|
IWiaPropertyStorage *pIWiaPropStg;
|
|
|
|
*plval = 0;
|
|
|
|
hr = pDevice->QueryInterface(IID_IWiaPropertyStorage, (void**)&pIWiaPropStg);
|
|
if (SUCCEEDED(hr)) {
|
|
PropVariantInit(pv);
|
|
ps[0].ulKind = PRSPEC_PROPID;
|
|
ps[0].propid = propid;
|
|
|
|
hr = pIWiaPropStg->ReadMultiple(1, ps, pv);
|
|
if (hr == S_OK) {
|
|
*plval = pv[0].lVal;
|
|
} else {
|
|
DBG_ERR(("ReadPropLong, ReadMultiple of propid: %d, failed", propid));
|
|
}
|
|
pIWiaPropStg->Release();
|
|
}
|
|
else {
|
|
DBG_ERR(("ReadPropLong, QI of IID_IWiaPropertyStorage failed"));
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* WritePropStr
|
|
*
|
|
* Writes a string property to the specified property storage. This is an
|
|
* overloaded function.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* propid - propid of the property
|
|
* pIPropStg - a pointer to the property storage
|
|
* bstr - the string to write
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Status
|
|
*
|
|
* History:
|
|
*
|
|
* 10/5/1999 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HRESULT _stdcall WritePropStr(PROPID propid, IPropertyStorage *pIPropStg, BSTR bstr)
|
|
{
|
|
DBG_FN(::WritePropStr);
|
|
HRESULT hr;
|
|
PROPSPEC propspec[1];
|
|
PROPVARIANT propvar[1];
|
|
|
|
propspec[0].ulKind = PRSPEC_PROPID;
|
|
propspec[0].propid = propid;
|
|
|
|
propvar[0].vt = VT_BSTR;
|
|
propvar[0].pwszVal = bstr;
|
|
|
|
hr = pIPropStg->WriteMultiple(1, propspec, propvar, 2);
|
|
if (FAILED(hr)) {
|
|
ReportReadWriteMultipleError( hr,
|
|
"Helpers WritePropStr",
|
|
NULL,
|
|
FALSE,
|
|
1,
|
|
propspec);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
* WritePropStr
|
|
*
|
|
* Writes a string property. This is an overloaded function which calls
|
|
* the other WritePropStr.
|
|
*
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pDevice - A pointer to a device item which will be queried for
|
|
* it's IWiaPropertyStorage.
|
|
* propid - propid of the property
|
|
* bstr - the string to write
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Status
|
|
*
|
|
* History:
|
|
*
|
|
* 10/5/1999 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HRESULT _stdcall WritePropStr(IUnknown *pDevice, PROPID propid, BSTR bstr)
|
|
{
|
|
DBG_FN(::WritePropStr);
|
|
HRESULT hr;
|
|
PROPVARIANT pv[1];
|
|
PROPSPEC ps[1];
|
|
IWiaPropertyStorage *pIWiaPropStg;
|
|
|
|
PropVariantInit(pv);
|
|
|
|
hr = pDevice->QueryInterface(IID_IWiaPropertyStorage, (void**)&pIWiaPropStg);
|
|
if (SUCCEEDED(hr)) {
|
|
ps[0].ulKind = PRSPEC_PROPID;
|
|
ps[0].propid = propid;
|
|
|
|
pv[0].vt = VT_BSTR;
|
|
pv[0].pwszVal = bstr;
|
|
|
|
hr = pIWiaPropStg->WriteMultiple(1, ps, pv, 2);
|
|
if (FAILED(hr)) {
|
|
ReportReadWriteMultipleError( hr,
|
|
"Helpers WritePropStr",
|
|
NULL,
|
|
FALSE,
|
|
1,
|
|
ps);
|
|
}
|
|
|
|
pIWiaPropStg->Release();
|
|
}
|
|
else {
|
|
DBG_ERR(("WritePropStr, QI of IID_IWiaPropertyStorage failed"));
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* WritePropLong
|
|
*
|
|
* Writes a long property to the specified property storage. This is an
|
|
* overloaded function.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* propid - propid of the property
|
|
* pIPropStg - a pointer to the property storage
|
|
* lVal - the LONG value to write
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Status
|
|
*
|
|
* History:
|
|
*
|
|
* 10/5/1999 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HRESULT _stdcall WritePropLong(PROPID propid, IPropertyStorage *pIPropStg, LONG lVal)
|
|
{
|
|
DBG_FN(::WritePropLong);
|
|
HRESULT hr;
|
|
PROPSPEC propspec[1];
|
|
PROPVARIANT propvar[1];
|
|
|
|
propspec[0].ulKind = PRSPEC_PROPID;
|
|
propspec[0].propid = propid;
|
|
|
|
propvar[0].vt = VT_I4;
|
|
propvar[0].lVal = lVal;
|
|
|
|
hr = pIPropStg->WriteMultiple(1, propspec, propvar, 2);
|
|
if (FAILED(hr)) {
|
|
ReportReadWriteMultipleError( hr,
|
|
"Helpers WritePropLong",
|
|
NULL,
|
|
FALSE,
|
|
1,
|
|
propspec);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* WritePropLong
|
|
*
|
|
* Writes a long property. This is an overloaded function which calls
|
|
* the other WritePropLong.
|
|
*
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pDevice - A pointer to a device item which will be queried for
|
|
* it's IWiaPropertyStorage.
|
|
* propid - propid of the property
|
|
* lVal - the LONG value to write
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Status
|
|
*
|
|
* History:
|
|
*
|
|
* 10/5/1999 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
HRESULT _stdcall WritePropLong(IUnknown *pDevice, PROPID propid, LONG lVal)
|
|
{
|
|
DBG_FN(::WritePropLong);
|
|
HRESULT hr;
|
|
PROPVARIANT pv[1];
|
|
PROPSPEC ps[1];
|
|
IWiaPropertyStorage *pIWiaPropStg;
|
|
|
|
hr = pDevice->QueryInterface(IID_IWiaPropertyStorage, (void**)&pIWiaPropStg);
|
|
if (SUCCEEDED(hr)) {
|
|
PropVariantInit(pv);
|
|
ps[0].ulKind = PRSPEC_PROPID;
|
|
ps[0].propid = propid;
|
|
|
|
pv[0].vt = VT_I4;
|
|
pv[0].lVal = lVal;
|
|
|
|
hr = pIWiaPropStg->WriteMultiple(1, ps, pv, 2);
|
|
if (FAILED(hr)) {
|
|
ReportReadWriteMultipleError( hr,
|
|
"Helpers WritePropLong",
|
|
NULL,
|
|
FALSE,
|
|
1,
|
|
ps);
|
|
}
|
|
pIWiaPropStg->Release();
|
|
}
|
|
else {
|
|
DBG_ERR(("WritePropLong, QI of IID_IWiaPropertyStorage failed"));
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* InitMiniDrvContext
|
|
*
|
|
* Initialize a mini driver context from an items properties.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pItem - Pointer to the wia item
|
|
* pmdtc - pointer to mini driver context
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Status
|
|
*
|
|
* History:
|
|
*
|
|
* 6/16/1999 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HRESULT _stdcall InitMiniDrvContext(
|
|
IWiaItem *pItem,
|
|
PMINIDRV_TRANSFER_CONTEXT pmdtc)
|
|
{
|
|
DBG_FN(::InitMiniDrvContext);
|
|
//
|
|
// Get a property storage from the item.
|
|
//
|
|
|
|
HRESULT hr;
|
|
IPropertyStorage *pIPropStg;
|
|
|
|
hr = ((CWiaItem*)pItem)->GetItemPropStreams(&pIPropStg, NULL, NULL, NULL);
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Setup the minidriver transfer context. Fill in transfer context
|
|
// members which derive from item properties.
|
|
//
|
|
|
|
memset(pmdtc, 0, sizeof(MINIDRV_TRANSFER_CONTEXT));
|
|
|
|
pmdtc->lSize = sizeof(MINIDRV_TRANSFER_CONTEXT);
|
|
|
|
#define NUM_IMAGE_SPEC 9
|
|
|
|
static PROPSPEC PropSpec[NUM_IMAGE_SPEC] =
|
|
{
|
|
{PRSPEC_PROPID, WIA_IPA_PIXELS_PER_LINE},
|
|
{PRSPEC_PROPID, WIA_IPA_NUMBER_OF_LINES},
|
|
{PRSPEC_PROPID, WIA_IPA_DEPTH},
|
|
{PRSPEC_PROPID, WIA_IPS_XRES},
|
|
{PRSPEC_PROPID, WIA_IPS_YRES},
|
|
{PRSPEC_PROPID, WIA_IPA_COMPRESSION},
|
|
{PRSPEC_PROPID, WIA_IPA_ITEM_SIZE},
|
|
{PRSPEC_PROPID, WIA_IPA_FORMAT},
|
|
{PRSPEC_PROPID, WIA_IPA_TYMED}
|
|
};
|
|
|
|
PROPVARIANT PropVar[NUM_IMAGE_SPEC];
|
|
|
|
memset(PropVar, 0, sizeof(PropVar));
|
|
|
|
hr = pIPropStg->ReadMultiple(NUM_IMAGE_SPEC, PropSpec, PropVar);
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
pmdtc->lWidthInPixels = PropVar[0].lVal;
|
|
pmdtc->lLines = PropVar[1].lVal;
|
|
pmdtc->lDepth = PropVar[2].lVal;
|
|
pmdtc->lXRes = PropVar[3].lVal;
|
|
pmdtc->lYRes = PropVar[4].lVal;
|
|
pmdtc->lCompression = PropVar[5].lVal;
|
|
pmdtc->lItemSize = PropVar[6].lVal;
|
|
pmdtc->guidFormatID = *PropVar[7].puuid;
|
|
pmdtc->tymed = PropVar[8].lVal;
|
|
|
|
FreePropVariantArray(NUM_IMAGE_SPEC, PropVar);
|
|
}
|
|
else {
|
|
ReportReadWriteMultipleError(hr, "InitMiniDrvContext", NULL, TRUE, NUM_IMAGE_SPEC, PropSpec);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* GetPropertyAttributesHelper
|
|
*
|
|
* Get the access flags and valid values for a property. Used by
|
|
* GetPropertyAttributes in the service and by WIA Items. Parameter
|
|
* validation is done beforehand by caller.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pItem - Pointer to WIA item
|
|
* cPropSpec - The number of properties
|
|
* pPropSpec - array of property specification.
|
|
* pulAccessFlags - array of LONGs access flags.
|
|
* ppvValidValues - Pointer to returned valid values.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Status
|
|
*
|
|
* History:
|
|
*
|
|
* 1/19/1999 Original Version
|
|
* 05/14/1999 Updated to return multiple attribute values
|
|
* 30/06/1999 Parameter validation removed,
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HRESULT _stdcall GetPropertyAttributesHelper(
|
|
IWiaItem *pItem,
|
|
LONG cPropSpec,
|
|
PROPSPEC *pPropSpec,
|
|
ULONG *pulAccessFlags,
|
|
PROPVARIANT *ppvValidValues)
|
|
{
|
|
DBG_FN(::GetPropertyAttributesHelper);
|
|
HRESULT hr;
|
|
|
|
memset(pulAccessFlags, 0, sizeof(ULONG) * cPropSpec);
|
|
memset(ppvValidValues, 0, sizeof(PROPVARIANT) * cPropSpec);
|
|
|
|
//
|
|
// Get the item's internal property storage pointers.
|
|
//
|
|
|
|
IPropertyStorage *pIPropAccessStg;
|
|
IPropertyStorage *pIPropValidStg;
|
|
|
|
hr = ((CWiaItem*)pItem)->GetItemPropStreams(NULL,
|
|
&pIPropAccessStg,
|
|
&pIPropValidStg,
|
|
NULL);
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Get the Access flags for the properties. Use pPropVar as
|
|
// temporary storage.
|
|
//
|
|
|
|
hr = pIPropAccessStg->ReadMultiple(cPropSpec, pPropSpec, ppvValidValues);
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
//
|
|
// Fill in the returned access flags
|
|
//
|
|
|
|
for (int flagIndex = 0; flagIndex < cPropSpec; flagIndex++) {
|
|
pulAccessFlags[flagIndex] = ppvValidValues[flagIndex].ulVal;
|
|
}
|
|
|
|
//
|
|
// Get the valid values
|
|
//
|
|
|
|
hr = pIPropValidStg->ReadMultiple(cPropSpec, pPropSpec, ppvValidValues);
|
|
if (FAILED(hr)) {
|
|
DBG_ERR(("GetPropertyAttributesHelper, ReadMultiple failed, could not get valid values (0x%X)", hr));
|
|
}
|
|
} else {
|
|
DBG_ERR(("GetPropertyAttributesHelper, ReadMultiple failed, could not get access flags (0x%X)", hr));
|
|
}
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
//
|
|
// Was not successful, so clear the return values and report
|
|
// which properties caused the error.
|
|
//
|
|
|
|
FreePropVariantArray(cPropSpec, ppvValidValues);
|
|
memset(pulAccessFlags, 0, sizeof(ULONG) * cPropSpec);
|
|
|
|
ReportReadWriteMultipleError(hr, "GetPropertyAttributesHelper",
|
|
NULL,
|
|
TRUE,
|
|
cPropSpec,
|
|
pPropSpec);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
* GetMinAndMaxLong
|
|
*
|
|
* This helper method is called to get the Min and Max values for a
|
|
* WIA_PROP_RANGE property of type VT_I4.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pWiasContext - a pointer to the item context
|
|
* propid - identifies the property we're interested in.
|
|
* plMin - the address of a LONG to receive the min value
|
|
* plMax - the address of a LONG to receive the max value
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Status
|
|
*
|
|
* History:
|
|
*
|
|
* 04/04/1999 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HRESULT _stdcall GetMinAndMaxLong(
|
|
BYTE* pWiasContext,
|
|
PROPID propid,
|
|
LONG *plMin,
|
|
LONG *plMax)
|
|
{
|
|
DBG_FN(::GetMinAndMaxLong);
|
|
IPropertyStorage *pIValidStg;
|
|
PROPSPEC ps[1];
|
|
PROPVARIANT pv[1];
|
|
HRESULT hr;
|
|
|
|
ps[0].ulKind = PRSPEC_PROPID;
|
|
ps[0].propid = propid;
|
|
|
|
PropVariantInit(pv);
|
|
|
|
hr = ((CWiaItem*) pWiasContext)->GetItemPropStreams(NULL,
|
|
NULL,
|
|
&pIValidStg,
|
|
NULL);
|
|
if (SUCCEEDED(hr)) {
|
|
hr = pIValidStg->ReadMultiple(1, ps, pv);
|
|
if (SUCCEEDED(hr)) {
|
|
if (plMin) {
|
|
*plMin = pv[0].cal.pElems[WIA_RANGE_MIN];
|
|
};
|
|
if (plMax) {
|
|
*plMax = pv[0].cal.pElems[WIA_RANGE_MAX];
|
|
};
|
|
PropVariantClear(pv);
|
|
} else {
|
|
DBG_ERR(("GetMinAndMaxLong, Reading property %d (%ws) failed",propid,GetNameFromWiaPropId(propid)));
|
|
};
|
|
} else {
|
|
DBG_ERR(("GetMinAndMaxLong, Could not get valid property stream"));
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* CheckXResAndUpdate
|
|
*
|
|
* This helper method is called to check whether WIA_IPS_XRES property
|
|
* is changed. When this property changes, other dependant
|
|
* properties and their valid values must also be changed.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pWiasContext - a pointer to the item context whose properties have
|
|
* changed.
|
|
* pContext - a pointer to the property context (which indicates
|
|
* which properties are being written).
|
|
* lWidth - the width of the maximum scan area in one thousandth's
|
|
* of an inch. Generally, this would be the horizontal
|
|
* bed size.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Status
|
|
*
|
|
* History:
|
|
*
|
|
* 04/04/1999 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HRESULT _stdcall CheckXResAndUpdate(
|
|
BYTE *pWiasContext,
|
|
WIA_PROPERTY_CONTEXT *pContext,
|
|
LONG lWidth)
|
|
{
|
|
DBG_FN(::CheckXResAndUpdate);
|
|
|
|
LONG lMinXExt, lMaxXExtOld, lMaxXPosOld;
|
|
LONG lMax, lExt;
|
|
WIAS_CHANGED_VALUE_INFO cviXRes, cviXPos, cviXExt;
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// Call wiasGetChangedValue for XResolution. XResolution is checked first
|
|
// since it's not dependant on any other property. All properties in
|
|
// this method that follow are dependant properties of XResolution.
|
|
//
|
|
|
|
hr = wiasGetChangedValueLong(pWiasContext,
|
|
pContext,
|
|
FALSE,
|
|
WIA_IPS_XRES,
|
|
&cviXRes);
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Call wiasGetChangedValue for XPos. XPos is a dependant property of
|
|
// XResolution whose valid value changes according to what the current
|
|
// value of XResolution is. This is so that when the resoltuion changes,
|
|
// the XPos will be in the same relative position.
|
|
//
|
|
|
|
hr = wiasGetChangedValueLong(pWiasContext,
|
|
pContext,
|
|
cviXRes.bChanged,
|
|
WIA_IPS_XPOS,
|
|
&cviXPos);
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Get the minimum and maximum extent values
|
|
//
|
|
|
|
hr = GetMinAndMaxLong(pWiasContext, WIA_IPS_XEXTENT, &lMinXExt, &lMaxXExtOld );
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
hr = GetMinAndMaxLong(pWiasContext, WIA_IPS_XPOS, NULL, &lMaxXPosOld );
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// lMax is the maximum horizontal position (in pixels) that XPos can be
|
|
// set to. lXRes is DPI, lWidth is in one thousandth's of an inch,
|
|
// and lMinXExt is in pixels.
|
|
//
|
|
|
|
lMax = ((cviXRes.Current.lVal * lWidth) / 1000) - lMinXExt;
|
|
|
|
if (cviXRes.bChanged) {
|
|
|
|
//
|
|
// XRes changed, so calc and set new XPos valid values.
|
|
//
|
|
|
|
hr = wiasSetValidRangeLong(pWiasContext, WIA_IPS_XPOS, 0, 0, lMax, 1);
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
//
|
|
// If XPos is not one of the properties being written, then fold
|
|
// it's current value.
|
|
//
|
|
|
|
if (!cviXPos.bChanged) {
|
|
|
|
cviXPos.Current.lVal = (cviXPos.Old.lVal * lMax) / lMaxXPosOld;
|
|
hr = wiasWritePropLong(pWiasContext, WIA_IPS_XPOS, cviXPos.Current.lVal);
|
|
if (FAILED(hr)) {
|
|
DBG_ERR(("CheckXResAndUpdate, could not write value for WIA_IPS_XPOS"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Call wiasGetChangedValue for XExtent. XExtent is a dependant property of
|
|
// both XResolution and XPos. The extent should be the same relative
|
|
// size no matter what the resolution. However, if the resolution changes
|
|
// or if the XPos is set, then the extent has the possibility of being
|
|
// too large and so must be folded to a valid value.
|
|
//
|
|
|
|
hr = wiasGetChangedValueLong(pWiasContext,
|
|
pContext,
|
|
cviXRes.bChanged || cviXPos.bChanged,
|
|
WIA_IPS_XEXTENT,
|
|
&cviXExt);
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
lExt = cviXExt.Current.lVal;
|
|
|
|
if (cviXRes.bChanged || cviXPos.bChanged) {
|
|
|
|
//
|
|
// XRes or XPos changed, so calc and set new XExtent valid values.
|
|
// The maximum valid value for XExtent is the maximum width allowed,
|
|
// starting at XPos.
|
|
//
|
|
|
|
lExt = (lMax - cviXPos.Current.lVal) + lMinXExt;
|
|
|
|
hr = wiasSetValidRangeLong(pWiasContext, WIA_IPS_XEXTENT, lMinXExt, lExt, lExt, 1);
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
//
|
|
// If XExtent is not one of the properties being written, then fold
|
|
// it's current value.
|
|
//
|
|
|
|
if (!cviXExt.bChanged) {
|
|
LONG lXExtScaled;
|
|
|
|
//
|
|
// First scale the extent and then check whether it has to be
|
|
// truncated. The old extent should be scaled to keep the
|
|
// same relative size. If the resolution has not changed,
|
|
// then the scaling simply keeps the extent the same size.
|
|
//
|
|
|
|
lXExtScaled = (cviXExt.Old.lVal * lExt) / lMaxXExtOld;
|
|
if (lXExtScaled > lExt) {
|
|
|
|
//
|
|
// The extent is too large, so clip it.
|
|
//
|
|
|
|
lXExtScaled = lExt;
|
|
}
|
|
hr = wiasWritePropLong(pWiasContext, WIA_IPS_XEXTENT, lXExtScaled);
|
|
if (FAILED(hr)) {
|
|
DBG_ERR(("CheckXResAndUpdate, could not write value for WIA_IPS_XEXTENT"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Update read-only property : PIXELS_PER_LINE. The width in pixels
|
|
// of the scanned image is the same size as the XExtent.
|
|
//
|
|
|
|
hr = wiasReadPropLong(pWiasContext, WIA_IPS_XEXTENT, &lExt, NULL, TRUE);
|
|
if (SUCCEEDED(hr)) {
|
|
hr = wiasWritePropLong(pWiasContext, WIA_IPA_PIXELS_PER_LINE, lExt);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* CheckYResAndUpdate
|
|
*
|
|
* This helper method is called to check whether WIA_IPS_YRES property
|
|
* is changed. When this property changes, other dependant
|
|
* properties and their valid values must also be changed. This is
|
|
* similar to the CheckXResAndUpdateChanged function.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pWiasContext - a pointer to the item context whose properties have
|
|
* changed.
|
|
* pContext - a pointer to the property context (which indicates
|
|
* which properties are being written).
|
|
* lHeight - the height of the maximum scan area in one
|
|
* thousandth's of an inch. Generally, this would be
|
|
* the vertical bed size.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Status
|
|
*
|
|
* History:
|
|
*
|
|
* 04/04/1999 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HRESULT _stdcall CheckYResAndUpdate(
|
|
BYTE *pWiasContext,
|
|
WIA_PROPERTY_CONTEXT *pContext,
|
|
LONG lHeight)
|
|
{
|
|
DBG_FN(::CheckYResAndUpdate);
|
|
LONG lMinYExt, lMaxYExtOld, lMaxYPosOld;
|
|
LONG lMax, lExt;
|
|
WIAS_CHANGED_VALUE_INFO cviYRes, cviYPos, cviYExt;
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// Call wiasGetChangedValue for YResolution. YResolution is checked first
|
|
// since it's not dependant on any other property. All properties in
|
|
// this method that follow are dependant properties of YResolution.
|
|
//
|
|
|
|
hr = wiasGetChangedValueLong(pWiasContext,
|
|
pContext,
|
|
FALSE,
|
|
WIA_IPS_YRES,
|
|
&cviYRes);
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Call wiasGetChangedValue for YPos. YPos is a dependant property of
|
|
// YResolution whose valid value changes according to what the current
|
|
// value of YResolution is. This is so that when the resoltuion changes,
|
|
// the YPos will be in the same relative position.
|
|
//
|
|
|
|
hr = wiasGetChangedValueLong(pWiasContext,
|
|
pContext,
|
|
cviYRes.bChanged,
|
|
WIA_IPS_YPOS,
|
|
&cviYPos);
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Get the minimum and maximum pos and extent values
|
|
//
|
|
|
|
hr = GetMinAndMaxLong(pWiasContext, WIA_IPS_YEXTENT, &lMinYExt, &lMaxYExtOld);
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
hr = GetMinAndMaxLong(pWiasContext, WIA_IPS_YPOS, NULL, &lMaxYPosOld);
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// lMax is the maximum vertical position (in pixels) that YPos can be
|
|
// set to. lYRes is DPI, lPageHeight is in one thousandth's of an inch,
|
|
// and lMinYExt is in pixels.
|
|
//
|
|
|
|
lMax = ((cviYRes.Current.lVal * lHeight) / 1000) - lMinYExt;
|
|
|
|
if (cviYRes.bChanged) {
|
|
|
|
//
|
|
// YRes changed, so calc and set new YPos valid values.
|
|
//
|
|
|
|
hr = wiasSetValidRangeLong(pWiasContext, WIA_IPS_YPOS, 0, 0, lMax, 1);
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
//
|
|
// If YPos is not one of the properties being written, then fold
|
|
// it's current value.
|
|
//
|
|
|
|
if (!cviYPos.bChanged) {
|
|
|
|
cviYPos.Current.lVal = (cviYPos.Old.lVal * lMax) / lMaxYPosOld;
|
|
hr = wiasWritePropLong(pWiasContext, WIA_IPS_YPOS, cviYPos.Current.lVal);
|
|
if (FAILED(hr)) {
|
|
DBG_ERR(("CheckYResAndUpdate, could not write value for WIA_IPS_YPOS"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Call wiasGetChangedValue for YExtent. YExtent is a dependant property of
|
|
// both YResolution and YPos. The extent should be the same relative
|
|
// size no matter what the resolution. However, if the resolution changes
|
|
// or if the YPos is set, then the extent has the possibility of being
|
|
// too large and so must be folded to a valid value.
|
|
//
|
|
|
|
hr = wiasGetChangedValueLong(pWiasContext,
|
|
pContext,
|
|
cviYRes.bChanged || cviYPos.bChanged,
|
|
WIA_IPS_YEXTENT,
|
|
&cviYExt);
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
lExt = cviYExt.Current.lVal;
|
|
|
|
if (cviYRes.bChanged || cviYPos.bChanged) {
|
|
|
|
//
|
|
// YRes or YPos changed, so calc and set new YExtent valid values.
|
|
// The maximum valid value for YExtent is the maximum height allowed,
|
|
// starting at YPos.
|
|
//
|
|
|
|
lExt = (lMax - cviYPos.Current.lVal) + lMinYExt;
|
|
|
|
hr = wiasSetValidRangeLong(pWiasContext, WIA_IPS_YEXTENT, lMinYExt, lExt, lExt, 1);
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
//
|
|
// If YExtent is not one of the properties being written, then fold
|
|
// it's current value.
|
|
//
|
|
|
|
if (!cviYExt.bChanged) {
|
|
LONG lYExtScaled;
|
|
|
|
//
|
|
// First scale the extent and then check whether it has to be
|
|
// truncated. The old extent should be scaled to keep the
|
|
// same relative size. If the resolution has not changed,
|
|
// then the scaling simply keeps the extent the same size.
|
|
//
|
|
|
|
lYExtScaled = (cviYExt.Old.lVal * lExt) / lMaxYExtOld;
|
|
if (lYExtScaled > lExt) {
|
|
|
|
//
|
|
// The extent is too large, so clip it.
|
|
//
|
|
|
|
lYExtScaled = lExt;
|
|
}
|
|
hr = wiasWritePropLong(pWiasContext, WIA_IPS_YEXTENT, lYExtScaled);
|
|
if (FAILED(hr)) {
|
|
DBG_ERR(("CheckYResAndUpdate, could not write value for WIA_IPS_YEXTENT"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Update read-only property : NUMBER_OF_LINES. The number of lines in the scanned
|
|
// image is the same as the vertical (Y) extent.
|
|
//
|
|
|
|
hr = wiasReadPropLong(pWiasContext, WIA_IPS_YEXTENT, &lExt, NULL, TRUE);
|
|
if (SUCCEEDED(hr)) {
|
|
hr = wiasWritePropLong(pWiasContext, WIA_IPA_NUMBER_OF_LINES, lExt);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* AreWiaInitializedProps
|
|
*
|
|
* This helper method is called to check whether a given set of propspecs
|
|
* identifies only the WIA managed properties. It is used to help
|
|
* performance with lazy intialization.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* cPropSpec - count of propecs in the array
|
|
* pPropSpec - the propspec array
|
|
*
|
|
* Return Value:
|
|
*
|
|
* TRUE - if all properties in the propspec array are WIA managed ones.
|
|
* FALSE - if at least one property is not a WIA managed one.
|
|
*
|
|
* History:
|
|
*
|
|
* 10/10/1999 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
BOOL _stdcall AreWiaInitializedProps(
|
|
ULONG cPropSpec,
|
|
PROPSPEC *pPropSpec)
|
|
{
|
|
DBG_FN(::AreWiaInitializedProps);
|
|
ULONG index;
|
|
ULONG propIndex;
|
|
BOOL bFoundProp = FALSE;
|
|
|
|
for (index = 0; index < cPropSpec; index++) {
|
|
bFoundProp = FALSE;
|
|
|
|
for (propIndex = 0; propIndex < NUM_WIA_MANAGED_PROPS; propIndex++) {
|
|
|
|
if (pPropSpec[index].ulKind == PRSPEC_LPWSTR) {
|
|
if (wcscmp(s_pszItemNameType[propIndex], pPropSpec[index].lpwstr) == 0) {
|
|
bFoundProp = TRUE;
|
|
break;
|
|
}
|
|
} else if (s_piItemNameType[propIndex] == pPropSpec[index].propid) {
|
|
bFoundProp = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!bFoundProp) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return bFoundProp;
|
|
}
|
|
|
|
HRESULT _stdcall SetValidProfileNames(
|
|
BYTE *pbData,
|
|
DWORD dwSize,
|
|
IWiaItem *pIWiaItem)
|
|
{
|
|
DBG_FN(::StripProfileNames);
|
|
HRESULT hr;
|
|
ULONG ulNumStrings = 0;
|
|
LPTSTR szProfileName = (LPTSTR) pbData;
|
|
BSTR bstrDefault = NULL;
|
|
BSTR *bstrValidProfiles = NULL;
|
|
ULONG ulIndex = 0;
|
|
|
|
USES_CONVERSION;
|
|
|
|
//
|
|
// Count number of strings
|
|
//
|
|
|
|
while ((BYTE*)szProfileName < (pbData + dwSize)) {
|
|
if (szProfileName[0] != TEXT('\0')) {
|
|
ulNumStrings++;
|
|
szProfileName += lstrlen(szProfileName);
|
|
}
|
|
szProfileName++;
|
|
}
|
|
|
|
if (ulNumStrings == 0) {
|
|
DBG_ERR(("StripProfileNames, No profile names!"));
|
|
return E_FAIL;
|
|
}
|
|
|
|
//
|
|
// Allocate memory for the string array
|
|
//
|
|
|
|
szProfileName = (LPTSTR)pbData;
|
|
|
|
bstrDefault = SysAllocString(T2W(szProfileName));
|
|
bstrValidProfiles = (BSTR*) LocalAlloc(LPTR, ulNumStrings * sizeof(BSTR));
|
|
if (!bstrValidProfiles || !bstrDefault) {
|
|
DBG_ERR(("StripProfileNames, could not allocate memory!"));
|
|
hr = E_OUTOFMEMORY;
|
|
} else {
|
|
memset(bstrValidProfiles, 0, ulNumStrings * sizeof(BSTR));
|
|
}
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
//
|
|
// Set the string values.
|
|
//
|
|
|
|
for (ulIndex = 0; ulIndex < ulNumStrings; ulIndex++) {
|
|
if (szProfileName[0] != TEXT('\0')) {
|
|
bstrValidProfiles[ulIndex] = SysAllocString(T2W(szProfileName));
|
|
if (!bstrValidProfiles[ulIndex]) {
|
|
DBG_ERR(("StripProfileNames, could not allocate strings!"));
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
szProfileName += (lstrlen(szProfileName) + 1);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set the valid values and the current value
|
|
//
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
hr = wiasSetValidListStr((BYTE*) pIWiaItem,
|
|
WIA_IPA_ICM_PROFILE_NAME,
|
|
ulNumStrings,
|
|
bstrDefault,
|
|
bstrValidProfiles);
|
|
if (SUCCEEDED(hr)) {
|
|
hr = wiasWritePropStr((BYTE*) pIWiaItem,
|
|
WIA_IPA_ICM_PROFILE_NAME,
|
|
bstrDefault);
|
|
if (FAILED(hr)) {
|
|
DBG_ERR(("StripProfileNames, could not set default color profiles!"));
|
|
}
|
|
|
|
} else {
|
|
DBG_ERR(("StripProfileNames, could not set valid list of color profiles!"));
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free memory
|
|
//
|
|
|
|
if (bstrDefault) {
|
|
SysFreeString(bstrDefault);
|
|
bstrDefault = NULL;
|
|
}
|
|
|
|
if (bstrValidProfiles) {
|
|
for (ulIndex = 0; ulIndex < ulNumStrings; ulIndex++) {
|
|
if (bstrValidProfiles[ulIndex]) {
|
|
SysFreeString(bstrValidProfiles[ulIndex]);
|
|
}
|
|
}
|
|
LocalFree(bstrValidProfiles);
|
|
bstrValidProfiles = NULL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* FillICMPropertyFromRegistry
|
|
*
|
|
* This helper method is called to fill the item properties with the ICM
|
|
* color profile names from a specified device's registry entries.
|
|
* NOTE: This function assumes this is called on a Root before it's called
|
|
* on its children!
|
|
*
|
|
* Arguments:
|
|
*
|
|
* IWiaItem - WIA item
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Status
|
|
*
|
|
* History:
|
|
*
|
|
* 10/10/1999 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HRESULT _stdcall FillICMPropertyFromRegistry(
|
|
IWiaPropertyStorage *pDevInfoProps,
|
|
IWiaItem *pIWiaItem)
|
|
{
|
|
DBG_FN(::FillICMPropertyFromRegistry);
|
|
PROPSPEC pspec[1] = {{PRSPEC_PROPID, WIA_DIP_DEV_ID}};
|
|
PROPVARIANT pvName[1];
|
|
HRESULT hr = E_FAIL;
|
|
BYTE *pbData = NULL;
|
|
DWORD dwType = 0;
|
|
DWORD dwSize = 0;
|
|
LONG lItemType = 0;
|
|
|
|
CWiaItem *pRoot = NULL;
|
|
|
|
USES_CONVERSION;
|
|
|
|
//
|
|
// Check whether this is the root item. If it is, read the ICM values from the
|
|
// registry, and cache it.
|
|
// NOTE: This should be moved into the STI_WIA_DEVICE_INFORMATION member of
|
|
// ACTIVE_DEVICE, and filled in when STI_WIA_DEVICE_INFORMATION is
|
|
// filled for the first time. This should increase performance.
|
|
// If it isn't the root item, then get the cached ICM values from the root, and
|
|
// fill them in.
|
|
//
|
|
|
|
hr = pIWiaItem->GetItemType(&lItemType);
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
if (lItemType & WiaItemTypeRoot) {
|
|
|
|
//
|
|
// This is a root item, so cache the ICM values.
|
|
// Start by getting the device name...
|
|
//
|
|
|
|
pRoot = (CWiaItem*) pIWiaItem;
|
|
|
|
if (pDevInfoProps) {
|
|
//
|
|
// Get the color profile names. First get the size, then get the value.
|
|
//
|
|
hr = g_pDevMan->GetDeviceValue(pRoot->m_pActiveDevice,
|
|
STI_DEVICE_VALUE_ICM_PROFILE,
|
|
&dwType,
|
|
NULL,
|
|
&dwSize);
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
pbData = (BYTE*) LocalAlloc(LPTR, dwSize);
|
|
if (pbData) {
|
|
dwType = REG_BINARY;
|
|
hr = g_pDevMan->GetDeviceValue(pRoot->m_pActiveDevice,
|
|
STI_DEVICE_VALUE_ICM_PROFILE,
|
|
&dwType,
|
|
pbData,
|
|
&dwSize);
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
//
|
|
// Store the ICM value with this root item.
|
|
//
|
|
|
|
pRoot->m_pICMValues = pbData;
|
|
pRoot->m_lICMSize = dwSize;
|
|
|
|
} else {
|
|
DBG_WRN(("FillICMPropertyFromRegistry, could not get ICM profile value!"));
|
|
LocalFree(pbData);
|
|
}
|
|
} else {
|
|
hr = E_OUTOFMEMORY;
|
|
DBG_ERR(("FillICMPropertyFromRegistry, not enough memory for ICM values!"));
|
|
}
|
|
} else {
|
|
DBG_WRN(("FillICMPropertyFromRegistry, could not get ICM profile size!"));
|
|
}
|
|
} else {
|
|
DBG_ERR(("FillICMPropertyFromRegistry, no property stream provided!"));
|
|
}
|
|
|
|
//
|
|
// Always set the return to S_OK if this is the root. Even if the color profile could not
|
|
// be read, when it comes time for the child items to have their profile property filled in,
|
|
// they'll simply get the standard sRGB one instead.
|
|
//
|
|
|
|
hr = S_OK;
|
|
} else {
|
|
|
|
//
|
|
// This is not a root item, so get the cached ICM values from the root
|
|
// and fill in the ICM property.
|
|
//
|
|
|
|
hr = pIWiaItem->GetRootItem((IWiaItem**) &pRoot);
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
//
|
|
// Check whether a cached ICM profile list exists. Get a standard one if it doesn't, else
|
|
// just set the property.
|
|
//
|
|
|
|
if (!pRoot->m_pICMValues ||
|
|
FAILED(hr = SetValidProfileNames(pRoot->m_pICMValues, pRoot->m_lICMSize, pIWiaItem)))
|
|
{
|
|
TCHAR szSRGB[MAX_PATH] = {TEXT('\0')};
|
|
|
|
dwSize = sizeof(szSRGB);
|
|
if (GetStandardColorSpaceProfile(NULL,
|
|
LCS_sRGB,
|
|
szSRGB,
|
|
&dwSize))
|
|
{
|
|
hr = SetValidProfileNames((BYTE*)szSRGB, dwSize, pIWiaItem);
|
|
DBG_TRC(("FillICMPropertyFromRegistry, using default color space profile"));
|
|
|
|
} else {
|
|
DBG_ERR(("FillICMPropertyFromRegistry, GetStandardColorSpaceProfile failed!"));
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
|
|
pRoot->Release();
|
|
} else {
|
|
DBG_ERR(("FillICMPropertyFromRegistry, could not get root item!"));
|
|
}
|
|
}
|
|
} else {
|
|
DBG_ERR(("FillICMPropertyFromRegistry, could not get item type!"));
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* GetParentItem
|
|
*
|
|
* Returns the item's parent
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pItem - WIA item
|
|
* ppItem - address to store the parent item.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Status
|
|
*
|
|
* History:
|
|
*
|
|
* 01/14/2000 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HRESULT _stdcall GetParentItem(CWiaItem *pItem, CWiaItem **ppParent)
|
|
{
|
|
DBG_FN(::GetParentItem);
|
|
CWiaTree *pTree, *pParentTree;
|
|
HRESULT hr = S_OK;
|
|
|
|
pTree = pItem->GetTreePtr();
|
|
if (pTree) {
|
|
|
|
hr = pTree->GetParentItem(&pParentTree);
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
if (hr == S_OK) {
|
|
pParentTree->GetItemData((VOID**) ppParent);
|
|
}
|
|
} else {
|
|
DBG_ERR(("GetParentItem, could not get root item tree!"));
|
|
}
|
|
} else {
|
|
DBG_ERR(("GetParentItem, item's tree ptr is NULL!"));
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* GetBufferValues
|
|
*
|
|
* Fills in the buffer size properties of the WIA_EXTENDED_TRANSFER_INFO
|
|
* struct.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pCWiaItem - WIA item
|
|
* pTransInfo - Pointer to the extended transfer information struct.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Status
|
|
*
|
|
* History:
|
|
*
|
|
* 01/23/2000 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HRESULT _stdcall GetBufferValues(
|
|
CWiaItem *pCWiaItem,
|
|
PWIA_EXTENDED_TRANSFER_INFO pTransInfo)
|
|
{
|
|
DBG_FN(::GetBufferValues);
|
|
HRESULT hr = S_OK;
|
|
IPropertyStorage *pIValidStg = NULL;
|
|
PROPSPEC ps[1] = {{PRSPEC_PROPID, WIA_IPA_BUFFER_SIZE}};
|
|
PROPVARIANT pv[1];
|
|
|
|
//
|
|
// Get the valid values for the WIA_IPA_BUFFER_SIZE property.
|
|
// NOTE: The WIA_IPA_BUFFER_SIZE property used to be the
|
|
// WIA_IPA_MIN_BUFFER_SIZE property. If we can't
|
|
// read the valid values for WIA_IPA_BUFFER_SIZE,
|
|
// we must read the current value of WIA_IP_MIN_BUFFER_SIZE
|
|
// and "guess" the other values instead.
|
|
// This is to facilitate drivers that were made with early versions
|
|
// of the WIA DDK.
|
|
//
|
|
|
|
hr = pCWiaItem->GetItemPropStreams(NULL, NULL, &pIValidStg, NULL);
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
PropVariantInit(pv);
|
|
|
|
hr = pIValidStg->ReadMultiple(1, ps, pv);
|
|
if (hr == S_OK) {
|
|
|
|
//
|
|
// Check that the returned property really has enough elements
|
|
// to specify min, max and nominal values. If not, set hr to
|
|
// fail so that we catch our attempt to reach MIN_BUFFER_SIZE
|
|
// instead.
|
|
//
|
|
|
|
if (pv[0].cal.cElems == WIA_RANGE_NUM_ELEMS) {
|
|
|
|
//
|
|
// Valid values for WIA_IPA_BUFFER_SIZE found, so
|
|
// set the returns.
|
|
|
|
pTransInfo->ulMinBufferSize = pv[0].cal.pElems[WIA_RANGE_MIN];
|
|
pTransInfo->ulOptimalBufferSize = pv[0].cal.pElems[WIA_RANGE_NOM];
|
|
pTransInfo->ulMaxBufferSize = pv[0].cal.pElems[WIA_RANGE_MAX];
|
|
} else {
|
|
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
|
|
if (hr != S_OK) {
|
|
|
|
//
|
|
// Attempt to read the current value of WIA_IPA_MIN_BUFFER_SIZE,
|
|
// since we couldn't find the values we wanted under
|
|
// WIA_IPA_BUFFER_SIZE.
|
|
//
|
|
|
|
IPropertyStorage *pICurrentStg = NULL;
|
|
|
|
PropVariantClear(pv);
|
|
|
|
hr = pCWiaItem->GetItemPropStreams(&pICurrentStg, NULL, NULL, NULL);
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
//
|
|
// Note that we can re-use ps, since the propid's of
|
|
// MIN_BUFFER_SIZE and BUFFER_SIZE are the same.
|
|
//
|
|
|
|
hr = pICurrentStg->ReadMultiple(1, ps, pv);
|
|
if (hr == S_OK) {
|
|
|
|
//
|
|
// Current value for WIA_IPA_MIN_BUFFER_SIZE found, so
|
|
// set the returns.
|
|
|
|
pTransInfo->ulMinBufferSize = pv[0].lVal;
|
|
pTransInfo->ulOptimalBufferSize = pv[0].lVal;
|
|
pTransInfo->ulMaxBufferSize = LONG_MAX;
|
|
} else {
|
|
DBG_ERR(("GetBufferValues, Could not read (valid) WIA_IPA_BUFFER_SIZE or (current) WIA_IPA_MIN_BUFFER_SIZE!"));
|
|
hr = E_INVALIDARG;
|
|
}
|
|
} else {
|
|
DBG_ERR(("GetBufferValues, Could not get item prop streams!"));
|
|
}
|
|
}
|
|
PropVariantClear(pv);
|
|
} else {
|
|
DBG_ERR(("GetBufferValues, failed to get item prop streams!"));
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* BQADScale
|
|
*
|
|
* This routine implements Byron's Quick And Dirty scaling algorithm. This
|
|
* specific implementation is meant for 1, 8, or 24bit only. Caller
|
|
* is responsible for all parameter checks!
|
|
*
|
|
* Please note: this is assumed to scale a band of BITMAP data. As such,
|
|
* the source should contain DWORD aligned pixel data, and the ouput buffer
|
|
* will contain DWORD aligned pixel data upon return.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pSrcBuffer - Pointer to the source buffer
|
|
* lSrcWidth - the source data width in pixels
|
|
* lSrcHeight - the source data height in pixels
|
|
* lSrcDepth - the bit depth of the source data
|
|
* pDestBuffer - Pointer to the destination buffer
|
|
* lDestWidth - the resultant width in pixels
|
|
* lDestHeight - the resultant height in pixels
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Status
|
|
*
|
|
* History:
|
|
*
|
|
* 08/28/2000 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HRESULT _stdcall BQADScale(BYTE* pSrcBuffer,
|
|
LONG lSrcWidth,
|
|
LONG lSrcHeight,
|
|
LONG lSrcDepth,
|
|
BYTE* pDestBuffer,
|
|
LONG lDestWidth,
|
|
LONG lDestHeight)
|
|
{
|
|
//
|
|
// We only deal with 1, 8 and 24 bit data
|
|
//
|
|
|
|
if ((lSrcDepth != 8) && (lSrcDepth != 1) && (lSrcDepth != 24)) {
|
|
DBG_ERR(("BQADScale, We only scale 1bit, 8bit or 24bit data right now, data is %dbit\n", lSrcDepth));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Make adjustments so we also work in all supported bit depths. We can get a performance increase
|
|
// by having separate implementations of all of these, but for now, we stick to a single generic
|
|
// implementation.
|
|
//
|
|
|
|
LONG lBytesPerPixel = (lSrcDepth + 7) / 8; // This is the ceiling of the number of
|
|
// bytes needed to hold a single pixel
|
|
ULONG lSrcRawWidth = ((lSrcWidth * lSrcDepth) + 7) / 8; // This is the width in bytes
|
|
ULONG lSrcWidthInBytes; // This is the DWORD-aligned width
|
|
ULONG lDestWidthInBytes; // This is the DWORD-aligned width
|
|
|
|
//
|
|
// We need to work out the DWORD aligned width in bytes. Normally we would do this in one step
|
|
// using the supplied lSrcDepth, but we avoid arithmetic overflow conditions that happen
|
|
// in 24bit if we do it in 2 steps like this instead.
|
|
//
|
|
|
|
if (lSrcDepth == 1) {
|
|
lSrcWidthInBytes = (lSrcWidth + 7) / 8;
|
|
lDestWidthInBytes = (lDestWidth + 7) / 8;
|
|
} else {
|
|
lSrcWidthInBytes = (lSrcWidth * lBytesPerPixel);
|
|
lDestWidthInBytes = (lDestWidth * lBytesPerPixel);
|
|
}
|
|
lSrcWidthInBytes += (lSrcWidthInBytes % sizeof(DWORD)) ? (sizeof(DWORD) - (lSrcWidthInBytes % sizeof(DWORD))) : 0;
|
|
lDestWidthInBytes += (lDestWidthInBytes % sizeof(DWORD)) ? (sizeof(DWORD) - (lDestWidthInBytes % sizeof(DWORD))) : 0;
|
|
|
|
//
|
|
// Define local variables and do the initial calculations needed for
|
|
// the scaling algorithm
|
|
//
|
|
|
|
BYTE *pDestPixel = NULL;
|
|
BYTE *pSrcPixel = NULL;
|
|
BYTE *pEnd = NULL;
|
|
BYTE *pDestLine = NULL;
|
|
BYTE *pSrcLine = NULL;
|
|
BYTE *pEndLine = NULL;
|
|
|
|
LONG lXEndSize = lBytesPerPixel * lDestWidth;
|
|
|
|
LONG lXNum = lSrcWidth; // Numerator in X direction
|
|
LONG lXDen = lDestWidth; // Denomiator in X direction
|
|
LONG lXInc = (lXNum / lXDen) * lBytesPerPixel; // Increment in X direction
|
|
|
|
LONG lXDeltaInc = lXNum % lXDen; // DeltaIncrement in X direction
|
|
LONG lXRem = 0; // Remainder in X direction
|
|
|
|
LONG lYNum = lSrcHeight; // Numerator in Y direction
|
|
LONG lYDen = lDestHeight; // Denomiator in Y direction
|
|
LONG lYInc = (lYNum / lYDen) * lSrcWidthInBytes; // Increment in Y direction
|
|
LONG lYDeltaInc = lYNum % lYDen; // DeltaIncrement in Y direction
|
|
LONG lYDestInc = lDestWidthInBytes;
|
|
LONG lYRem = 0; // Remainder in Y direction
|
|
|
|
pSrcLine = pSrcBuffer; // This is where we start in the source
|
|
pDestLine = pDestBuffer; // This is the start of the destination buffer
|
|
// This is where we end overall
|
|
pEndLine = pDestBuffer + (lDestWidthInBytes * lDestHeight);
|
|
|
|
while (pDestLine < pEndLine) { // Start LoopY (Decides where the src and dest lines start)
|
|
|
|
pSrcPixel = pSrcLine; // We're starting at the beginning of a new line
|
|
pDestPixel = pDestLine;
|
|
// Calc. where we end the line
|
|
pEnd = pDestPixel + lXEndSize;
|
|
lXRem = 0; // Reset the remainder for the horizontal direction
|
|
|
|
while (pDestPixel < pEnd) { // Start LoopX (puts pixels in the destination line)
|
|
|
|
// Put the pixel
|
|
if (lBytesPerPixel > 1) {
|
|
pDestPixel[0] = pSrcPixel[0];
|
|
pDestPixel[1] = pSrcPixel[1];
|
|
pDestPixel[2] = pSrcPixel[2];
|
|
} else {
|
|
*pDestPixel = *pSrcPixel;
|
|
}
|
|
// Move the destination pointer to the next pixel
|
|
pDestPixel += lBytesPerPixel;
|
|
pSrcPixel += lXInc; // Move the source pointer over by the horizontal increment
|
|
lXRem += lXDeltaInc; // Increase the horizontal remainder - this decides when we "overflow"
|
|
|
|
if (lXRem >= lXDen) { // This is our "overflow" condition. It means we're now one
|
|
// pixel off.
|
|
// In Overflow case, we need to shift one pixel over
|
|
pSrcPixel += lBytesPerPixel;
|
|
lXRem -= lXDen; // Decrease the remainder by the X denominator. This is essentially
|
|
// lXRem MOD lXDen.
|
|
}
|
|
} // End LoopX (puts pixels in the destination line)
|
|
|
|
pSrcLine += lYInc; // We've finished a horizontal line, time to move to the next one
|
|
lYRem += lYDeltaInc; // Increase our vertical remainder. This decides when we "overflow"
|
|
|
|
if (lYRem > lYDen) { // This is our vertical overflow condition.
|
|
// We need to move to the next line down
|
|
pSrcLine += lSrcWidthInBytes;
|
|
lYRem -= lYDen; // Decrease the remainder by the Y denominator. This is essentially
|
|
// lYRem MOD lYDen.
|
|
}
|
|
pDestLine += lYDestInc; // Move the destination pointer to the start of the next line in the
|
|
// destination buffer
|
|
} // End LoopY (Decides where the src and dest lines start)
|
|
return S_OK;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* AllocReadRegistryString
|
|
*
|
|
* This function reads a REG_SZ value from the registry. The memory for
|
|
* the srting value ius allocated with new. The caller should use
|
|
* "delete" when it is finished with it.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* hKey - Registry key to read from
|
|
* *wszValueName - Value to read
|
|
* **pwszReturnValue - Addess of pointer that will receive the allocated
|
|
* string
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Status.
|
|
*
|
|
* History:
|
|
*
|
|
* 11/06/2000 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
HRESULT AllocReadRegistryString(
|
|
HKEY hKey,
|
|
WCHAR *wszValueName,
|
|
WCHAR **pwszReturnValue)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwError = 0;
|
|
DWORD cbData = 0;
|
|
DWORD dwType = REG_SZ;
|
|
|
|
if (!wszValueName || !pwszReturnValue) {
|
|
DBG_WRN(("::AllocReadRegistryString, NULL parameter"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*pwszReturnValue = NULL;
|
|
|
|
//
|
|
// Get the number of bytes neded to store the string value.
|
|
//
|
|
dwError = RegQueryValueExW(hKey,
|
|
wszValueName,
|
|
NULL,
|
|
&dwType,
|
|
NULL,
|
|
&cbData);
|
|
if (dwError == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Allocate the correct number of bytes (leave space for terminator)
|
|
//
|
|
*pwszReturnValue = (WCHAR*) new BYTE[cbData + sizeof(L"\0")];
|
|
if (*pwszReturnValue) {
|
|
memset(*pwszReturnValue, 0, cbData + sizeof(L"\0"));
|
|
|
|
//
|
|
// Get the string
|
|
//
|
|
dwError = RegQueryValueExW(hKey,
|
|
wszValueName,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)(*pwszReturnValue),
|
|
&cbData);
|
|
if (dwError == ERROR_SUCCESS) {
|
|
} else {
|
|
DBG_WRN(("::AllocReadRegistryString, second RegQueryValueExW returned %d", dwError));
|
|
hr = HRESULT_FROM_WIN32(dwError);
|
|
}
|
|
} else {
|
|
DBG_WRN(("::AllocReadRegistryString, Out of memory!"));
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
} else {
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
if (hr != S_OK) {
|
|
if (*pwszReturnValue) {
|
|
delete[] *pwszReturnValue;
|
|
}
|
|
*pwszReturnValue = NULL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* AllocCopyString
|
|
*
|
|
* This function copies a widestring. The memory for the string is
|
|
* allocated with new. The caller should use "delete" to free the string
|
|
* when it is finished with it.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* wszString - WideString to copy.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Pointer to newly allocated string. Null otherwise.
|
|
*
|
|
* History:
|
|
*
|
|
* 11/06/2000 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
WCHAR* AllocCopyString(
|
|
WCHAR* wszString)
|
|
{
|
|
WCHAR *wszOut = NULL;
|
|
ULONG ulLen = 0;
|
|
|
|
//
|
|
// Get length of string including terminating NULL
|
|
//
|
|
ulLen = lstrlenW(wszString) + 2;
|
|
|
|
//
|
|
// Allocate memory for the string
|
|
//
|
|
wszOut = new WCHAR[ulLen];
|
|
if (wszOut) {
|
|
|
|
//
|
|
// Copy it
|
|
//
|
|
lstrcpynW(wszOut, wszString, ulLen);
|
|
}
|
|
return wszOut;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* AllocCatString
|
|
*
|
|
* This function concatenates 2 strings. The memory for the string is
|
|
* allocated with new. The caller should use "delete []" to free the string
|
|
* when it is finished with it.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* wszString1 - First WideString.
|
|
* wszString2 - Second WideString to add to first.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Pointer to newly allocated string. Null otherwise.
|
|
*
|
|
* History:
|
|
*
|
|
* 16/02/2001 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
WCHAR* AllocCatString(WCHAR* wszString1, WCHAR* wszString2)
|
|
{
|
|
WCHAR *wszOut = NULL;
|
|
ULONG ulLen = 0;
|
|
|
|
//ASSERT (!wszString1 && !wszString2)
|
|
//
|
|
// Get length of string including terminating NULL
|
|
//
|
|
ulLen = lstrlenW(wszString1) + lstrlenW(wszString2) + 1;
|
|
|
|
//
|
|
// Allocate memory for the string
|
|
//
|
|
wszOut = new WCHAR[ulLen];
|
|
if (wszOut) {
|
|
|
|
//
|
|
// Copy 1st string
|
|
//
|
|
lstrcpynW(wszOut, wszString1, ulLen);
|
|
|
|
//
|
|
// Concatenate the strings
|
|
//
|
|
lstrcpynW(wszOut + lstrlenW(wszOut), wszString2, ulLen - lstrlenW(wszOut));
|
|
|
|
//
|
|
// Always terminate the string
|
|
//
|
|
wszOut[ulLen - 1] = L'\0';
|
|
}
|
|
return wszOut;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* ReadRegistryDWORD
|
|
*
|
|
* This function reads a dword value from the registry.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* hKey - Registry key to read from
|
|
* wszValueName - Value to read from key
|
|
* pdwReturnValue - Address of variable to receive the data
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Status
|
|
*
|
|
* History:
|
|
*
|
|
* 11/06/2000 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
HRESULT ReadRegistryDWORD(
|
|
HKEY hKey,
|
|
WCHAR *wszValueName,
|
|
DWORD *pdwReturnValue)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwError = 0;
|
|
DWORD cbData = sizeof(DWORD);
|
|
DWORD dwType = REG_DWORD;
|
|
|
|
if (!pdwReturnValue || !wszValueName) {
|
|
DBG_WRN(("::ReadRegistryDWORD called with NULL"));
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
*pdwReturnValue = 0;
|
|
dwError = RegQueryValueExW(hKey,
|
|
wszValueName,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)pdwReturnValue,
|
|
&cbData);
|
|
if (dwError != ERROR_SUCCESS) {
|
|
|
|
DBG_TRC(("::ReadRegistryDWORD, RegQueryValueExW returned %d", dwError));
|
|
hr = HRESULT_FROM_WIN32(dwError);
|
|
}
|
|
if (FAILED(hr)) {
|
|
*pdwReturnValue = 0;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* CreateDevInfoFromHKey
|
|
*
|
|
* This function creates and fills out a DEVICE_INFO struct. Most of
|
|
* the information is read from the registry. This is called for Devnode
|
|
* and interface devices (volume devices don't have registry entries)
|
|
*
|
|
* Arguments:
|
|
*
|
|
* hKeyDev - Device registry key
|
|
* dwDeviceState - The device state
|
|
* pspDevInfoData - The devnode data
|
|
* pspDevInterfaceData - The interface data - will be NULL for devnode
|
|
* devices.
|
|
* Return Value:
|
|
*
|
|
* Pointer to newly created DEVICE_INFO struct. NULL if one could not
|
|
* be allocated.
|
|
*
|
|
* History:
|
|
*
|
|
* 11/06/2000 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
DEVICE_INFO* CreateDevInfoFromHKey(
|
|
HKEY hKeyDev,
|
|
DWORD dwDeviceState,
|
|
SP_DEVINFO_DATA *pspDevInfoData,
|
|
SP_DEVICE_INTERFACE_DATA *pspDevInterfaceData)
|
|
{
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
DEVICE_INFO *pDeviceInfo = NULL;
|
|
HKEY hDeviceDataKey = NULL;
|
|
DWORD dwMajorType = 0;
|
|
DWORD dwMinorType = 0;
|
|
BOOL bFatalError = FALSE;
|
|
|
|
DWORD dwTemp;
|
|
WCHAR *wszTemp = NULL;
|
|
|
|
|
|
pDeviceInfo = new DEVICE_INFO;
|
|
if (!pDeviceInfo) {
|
|
DBG_WRN(("CWiaDevMan::CreateDevInfoFromHKey, Out of memory"));
|
|
return NULL;
|
|
}
|
|
memset(pDeviceInfo, 0, sizeof(DEVICE_INFO));
|
|
pDeviceInfo->bValid = FALSE;
|
|
pDeviceInfo->dwDeviceState = dwDeviceState;
|
|
//
|
|
// Copy the SP_DEVINFO_DATA and SP_DEVICE_INTERFACE_DATA
|
|
//
|
|
if (pspDevInfoData) {
|
|
memmove(&pDeviceInfo->spDevInfoData, pspDevInfoData, sizeof(SP_DEVINFO_DATA));
|
|
if (pspDevInterfaceData) {
|
|
memmove(&pDeviceInfo->spDevInterfaceData, pspDevInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA));
|
|
}
|
|
}
|
|
|
|
//
|
|
// NOTE: To avoid any alignment faults, we read into &wszTemp, then assign wszTemp to
|
|
// the appropriate structure member.
|
|
//
|
|
hr = AllocReadRegistryString(hKeyDev, REGSTR_VAL_DEVICE_ID_W, &wszTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_WRN(("::CreateDevInfoFromHKey, Failed to read %ws, fatal for this device (NULL name)", REGSTR_VAL_DEVICE_ID_W));
|
|
bFatalError = TRUE;
|
|
} else {
|
|
pDeviceInfo->wszDeviceInternalName = wszTemp;
|
|
}
|
|
hr = AllocReadRegistryString(hKeyDev, REGSTR_VAL_DEVICE_ID_W, &wszTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_WRN(("::CreateDevInfoFromHKey, Failed to read %ws (remote), fatal for this device (NULL name)", REGSTR_VAL_DEVICE_ID_W));
|
|
bFatalError = TRUE;
|
|
} else {
|
|
pDeviceInfo->wszDeviceRemoteName = wszTemp;
|
|
}
|
|
hr = AllocReadRegistryString(hKeyDev, REGSTR_VAL_USD_CLASS_W, &wszTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_WRN(("::CreateDevInfoFromHKey, Failed to read %ws, fatal for this device (%ws)", REGSTR_VAL_USD_CLASS_W, pDeviceInfo->wszDeviceInternalName));
|
|
bFatalError = TRUE;
|
|
} else {
|
|
pDeviceInfo->wszUSDClassId = wszTemp;
|
|
}
|
|
hr = AllocReadRegistryString(hKeyDev, REGSTR_VAL_VENDOR_NAME_W, &wszTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", REGSTR_VAL_VENDOR_NAME_W, pDeviceInfo->wszDeviceInternalName));
|
|
} else {
|
|
pDeviceInfo->wszVendorDescription = wszTemp;
|
|
}
|
|
hr = AllocReadRegistryString(hKeyDev, REGSTR_VAL_DEVICE_NAME_W, &wszTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", REGSTR_VAL_DEVICE_NAME_W, pDeviceInfo->wszDeviceInternalName));
|
|
} else {
|
|
pDeviceInfo->wszDeviceDescription = wszTemp;
|
|
}
|
|
hr = AllocReadRegistryString(hKeyDev, REGSTR_VAL_DEVICEPORT_W, &wszTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", REGSTR_VAL_DEVICEPORT_W, pDeviceInfo->wszDeviceInternalName));
|
|
} else {
|
|
pDeviceInfo->wszPortName = wszTemp;
|
|
}
|
|
hr = AllocReadRegistryString(hKeyDev, REGSTR_VAL_PROP_PROVIDER_W, &wszTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", REGSTR_VAL_PROP_PROVIDER_W, pDeviceInfo->wszDeviceInternalName));
|
|
} else {
|
|
pDeviceInfo->wszPropProvider = wszTemp;
|
|
}
|
|
hr = AllocReadRegistryString(hKeyDev, REGSTR_VAL_FRIENDLY_NAME_W, &wszTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", REGSTR_VAL_FRIENDLY_NAME_W, pDeviceInfo->wszDeviceInternalName));
|
|
} else {
|
|
pDeviceInfo->wszLocalName = wszTemp;
|
|
}
|
|
hr = ReadRegistryDWORD(hKeyDev, REGSTR_VAL_HARDWARE_W, &dwTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", REGSTR_VAL_HARDWARE_W, pDeviceInfo->wszDeviceInternalName));
|
|
} else {
|
|
pDeviceInfo->dwHardwareConfiguration = dwTemp;
|
|
}
|
|
hr = ReadRegistryDWORD(hKeyDev, REGSTR_VAL_DEVICETYPE_W, &dwMajorType);
|
|
if (FAILED(hr)) {
|
|
DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", REGSTR_VAL_DEVICETYPE_W, pDeviceInfo->wszDeviceInternalName));
|
|
}
|
|
hr = ReadRegistryDWORD(hKeyDev, REGSTR_VAL_DEVICESUBTYPE_W, &dwMinorType);
|
|
if (FAILED(hr)) {
|
|
DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", REGSTR_VAL_DEVICESUBTYPE_W, pDeviceInfo->wszDeviceInternalName));
|
|
}
|
|
pDeviceInfo->DeviceType = MAKELONG(dwMinorType,dwMajorType);
|
|
hr = ReadRegistryDWORD(hKeyDev, REGSTR_VAL_GENERIC_CAPS_W, &dwTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", REGSTR_VAL_GENERIC_CAPS_W, pDeviceInfo->wszDeviceInternalName));
|
|
} else {
|
|
pDeviceInfo->DeviceCapabilities.dwGenericCaps = dwTemp;
|
|
}
|
|
|
|
//
|
|
// Set the Internal Device type
|
|
//
|
|
|
|
pDeviceInfo->dwInternalType = INTERNAL_DEV_TYPE_REAL;
|
|
if (pDeviceInfo->DeviceCapabilities.dwGenericCaps & STI_GENCAP_WIA) {
|
|
pDeviceInfo->dwInternalType |= INTERNAL_DEV_TYPE_WIA;
|
|
}
|
|
if (pspDevInterfaceData) {
|
|
pDeviceInfo->dwInternalType |= INTERNAL_DEV_TYPE_INTERFACE;
|
|
}
|
|
|
|
//
|
|
// Read everything we can from DeviceData section under Device Registry Key
|
|
//
|
|
|
|
hr = RegCreateKeyExW(hKeyDev, REGSTR_VAL_DATA_W, NULL, NULL, REG_OPTION_NON_VOLATILE, KEY_READ,
|
|
NULL, &hDeviceDataKey, NULL);
|
|
hr = AllocReadRegistryString(hDeviceDataKey, WIA_DIP_SERVER_NAME_STR, &wszTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_WRN(("::CreateDevInfoFromHKey, Failed to read %ws, fatal for device (%ws)", WIA_DIP_SERVER_NAME_STR, pDeviceInfo->wszDeviceInternalName));
|
|
bFatalError = TRUE;
|
|
} else {
|
|
pDeviceInfo->wszServer = wszTemp;
|
|
if (!pDeviceInfo->wszServer) {
|
|
pDeviceInfo->wszServer = AllocCopyString(LOCAL_DEVICE_STR);
|
|
}
|
|
if (pDeviceInfo->wszServer) {
|
|
if (lstrcmpiW(pDeviceInfo->wszServer, LOCAL_DEVICE_STR) == 0) {
|
|
//
|
|
// Mark this device as being local
|
|
//
|
|
pDeviceInfo->dwInternalType |= INTERNAL_DEV_TYPE_LOCAL;
|
|
}
|
|
}
|
|
}
|
|
hr = AllocReadRegistryString(hDeviceDataKey, WIA_DIP_UI_CLSID_STR, &wszTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_WRN(("::CreateDevInfoFromHKey, Failed to read %ws, fatal for device (%ws)", WIA_DIP_SERVER_NAME_STR, pDeviceInfo->wszDeviceInternalName));
|
|
} else {
|
|
pDeviceInfo->wszUIClassId = wszTemp;
|
|
if (!pDeviceInfo->wszUIClassId) {
|
|
pDeviceInfo->wszUIClassId = AllocCopyString(DEF_UI_CLSID_STR);
|
|
}
|
|
}
|
|
hr = AllocReadRegistryString(hDeviceDataKey, REGSTR_VAL_BAUDRATE, &wszTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", REGSTR_VAL_BAUDRATE, pDeviceInfo->wszDeviceInternalName));
|
|
} else {
|
|
|
|
if (( pDeviceInfo->dwHardwareConfiguration & STI_HW_CONFIG_SERIAL ) &&
|
|
(hr == S_FALSE)) {
|
|
//
|
|
// Only for serial devices we need to set default baud rate in case it is not set in the
|
|
// registry.
|
|
pDeviceInfo->wszBaudRate = AllocCopyString(DEF_BAUD_RATE_STR);
|
|
} else {
|
|
pDeviceInfo->wszBaudRate = wszTemp;
|
|
}
|
|
DBG_TRC(("::CreateDevInfoFromHKey, Read baud rate %ws ",pDeviceInfo->wszBaudRate));
|
|
}
|
|
hr = ReadRegistryDWORD(hDeviceDataKey, STI_DEVICE_VALUE_HOLDINGTIME_W, &dwTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", STI_DEVICE_VALUE_HOLDINGTIME_W, pDeviceInfo->wszDeviceInternalName));
|
|
} else {
|
|
pDeviceInfo->dwLockHoldingTime = dwTemp;
|
|
}
|
|
hr = ReadRegistryDWORD(hDeviceDataKey, STI_DEVICE_VALUE_TIMEOUT, &dwTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", STI_DEVICE_VALUE_TIMEOUT, pDeviceInfo->wszDeviceInternalName));
|
|
} else {
|
|
pDeviceInfo->dwPollTimeout = dwTemp;
|
|
}
|
|
hr = ReadRegistryDWORD(hDeviceDataKey, STI_DEVICE_VALUE_DISABLE_NOTIFICATIONS, &dwTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", STI_DEVICE_VALUE_DISABLE_NOTIFICATIONS, pDeviceInfo->wszDeviceInternalName));
|
|
} else {
|
|
pDeviceInfo->dwDisableNotifications = dwTemp;
|
|
}
|
|
RegCloseKey(hDeviceDataKey);
|
|
|
|
if (!bFatalError) {
|
|
pDeviceInfo->bValid = TRUE;
|
|
} else {
|
|
DBG_WRN(("::CreateDevInfoFromHKey, marking device info. as invalid"));
|
|
}
|
|
|
|
return pDeviceInfo;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* RefreshDevInfoFromHKey
|
|
*
|
|
* This function refreshes fields that are subject to change
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pDeviceInfo - Pointer to the DEVICE_INFO struct to update
|
|
* hKeyDev - Device registry key
|
|
* dwDeviceState - The new device state
|
|
* pspDevInfoData - The devnode data
|
|
* pspDevInterfaceData - The interface data - will be NULL for devnode
|
|
* devices.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* True - Everything successfully updated
|
|
* False - Could not update
|
|
*
|
|
* History:
|
|
*
|
|
* 11/06/2000 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
BOOL RefreshDevInfoFromHKey(
|
|
DEVICE_INFO *pDeviceInfo,
|
|
HKEY hKeyDev,
|
|
DWORD dwDeviceState,
|
|
SP_DEVINFO_DATA *pspDevInfoData,
|
|
SP_DEVICE_INTERFACE_DATA *pspDevInterfaceData)
|
|
{
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
BOOL Succeeded = TRUE;
|
|
|
|
WCHAR *wszTemp = NULL;
|
|
|
|
//
|
|
// Set new device state
|
|
//
|
|
pDeviceInfo->dwDeviceState = dwDeviceState;
|
|
|
|
//
|
|
// Copy the SP_DEVINFO_DATA and SP_DEVICE_INTERFACE_DATA
|
|
//
|
|
|
|
if (pspDevInfoData) {
|
|
memcpy(&pDeviceInfo->spDevInfoData, pspDevInfoData, sizeof(SP_DEVINFO_DATA));
|
|
if (pspDevInterfaceData) {
|
|
memcpy(&pDeviceInfo->spDevInterfaceData, pspDevInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set new port name. First free the old one if it exists
|
|
//
|
|
if (pDeviceInfo->wszPortName) {
|
|
delete [] pDeviceInfo->wszPortName;
|
|
pDeviceInfo->wszPortName = NULL;
|
|
}
|
|
hr = AllocReadRegistryString(hKeyDev, REGSTR_VAL_DEVICEPORT_W, &wszTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_WRN(("::RefreshDevInfoFromHKey, Failed to update %ws, may be fatal for device (%ws)", REGSTR_VAL_DEVICEPORT_W, pDeviceInfo->wszDeviceInternalName));
|
|
Succeeded = FALSE;
|
|
} else {
|
|
pDeviceInfo->wszPortName = wszTemp;
|
|
}
|
|
|
|
//
|
|
// Grab new Local name. First free the old one...
|
|
//
|
|
if (pDeviceInfo->wszLocalName) {
|
|
delete [] pDeviceInfo->wszLocalName;
|
|
pDeviceInfo->wszLocalName = NULL;
|
|
}
|
|
hr = AllocReadRegistryString(hKeyDev, REGSTR_VAL_FRIENDLY_NAME_W, &wszTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_TRC(("::RefreshDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", REGSTR_VAL_FRIENDLY_NAME_W, pDeviceInfo->wszDeviceInternalName));
|
|
} else {
|
|
pDeviceInfo->wszLocalName = wszTemp;
|
|
}
|
|
|
|
//
|
|
// Grab new Device Description. First free the old one...
|
|
//
|
|
if (pDeviceInfo->wszDeviceDescription) {
|
|
delete [] pDeviceInfo->wszDeviceDescription;
|
|
pDeviceInfo->wszDeviceDescription = NULL;
|
|
}
|
|
hr = AllocReadRegistryString(hKeyDev, REGSTR_VAL_DEVICE_NAME_W, &wszTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_TRC(("::RefreshDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", REGSTR_VAL_DEVICE_NAME_W, pDeviceInfo->wszDeviceInternalName));
|
|
} else {
|
|
pDeviceInfo->wszDeviceDescription = wszTemp;
|
|
}
|
|
|
|
//
|
|
// Grab new Vendor name. First free the old one...
|
|
//
|
|
if (pDeviceInfo->wszVendorDescription) {
|
|
delete [] pDeviceInfo->wszVendorDescription;
|
|
pDeviceInfo->wszVendorDescription = NULL;
|
|
}
|
|
hr = AllocReadRegistryString(hKeyDev, REGSTR_VAL_VENDOR_NAME_W, &wszTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_TRC(("::RefreshDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", REGSTR_VAL_VENDOR_NAME_W, pDeviceInfo->wszDeviceInternalName));
|
|
} else {
|
|
pDeviceInfo->wszVendorDescription = wszTemp;
|
|
}
|
|
|
|
return Succeeded;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* RefreshDevInfoFromMountPoint
|
|
*
|
|
* This function refreshes fields that are subject to change for volume
|
|
* devices.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pDeviceInfo - Pointer to the DEVICE_INFO struct to update
|
|
*
|
|
* Return Value:
|
|
*
|
|
* True - Everything successfully updated
|
|
* False - Could not update
|
|
*
|
|
* History:
|
|
*
|
|
* 16/03/2001 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
BOOL RefreshDevInfoFromMountPoint(
|
|
DEVICE_INFO *pDeviceInfo,
|
|
WCHAR *wszMountPoint)
|
|
{
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
BOOL Succeeded = TRUE;
|
|
|
|
WCHAR wszLabel[MAX_PATH];
|
|
|
|
//
|
|
// Grab the friendly name of the FS device
|
|
//
|
|
|
|
hr = GetMountPointLabel(wszMountPoint, wszLabel, sizeof(wszLabel) / sizeof(wszLabel[0]));
|
|
if (FAILED(hr)) {
|
|
DBG_WRN(("RefreshDevInfoFromMountPoint, GetMountPointLabel failed - could not get display name - using mount point instead"));
|
|
lstrcpynW(wszLabel, wszMountPoint, sizeof(wszLabel) / sizeof(wszLabel[0]));
|
|
}
|
|
|
|
//
|
|
// Update the appropriate fields that rely on the display name.
|
|
//
|
|
if (pDeviceInfo->wszVendorDescription) {
|
|
delete [] pDeviceInfo->wszVendorDescription;
|
|
pDeviceInfo->wszVendorDescription = NULL;
|
|
}
|
|
if (pDeviceInfo->wszDeviceDescription) {
|
|
delete [] pDeviceInfo->wszDeviceDescription;
|
|
pDeviceInfo->wszDeviceDescription = NULL;
|
|
}
|
|
if (pDeviceInfo->wszLocalName) {
|
|
delete [] pDeviceInfo->wszLocalName;
|
|
pDeviceInfo->wszLocalName = NULL;
|
|
}
|
|
|
|
pDeviceInfo->wszVendorDescription = AllocCopyString(wszLabel);
|
|
pDeviceInfo->wszDeviceDescription = AllocCopyString(wszLabel);
|
|
pDeviceInfo->wszLocalName = AllocCopyString(wszLabel);
|
|
|
|
return Succeeded;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
* CreateDevInfoForFSDriver
|
|
*
|
|
* Create a device info struct containing all the relevant info for our
|
|
* volume devices.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* wszMountPoint - The mount point of this volume
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Pointer to a newly created DEVICE_INFO. NULL on error.
|
|
*
|
|
* History:
|
|
*
|
|
* 11/06/2000 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
DEVICE_INFO* CreateDevInfoForFSDriver(WCHAR *wszMountPoint)
|
|
{
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
DEVICE_INFO *pDeviceInfo = NULL;
|
|
BOOL bFatalError = FALSE;
|
|
DWORD dwMajorType = StiDeviceTypeDigitalCamera;
|
|
DWORD dwMinorType = 1;
|
|
|
|
WCHAR wszDevId[STI_MAX_INTERNAL_NAME_LENGTH];
|
|
WCHAR wszLabel[MAX_PATH];
|
|
|
|
pDeviceInfo = new DEVICE_INFO;
|
|
if (!pDeviceInfo) {
|
|
DBG_WRN(("CWiaDevMan::CreateDevInfoForFSDriver, Out of memory"));
|
|
return NULL;
|
|
}
|
|
memset(pDeviceInfo, 0, sizeof(DEVICE_INFO));
|
|
memset(wszDevId, 0, sizeof(wszDevId));
|
|
|
|
//
|
|
// Grab the friendly name of the FS device
|
|
//
|
|
|
|
hr = GetMountPointLabel(wszMountPoint, wszLabel, sizeof(wszLabel) / sizeof(wszLabel[0]));
|
|
if (FAILED(hr)) {
|
|
DBG_WRN(("CWiaDevMan::CreateDevInfoForFSDriver, GetMountPointLabel failed - could not get display name - using mount point instead"));
|
|
lstrcpynW(wszLabel, wszMountPoint, sizeof(wszLabel) / sizeof(wszLabel[0]));
|
|
}
|
|
|
|
pDeviceInfo->bValid = FALSE;
|
|
pDeviceInfo->dwDeviceState = 0;
|
|
|
|
pDeviceInfo->wszAlternateID = AllocCopyString(wszMountPoint);
|
|
if (!pDeviceInfo->wszAlternateID) {
|
|
DBG_WRN(("::CreateDevInfoForFSDriver, out of memory allocating wszAlternateID"));
|
|
bFatalError = TRUE;
|
|
}
|
|
|
|
//
|
|
// Construct Device ID. Device ID looks like:
|
|
// {MountPoint}
|
|
// e.g. {e:\}
|
|
//
|
|
|
|
lstrcpyW(wszDevId, L"{");
|
|
//
|
|
// We don't want to overrun our internal name length constarint, so we first check
|
|
// to see whether the string length of wszMountPoint is short enough to allow concatenation
|
|
// of {, }, wszMountPoint and NULL terminator, and still fit all this into a string of
|
|
// length STI_MAX_INTERNAL_NAME_LENGTH.
|
|
// Note the space after the brackets in sizeof(L"{} ").
|
|
//
|
|
if (lstrlenW(wszMountPoint) > (STI_MAX_INTERNAL_NAME_LENGTH - (sizeof(L"{} ") / sizeof(WCHAR)))) {
|
|
//
|
|
// The name is too long, so we just insert our own name instead
|
|
//
|
|
lstrcatW(wszDevId, L"NameTooLong");
|
|
} else {
|
|
lstrcatW(wszDevId, wszMountPoint);
|
|
}
|
|
lstrcatW(wszDevId, L"}");
|
|
|
|
pDeviceInfo->wszDeviceInternalName = AllocCopyString(wszDevId);
|
|
if (!pDeviceInfo->wszAlternateID) {
|
|
DBG_WRN(("::CreateDevInfoForFSDriver, out of memory allocating wszDeviceInternalName"));
|
|
bFatalError = TRUE;
|
|
}
|
|
pDeviceInfo->wszDeviceRemoteName = AllocCopyString(wszDevId);
|
|
if (!pDeviceInfo->wszDeviceRemoteName) {
|
|
DBG_WRN(("::CreateDevInfoForFSDriver, out of memory allocating wszDeviceRemoteName"));
|
|
bFatalError = TRUE;
|
|
}
|
|
pDeviceInfo->wszPortName = AllocCopyString(wszMountPoint);
|
|
if (!pDeviceInfo->wszPortName) {
|
|
DBG_WRN(("::CreateDevInfoForFSDriver, out of memory allocating wszPortName"));
|
|
bFatalError = TRUE;
|
|
}
|
|
pDeviceInfo->wszUSDClassId = AllocCopyString(FS_USD_CLSID);
|
|
if (!pDeviceInfo->wszUSDClassId) {
|
|
DBG_WRN(("::CreateDevInfoForFSDriver, out of memory allocating wszUSDClassId"));
|
|
bFatalError = TRUE;
|
|
}
|
|
|
|
//
|
|
// We can't get the manufacturer string for these devices, so
|
|
// load our standard Manufacturer resource string
|
|
// (something like "(Not available)").
|
|
//
|
|
WCHAR wszManufacturer[32];
|
|
|
|
INT iRet = LoadStringW(g_hInst,
|
|
IDS_MSC_MANUFACTURER_STR,
|
|
wszManufacturer,
|
|
sizeof(wszManufacturer)/sizeof(wszManufacturer[0]));
|
|
if (iRet) {
|
|
pDeviceInfo->wszVendorDescription = AllocCopyString(wszManufacturer);
|
|
} else {
|
|
//
|
|
// Can't load it, so give it an empty string
|
|
//
|
|
pDeviceInfo->wszVendorDescription = AllocCopyString(L"");
|
|
}
|
|
pDeviceInfo->wszDeviceDescription = AllocCopyString(wszLabel);
|
|
pDeviceInfo->wszLocalName = AllocCopyString(wszLabel);
|
|
pDeviceInfo->wszServer = AllocCopyString(LOCAL_DEVICE_STR);
|
|
pDeviceInfo->wszBaudRate = NULL;
|
|
pDeviceInfo->wszUIClassId = AllocCopyString(FS_UI_CLSID);
|
|
|
|
pDeviceInfo->dwDeviceState = DEV_STATE_ACTIVE;
|
|
pDeviceInfo->DeviceType = MAKELONG(dwMinorType,dwMajorType);
|
|
pDeviceInfo->dwLockHoldingTime = 0;
|
|
pDeviceInfo->dwPollTimeout = 0;
|
|
pDeviceInfo->dwDisableNotifications = 0;
|
|
pDeviceInfo->DeviceCapabilities.dwVersion = STI_VERSION_REAL;
|
|
pDeviceInfo->DeviceCapabilities.dwGenericCaps = STI_GENCAP_WIA;
|
|
pDeviceInfo->dwHardwareConfiguration = HEL_DEVICE_TYPE_WDM;
|
|
pDeviceInfo->dwInternalType = INTERNAL_DEV_TYPE_WIA | INTERNAL_DEV_TYPE_LOCAL;
|
|
//
|
|
// Check whther this volume is really a camera device representing
|
|
// itself as a volume...
|
|
//
|
|
if (IsMassStorageCamera(wszMountPoint)) {
|
|
pDeviceInfo->dwInternalType |= INTERNAL_DEV_TYPE_MSC_CAMERA;
|
|
|
|
//
|
|
// Here is a good time to set up the Device's registry entries. We'll call
|
|
// g_pDevMan->GetHKeyFromMountPoint(..), since this has the effect of creating
|
|
// the keys if the don't exist.
|
|
//
|
|
HKEY hKeyDev = g_pDevMan->GetHKeyFromMountPoint(wszMountPoint);
|
|
if (hKeyDev) {
|
|
RegCloseKey(hKeyDev);
|
|
}
|
|
} else {
|
|
pDeviceInfo->dwInternalType |= INTERNAL_DEV_TYPE_VOL;
|
|
}
|
|
|
|
if (!bFatalError) {
|
|
pDeviceInfo->bValid = TRUE;
|
|
} else {
|
|
pDeviceInfo->bValid = FALSE;
|
|
}
|
|
|
|
return pDeviceInfo;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
* CreateDevInfoForRemoteDevice
|
|
*
|
|
* Create a device info struct containing all the relevant info for our
|
|
* remote devices.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* hKeyDev - Device registry key
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Pointer to a newly created DEVICE_INFO. NULL on error.
|
|
*
|
|
* History:
|
|
*
|
|
* 15/02/2001 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
DEVICE_INFO* CreateDevInfoForRemoteDevice(
|
|
HKEY hKeyDev)
|
|
{
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
DEVICE_INFO *pDeviceInfo = NULL;
|
|
BOOL bFatalError = FALSE;
|
|
|
|
DWORD dwTemp;
|
|
WCHAR *wszTemp = NULL;
|
|
|
|
|
|
pDeviceInfo = new DEVICE_INFO;
|
|
if (!pDeviceInfo) {
|
|
DBG_WRN(("::CreateDevInfoForRemoteDevice, Out of memory"));
|
|
return NULL;
|
|
}
|
|
memset(pDeviceInfo, 0, sizeof(DEVICE_INFO));
|
|
pDeviceInfo->bValid = FALSE;
|
|
|
|
//
|
|
// Always assume remote devices are ACTIVE
|
|
//
|
|
pDeviceInfo->dwDeviceState = DEV_STATE_ACTIVE;
|
|
|
|
|
|
//
|
|
// NOTE: To avoid any alignment faults, we read into &wszTemp, then assign wszTemp to
|
|
// the appropriate structure member.
|
|
//
|
|
hr = AllocReadRegistryString(hKeyDev, WIA_DIP_SERVER_NAME_STR, &wszTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, fatal for device (%ws)", WIA_DIP_SERVER_NAME_STR, pDeviceInfo->wszServer));
|
|
bFatalError = TRUE;
|
|
} else {
|
|
pDeviceInfo->wszServer = wszTemp;
|
|
}
|
|
hr = AllocReadRegistryString(hKeyDev, WIA_DIP_REMOTE_DEV_ID_STR, &wszTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, fatal for device (%ws)", WIA_DIP_REMOTE_DEV_ID_STR, pDeviceInfo->wszDeviceRemoteName));
|
|
bFatalError = TRUE;
|
|
} else {
|
|
pDeviceInfo->wszDeviceRemoteName = wszTemp;
|
|
}
|
|
pDeviceInfo->wszDeviceInternalName = AllocCatString(pDeviceInfo->wszServer, pDeviceInfo->wszDeviceRemoteName);
|
|
if (!pDeviceInfo->wszDeviceInternalName) {
|
|
DBG_TRC(("::CreateDevInfoFromHKey, Failed allocate memory for Device Name, fatal for device (%ws)", pDeviceInfo->wszDeviceInternalName));
|
|
bFatalError = TRUE;
|
|
}
|
|
hr = AllocReadRegistryString(hKeyDev, WIA_DIP_VEND_DESC_STR, &wszTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", WIA_DIP_VEND_DESC_STR, pDeviceInfo->wszDeviceInternalName));
|
|
} else {
|
|
pDeviceInfo->wszVendorDescription = wszTemp;
|
|
}
|
|
hr = AllocReadRegistryString(hKeyDev, WIA_DIP_DEV_NAME_STR, &wszTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", WIA_DIP_DEV_NAME_STR, pDeviceInfo->wszDeviceInternalName));
|
|
} else {
|
|
pDeviceInfo->wszLocalName = wszTemp;
|
|
}
|
|
hr = AllocReadRegistryString(hKeyDev, WIA_DIP_DEV_DESC_STR, &wszTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", WIA_DIP_DEV_DESC_STR, pDeviceInfo->wszDeviceInternalName));
|
|
} else {
|
|
pDeviceInfo->wszDeviceDescription = wszTemp;
|
|
}
|
|
hr = AllocReadRegistryString(hKeyDev, WIA_DIP_PORT_NAME_STR, &wszTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", WIA_DIP_PORT_NAME_STR, pDeviceInfo->wszDeviceInternalName));
|
|
} else {
|
|
pDeviceInfo->wszPortName = wszTemp;
|
|
}
|
|
hr = AllocReadRegistryString(hKeyDev, WIA_DIP_UI_CLSID_STR, &wszTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", WIA_DIP_UI_CLSID_STR, pDeviceInfo->wszDeviceInternalName));
|
|
} else {
|
|
pDeviceInfo->wszUIClassId = wszTemp;
|
|
}
|
|
hr = ReadRegistryDWORD(hKeyDev, WIA_DIP_DEV_TYPE_STR, &dwTemp);
|
|
if (FAILED(hr)) {
|
|
DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", WIA_DIP_DEV_TYPE_STR, pDeviceInfo->wszDeviceInternalName));
|
|
} else {
|
|
pDeviceInfo->DeviceType = dwTemp;
|
|
}
|
|
pDeviceInfo->DeviceCapabilities.dwGenericCaps = STI_GENCAP_WIA;
|
|
|
|
//
|
|
// Set the Internal Device type
|
|
//
|
|
|
|
pDeviceInfo->dwInternalType = INTERNAL_DEV_TYPE_REAL | INTERNAL_DEV_TYPE_WIA;
|
|
|
|
if (!bFatalError) {
|
|
pDeviceInfo->bValid = TRUE;
|
|
} else {
|
|
|
|
//
|
|
// If it's not valid, free the memory
|
|
// TDB: Remove the bValid field
|
|
//
|
|
DestroyDevInfo(pDeviceInfo);
|
|
pDeviceInfo = NULL;
|
|
}
|
|
|
|
return pDeviceInfo;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
* DestroyDevInfo
|
|
*
|
|
* Frees up any resources help by the DEVICE_INFO struct (like strings).
|
|
* It will then delete the structure itsself.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pInfo - Pointer to DEVICE_INFO struct
|
|
*
|
|
* Return Value:
|
|
*
|
|
* None.
|
|
*
|
|
* History:
|
|
*
|
|
* 11/06/2000 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
VOID DestroyDevInfo(DEVICE_INFO *pInfo)
|
|
{
|
|
if (pInfo) {
|
|
|
|
//
|
|
// Free struct members first
|
|
//
|
|
|
|
if (pInfo->wszAlternateID) {
|
|
delete [] pInfo->wszAlternateID;
|
|
pInfo->wszAlternateID = NULL;
|
|
}
|
|
if (pInfo->wszUSDClassId) {
|
|
delete [] pInfo->wszUSDClassId;
|
|
pInfo->wszUSDClassId = NULL;
|
|
}
|
|
if (pInfo->wszDeviceInternalName) {
|
|
delete [] pInfo->wszDeviceInternalName;
|
|
pInfo->wszDeviceInternalName = NULL;
|
|
}
|
|
if (pInfo->wszDeviceRemoteName) {
|
|
delete [] pInfo->wszDeviceRemoteName;
|
|
pInfo->wszDeviceRemoteName = NULL;
|
|
}
|
|
if (pInfo->wszVendorDescription) {
|
|
delete [] pInfo->wszVendorDescription;
|
|
pInfo->wszVendorDescription = NULL;
|
|
}
|
|
if (pInfo->wszDeviceDescription) {
|
|
delete [] pInfo->wszDeviceDescription;
|
|
pInfo->wszDeviceDescription = NULL;
|
|
}
|
|
if (pInfo->wszPortName) {
|
|
delete [] pInfo->wszPortName;
|
|
pInfo->wszPortName = NULL;
|
|
}
|
|
if (pInfo->wszPropProvider) {
|
|
delete [] pInfo->wszPropProvider;
|
|
pInfo->wszPropProvider = NULL;
|
|
}
|
|
if (pInfo->wszLocalName) {
|
|
delete [] pInfo->wszLocalName;
|
|
pInfo->wszLocalName = NULL;
|
|
}
|
|
if (pInfo->wszServer) {
|
|
delete [] pInfo->wszServer;
|
|
pInfo->wszServer = NULL;
|
|
}
|
|
if (pInfo->wszBaudRate) {
|
|
delete [] pInfo->wszBaudRate;
|
|
pInfo->wszBaudRate = NULL;
|
|
}
|
|
if (pInfo->wszUIClassId) {
|
|
delete [] pInfo->wszUIClassId;
|
|
pInfo->wszUIClassId = NULL;
|
|
}
|
|
|
|
//
|
|
// Now free the struct itsself. NOTE: The caller must
|
|
// not attempt to use this pointer again!
|
|
//
|
|
|
|
delete pInfo;
|
|
|
|
}
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* DumpDevInfo
|
|
*
|
|
* Used for debugging, this dumps a few members of the DEVICE_INFO struct.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pInfo - Pointer to DEVICE_INFO struct
|
|
*
|
|
* Return Value:
|
|
*
|
|
* None.
|
|
*
|
|
* History:
|
|
*
|
|
* 11/06/2000 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
VOID DumpDevInfo(DEVICE_INFO *pInfo)
|
|
{
|
|
if (pInfo) {
|
|
DBG_PRT(("------------------------------------------------", pInfo));
|
|
DBG_PRT(("::DumpDevInfo (0x%08X)", pInfo));
|
|
//
|
|
// Output field values we're interested in
|
|
//
|
|
|
|
DBG_PRT(("\t\t bValid (%d)", pInfo->bValid));
|
|
DBG_PRT(("\t\t wszLocalName \t(%ws)", pInfo->wszLocalName));
|
|
DBG_PRT(("\t\t wszInternalName \t(%ws)", pInfo->wszDeviceInternalName));
|
|
DBG_PRT(("\t\t wszRemoteName \t(%ws)", pInfo->wszDeviceRemoteName));
|
|
DBG_PRT(("\t\t wszAlternateID \t(%ws)", pInfo->wszAlternateID));
|
|
DBG_PRT(("\t\t wszPortName \t(%ws)", pInfo->wszPortName));
|
|
DBG_PRT(("\t\t dwInternalType \t(%d)", pInfo->dwInternalType));
|
|
DBG_PRT(("------------------------------------------------", pInfo));
|
|
}
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* CreateDevInfoStg
|
|
*
|
|
* This helper method takes a DEVICE_INFO struct and creates an
|
|
* IWiaPropertyStorage filled with the appropriate entries.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pInfo - Pointer to DEVICE_INFO struct
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Pointer to IWiaPropertyStorage. Will be NULL on error.
|
|
*
|
|
* History:
|
|
*
|
|
* 11/06/2000 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
IWiaPropertyStorage* CreateDevInfoStg(DEVICE_INFO *pInfo)
|
|
{
|
|
CWIADevInfo *pWiaDevInfo = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
ULONG ulIndex = 0;
|
|
WCHAR *wszTmp = NULL;
|
|
PROPID propid = 0;
|
|
PROPSPEC propspec[WIA_NUM_DIP];
|
|
PROPVARIANT propvar[WIA_NUM_DIP];
|
|
WCHAR wszVer[MAX_PATH];
|
|
|
|
IWiaPropertyStorage *pIWiaPropStg = NULL;
|
|
|
|
//
|
|
// Create the CWIADevInfo class
|
|
//
|
|
|
|
pWiaDevInfo = new CWIADevInfo();
|
|
if (!pWiaDevInfo) {
|
|
return NULL;
|
|
}
|
|
|
|
hr = pWiaDevInfo->Initialize();
|
|
if (SUCCEEDED(hr)) {
|
|
//
|
|
// Insert the properties
|
|
//
|
|
// Set the property specifications and data. Order must match DEVMANGR.IDL
|
|
memset(propspec, 0, sizeof(PROPSPEC) * WIA_NUM_DIP);
|
|
memset(propvar, 0, sizeof(VARIANT) * WIA_NUM_DIP);
|
|
memset(wszVer ,0, sizeof(wszVer));
|
|
|
|
for (ulIndex = 0; ulIndex < WIA_NUM_DIP; ulIndex++) {
|
|
|
|
propid = g_piDeviceInfo[ulIndex];
|
|
wszTmp = NULL;
|
|
|
|
// Setup property specification.
|
|
propspec[ulIndex].ulKind = PRSPEC_PROPID;
|
|
propspec[ulIndex].propid = propid;
|
|
|
|
propvar[ulIndex].vt = VT_BSTR;
|
|
propvar[ulIndex].bstrVal = NULL;
|
|
|
|
switch (propid) {
|
|
|
|
case WIA_DIP_DEV_ID:
|
|
wszTmp = pInfo->wszDeviceInternalName;
|
|
break;
|
|
|
|
case WIA_DIP_REMOTE_DEV_ID:
|
|
wszTmp = pInfo->wszDeviceRemoteName;
|
|
break;
|
|
|
|
case WIA_DIP_SERVER_NAME:
|
|
wszTmp = pInfo->wszServer;
|
|
break;
|
|
|
|
case WIA_DIP_VEND_DESC:
|
|
wszTmp = pInfo->wszVendorDescription;
|
|
break;
|
|
|
|
case WIA_DIP_DEV_DESC:
|
|
wszTmp = pInfo->wszDeviceDescription;
|
|
break;
|
|
|
|
case WIA_DIP_DEV_TYPE:
|
|
propvar[ulIndex].vt = VT_I4;
|
|
propvar[ulIndex].lVal = (LONG) pInfo->DeviceType;
|
|
break;
|
|
|
|
case WIA_DIP_PORT_NAME:
|
|
wszTmp = pInfo->wszPortName;
|
|
break;
|
|
|
|
case WIA_DIP_DEV_NAME:
|
|
wszTmp = pInfo->wszLocalName;
|
|
break;
|
|
|
|
case WIA_DIP_UI_CLSID:
|
|
wszTmp = pInfo->wszUIClassId;
|
|
break;
|
|
|
|
case WIA_DIP_HW_CONFIG:
|
|
propvar[ulIndex].vt = VT_I4;
|
|
propvar[ulIndex].lVal = (LONG) pInfo->dwHardwareConfiguration;
|
|
break;
|
|
|
|
case WIA_DIP_BAUDRATE:
|
|
wszTmp = pInfo->wszBaudRate;
|
|
break;
|
|
|
|
case WIA_DIP_STI_GEN_CAPABILITIES:
|
|
propvar[ulIndex].vt = VT_I4;
|
|
propvar[ulIndex].lVal = (LONG) pInfo->DeviceCapabilities.dwGenericCaps;
|
|
break;
|
|
|
|
case WIA_DIP_WIA_VERSION:
|
|
wsprintf(wszVer,L"%d.%d",LOWORD(STI_VERSION_REAL),HIWORD(STI_VERSION_REAL));
|
|
wszTmp = wszVer;
|
|
break;
|
|
|
|
case WIA_DIP_DRIVER_VERSION:
|
|
if(FALSE == GetDriverDLLVersion(pInfo,wszVer,sizeof(wszVer))){
|
|
DBG_WRN(("GetDriverDLLVersion, unable to alloc get driver version resource information, defaulting to 0.0.0.0"));
|
|
lstrcpyW(wszVer,L"0.0.0.0");
|
|
}
|
|
wszTmp = wszVer;
|
|
break;
|
|
|
|
default:
|
|
hr = E_FAIL;
|
|
DBG_ERR(("CreateDevInfoStg, Unknown device property"));
|
|
DBG_ERR((" propid = %li",propid));
|
|
}
|
|
|
|
// Allocate and assign BSTR's.
|
|
if (propvar[ulIndex].vt == VT_BSTR) {
|
|
if (wszTmp) {
|
|
propvar[ulIndex].bstrVal = SysAllocString(wszTmp);
|
|
if (!propvar[ulIndex].bstrVal) {
|
|
DBG_WRN(("CreateDevInfoStg, unable to alloc dev info strings"));
|
|
}
|
|
} else {
|
|
DBG_TRC(("CreateDevInfoStg, NULL device property string"));
|
|
DBG_TRC((" propid = %li",propid));
|
|
propvar[ulIndex].bstrVal = SysAllocString(L"Empty");
|
|
}
|
|
}
|
|
}
|
|
|
|
IPropertyStorage *pIPropStg = pWiaDevInfo->m_pIPropStg;
|
|
|
|
if (pIPropStg) {
|
|
// Set the device information properties.
|
|
hr = pIPropStg->WriteMultiple(WIA_NUM_DIP,
|
|
propspec,
|
|
propvar,
|
|
WIA_DIP_FIRST);
|
|
// Write the property names.
|
|
if (SUCCEEDED(hr)) {
|
|
hr = pIPropStg->WritePropertyNames(WIA_NUM_DIP,
|
|
g_piDeviceInfo,
|
|
g_pszDeviceInfo);
|
|
if (SUCCEEDED(hr)) {
|
|
hr = pWiaDevInfo->QueryInterface(IID_IWiaPropertyStorage, (void**) &pIWiaPropStg);
|
|
} else {
|
|
DBG_WRN(("CreateDevInfoStg, WritePropertyNames Failed (0x%X)", hr));
|
|
}
|
|
}
|
|
else {
|
|
ReportReadWriteMultipleError(hr, "CreateDevInfoStg", NULL, FALSE, WIA_NUM_DIP, propspec);
|
|
}
|
|
} else {
|
|
DBG_WRN(("CreateDevInfoStg, IPropertyStorage is NULL"));
|
|
hr = E_UNEXPECTED;
|
|
}
|
|
|
|
// Free the allocated BSTR's.
|
|
FreePropVariantArray(WIA_NUM_DIP, propvar);
|
|
}
|
|
|
|
|
|
//
|
|
// On failure, delete pWiaDevInfo
|
|
//
|
|
if (FAILED(hr)) {
|
|
if (pWiaDevInfo) {
|
|
delete pWiaDevInfo;
|
|
pWiaDevInfo = NULL;
|
|
pIWiaPropStg = NULL;
|
|
}
|
|
}
|
|
return pIWiaPropStg;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* _CoCreateInstanceInConsoleSession
|
|
*
|
|
* This helper function acts the same as CoCreateInstance, but will launch
|
|
* a out-of-process COM server on the correct user's desktop, taking
|
|
* fast user switching into account. (Normal CoCreateInstance will
|
|
* launch it on the first logged on user's desktop, instead of the currently
|
|
* logged on one).
|
|
*
|
|
* This code was taken with permission from the Shell's Hardware
|
|
* Notification service, on behalf of StephStm.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* rclsid, // Class identifier (CLSID) of the object
|
|
* pUnkOuter, // Pointer to controlling IUnknown
|
|
* dwClsContext // Context for running executable code
|
|
* riid, // Reference to the identifier of the interface
|
|
* ppv // Address of output variable that receives
|
|
* // the interface pointer requested in riid
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Status
|
|
*
|
|
* History:
|
|
*
|
|
* 03/01/2001 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HRESULT _CoCreateInstanceInConsoleSession(REFCLSID rclsid,
|
|
IUnknown* punkOuter,
|
|
DWORD dwClsContext,
|
|
REFIID riid,
|
|
void** ppv)
|
|
{
|
|
IBindCtx *pbc = NULL;
|
|
HRESULT hr = CreateBindCtx(0, &pbc); // Create a bind context for use with Moniker
|
|
|
|
//
|
|
// Set the return
|
|
//
|
|
*ppv = NULL;
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
WCHAR wszCLSID[39];
|
|
|
|
//
|
|
// Convert the riid to GUID string for use in binding to moniker
|
|
//
|
|
if (StringFromGUID2(rclsid, wszCLSID, sizeof(wszCLSID)/sizeof(wszCLSID[0]))) {
|
|
ULONG ulEaten = 0;
|
|
IMoniker* pmoniker = NULL;
|
|
WCHAR wszDisplayName[sizeof(SESSION_MONIKER)/sizeof(WCHAR) + sizeof(wszCLSID)/sizeof(wszCLSID[0]) + 2] = SESSION_MONIKER;
|
|
|
|
//
|
|
// We want something like: "Session:Console!clsid:760befd0-5b0b-44d7-957e-969af35ce954"
|
|
// Notice that we don't want the leading and trailing brackets {..} around the GUID.
|
|
// So, first get rid of trailing bracket by overwriting it with termintaing '\0'
|
|
//
|
|
wszCLSID[lstrlenW(wszCLSID) - 1] = L'\0';
|
|
|
|
//
|
|
// Form display name string. To get rid of the leading bracket, we pass in the
|
|
// address of the next character as the start of the string.
|
|
//
|
|
if (lstrcatW(wszDisplayName, &(wszCLSID[1]))) {
|
|
|
|
//
|
|
// Parse the name and get a moniker:
|
|
//
|
|
|
|
hr = MkParseDisplayName(pbc, wszDisplayName, &ulEaten, &pmoniker);
|
|
if (SUCCEEDED(hr)) {
|
|
IClassFactory *pcf = NULL;
|
|
|
|
//
|
|
// Attempt to get the class factory
|
|
//
|
|
hr = pmoniker->BindToObject(pbc, NULL, IID_IClassFactory, (void**)&pcf);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Attempt to create the object
|
|
//
|
|
hr = pcf->CreateInstance(punkOuter, riid, ppv);
|
|
|
|
DBG_TRC(("_CoCreateInstanceInConsoleSession, pcf->CreateInstance returned: hr = 0x%08X", hr));
|
|
pcf->Release();
|
|
} else {
|
|
|
|
DBG_WRN(("_CoCreateInstanceInConsoleSession, pmoniker->BindToObject returned: hr = 0x%08X", hr));
|
|
}
|
|
pmoniker->Release();
|
|
} else {
|
|
DBG_WRN(("_CoCreateInstanceInConsoleSession, MkParseDisplayName returned: hr = 0x%08X", hr));
|
|
}
|
|
} else {
|
|
DBG_WRN(("_CoCreateInstanceInConsoleSession, string concatenation failed"));
|
|
hr = E_INVALIDARG;
|
|
}
|
|
} else {
|
|
DBG_WRN(("_CoCreateInstanceInConsoleSession, StringFromGUID2 failed"));
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
pbc->Release();
|
|
} else {
|
|
DBG_WRN(("_CoCreateInstanceInConsoleSession, CreateBindCtxt returned: hr = 0x%08X", hr));
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* GetUserTokenForConsoleSession
|
|
*
|
|
* This helper function will grab the currently logged on interactive
|
|
* user's token, which can be used in a call to CreateProcessAsUser.
|
|
* Caller is responsible for closing this Token handle.
|
|
*
|
|
* It first grabs the impersontaed token from the current session (our
|
|
* service runs in session 0, but with Fast User Switching, the currently
|
|
* active user may be in a different session). It then creates a
|
|
* primary token from the impersonated one.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* None
|
|
*
|
|
* Return Value:
|
|
*
|
|
* HANDLE to Token for logged on user in the currently active session.
|
|
* NULL otherwise.
|
|
*
|
|
* History:
|
|
*
|
|
* 03/05/2001 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HANDLE GetUserTokenForConsoleSession()
|
|
{
|
|
HANDLE hImpersonationToken = NULL;
|
|
HANDLE hTokenUser = NULL;
|
|
|
|
|
|
//
|
|
// Get interactive user's token
|
|
//
|
|
|
|
if (GetWinStationUserToken(GetCurrentSessionID(), &hImpersonationToken)) {
|
|
|
|
//
|
|
// Maybe nobody is logged on, so do a check first.
|
|
//
|
|
|
|
if (hImpersonationToken) {
|
|
|
|
//
|
|
// We duplicate the token, since the returned token is an
|
|
// impersonated one, and we need it to be primary for
|
|
// use in CreateProcessAsUser.
|
|
//
|
|
if (!DuplicateTokenEx(hImpersonationToken,
|
|
0,
|
|
NULL,
|
|
SecurityImpersonation,
|
|
TokenPrimary,
|
|
&hTokenUser)) {
|
|
DBG_WRN(("CEventNotifier::StartCallbackProgram, DuplicateTokenEx failed! GetLastError() = 0x%08X", GetLastError()));
|
|
}
|
|
} else {
|
|
DBG_PRT(("CEventNotifier::StartCallbackProgram, No user appears to be logged on..."));
|
|
}
|
|
|
|
} else {
|
|
DBG_WRN(("CEventNotifier::StartCallbackProgram, GetWinStationUserToken failed! GetLastError() = 0x%08X", GetLastError()));
|
|
}
|
|
|
|
//
|
|
// Close the impersonated token, since we no longer need it.
|
|
//
|
|
if (hImpersonationToken) {
|
|
CloseHandle(hImpersonationToken);
|
|
}
|
|
|
|
return hTokenUser;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* IsMassStorageCamera
|
|
*
|
|
* This helper function will use the shell's CustomDeviceProperty API
|
|
* to check whether a given volume device (represented by it's mount point)
|
|
* reports itsself as a digital camera.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* wszMountPoint - The mount point for a specified volume.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* TRUE - The custom device property says this device is really a camera
|
|
* FALSE - This device is not reported as a camera
|
|
*
|
|
* History:
|
|
*
|
|
* 03/08/2001 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL IsMassStorageCamera(
|
|
WCHAR *wszMountPoint)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
IHWDeviceCustomProperties *pIHWDeviceCustomProperties = NULL;
|
|
BOOL bIsCamera = FALSE;
|
|
|
|
//
|
|
// CoCreate the CLSID_HWDeviceCustomProperties and grab the
|
|
// IHWDeviceCustomProperties interface.
|
|
//
|
|
hr = CoCreateInstance(CLSID_HWDeviceCustomProperties,
|
|
NULL,
|
|
CLSCTX_LOCAL_SERVER,
|
|
IID_IHWDeviceCustomProperties,
|
|
(VOID**)&pIHWDeviceCustomProperties);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
|
|
//
|
|
// Make sure we initialize the device property interface, so it
|
|
// will know which device we're talking about.
|
|
//
|
|
hr = pIHWDeviceCustomProperties->InitFromDeviceID(wszMountPoint,
|
|
HWDEVCUSTOMPROP_USEVOLUMEPROCESSING);
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
//
|
|
// Check whether this mass storage device is really a camera
|
|
//
|
|
DWORD dwVal = 0;
|
|
|
|
hr = pIHWDeviceCustomProperties->GetDWORDProperty(IS_DIGITAL_CAMERA_STR,
|
|
&dwVal);
|
|
if (SUCCEEDED(hr) && (dwVal == IS_DIGITAL_CAMERA_VAL)) {
|
|
bIsCamera = TRUE;
|
|
}
|
|
} else {
|
|
DBG_WRN(("IsMassStorageCamera, Initialize failed with (0x%08X)", hr));
|
|
}
|
|
|
|
pIHWDeviceCustomProperties->Release();
|
|
} else {
|
|
DBG_WRN(("IsMassStorageCamera, CoCreateInstance failed with (0x%08X)", hr));
|
|
}
|
|
|
|
//
|
|
// Log whether we think this device is a camera or not
|
|
//
|
|
DBG_PRT(("IsMassStorageCamera, Returning %ws for drive (%ws)", bIsCamera ? L"TRUE" : L"FALSE", wszMountPoint));
|
|
|
|
return bIsCamera;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* GetMountPointLabel
|
|
*
|
|
* This helper function is a replacement for SHGetFileInfoW. It will
|
|
* fill in the label string of the specified mountpoint.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* wszMountPoint - The mount point for a specified volume.
|
|
* pszLabel - Pointer to a caller allocated buffer
|
|
* cchLabel - Number of characters available in pszLabel
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Status
|
|
*
|
|
* History:
|
|
*
|
|
* 03/08/2001 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HRESULT GetMountPointLabel(WCHAR* wszMountPoint, LPTSTR pszLabel, DWORD cchLabel)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL fFoundIt = FALSE;
|
|
UINT uDriveType = GetDriveTypeW(wszMountPoint);
|
|
|
|
if (!wszMountPoint) {
|
|
DBG_WRN(("GetMountPointLabel, called with NULL string"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (!fFoundIt)
|
|
{
|
|
//
|
|
// Grab "Label" property, if it exists
|
|
//
|
|
//
|
|
// CoCreate the CLSID_HWDeviceCustomProperties and grab the
|
|
// IHWDeviceCustomProperties interface.
|
|
//
|
|
|
|
IHWDeviceCustomProperties *pIHWDeviceCustomProperties = NULL;
|
|
hr = CoCreateInstance(CLSID_HWDeviceCustomProperties,
|
|
NULL,
|
|
CLSCTX_LOCAL_SERVER,
|
|
IID_IHWDeviceCustomProperties,
|
|
(VOID**)&pIHWDeviceCustomProperties);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
|
|
//
|
|
// Make sure we initialize the device property interface, so it
|
|
// will know which device we're talking about.
|
|
//
|
|
|
|
hr = pIHWDeviceCustomProperties->InitFromDeviceID(wszMountPoint,
|
|
HWDEVCUSTOMPROP_USEVOLUMEPROCESSING);
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
//
|
|
// Check whether this mass storage device is really a camera
|
|
//
|
|
LPWSTR pwszLabel = NULL;
|
|
|
|
hr = pIHWDeviceCustomProperties->GetStringProperty(L"Label",
|
|
&pwszLabel);
|
|
if (SUCCEEDED(hr)) {
|
|
lstrcpynW(pszLabel, pwszLabel, cchLabel);
|
|
CoTaskMemFree(pwszLabel);
|
|
|
|
fFoundIt = TRUE;
|
|
}
|
|
} else {
|
|
DBG_WRN(("GetMountPointLabel, Initialize failed with (0x%08X)", hr));
|
|
}
|
|
|
|
pIHWDeviceCustomProperties->Release();
|
|
} else {
|
|
DBG_WRN(("GetMountPointLabel, CoCreateInstance failed with (0x%08X)", hr));
|
|
}
|
|
|
|
//
|
|
// Make sure to set hr to S_OK, since it is not a problem if we can't get the
|
|
// custom label (one might not exist).
|
|
//
|
|
hr = S_OK;
|
|
}
|
|
|
|
if (!fFoundIt)
|
|
{
|
|
//
|
|
// If the drive is REMOVABLE, and the mountpoint begins with 'A' or 'B', then it is considered
|
|
// a floppy drive. We only want to call GetVolumeInformationW(..) if it is NOT a floppy...
|
|
//
|
|
if (!((uDriveType == DRIVE_REMOVABLE) && ((towupper(wszMountPoint[0]) == L'A') || (towupper(wszMountPoint[0]) == L'B')))) {
|
|
|
|
//
|
|
// This is not a floppy, so find out its volume info.
|
|
//
|
|
if (!GetVolumeInformationW(wszMountPoint,
|
|
pszLabel,
|
|
cchLabel,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
0))
|
|
{
|
|
//
|
|
// Failure case
|
|
//
|
|
*pszLabel = 0;
|
|
} else {
|
|
fFoundIt = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!fFoundIt)
|
|
{
|
|
UINT uResId = 0;
|
|
INT iRet = 0;
|
|
|
|
switch (uDriveType)
|
|
{
|
|
case DRIVE_REMOVABLE:
|
|
uResId = IDS_DRIVES_REMOVABLE_STR;
|
|
break;
|
|
case DRIVE_CDROM:
|
|
uResId = IDS_DRIVES_CDROM_STR;
|
|
break;
|
|
case DRIVE_FIXED:
|
|
default:
|
|
uResId = IDS_DRIVES_FIXED_STR;
|
|
break;
|
|
}
|
|
iRet = LoadString(g_hInst,
|
|
uResId,
|
|
pszLabel,
|
|
cchLabel);
|
|
if (iRet) {
|
|
|
|
fFoundIt = TRUE;
|
|
} else {
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
|
|
if (fFoundIt) {
|
|
|
|
int iLabelLen = lstrlenW(pszLabel);
|
|
if ((iLabelLen + (sizeof(L" ()") / sizeof(WCHAR)) + lstrlenW(wszMountPoint)) < cchLabel)
|
|
{
|
|
int iLenToChopOff = 1;
|
|
|
|
lstrcatW(pszLabel, L" (");
|
|
lstrcatW(pszLabel, wszMountPoint);
|
|
lstrcpy(&pszLabel[lstrlenW(pszLabel) - iLenToChopOff], L")");
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* GetDriverDLLVersion
|
|
*
|
|
* This helper function is for reading a DLL version resource
|
|
* fill in the label string of the specified mountpoint.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* wszMountPoint - The mount point for a specified volume.
|
|
* pszLabel - Pointer to a caller allocated buffer
|
|
* cchLabel - Number of characters available in pszLabel
|
|
*
|
|
* Return Value:
|
|
*
|
|
* TRUE - The custom device property says this device is really a camera
|
|
* FALSE - This device is not reported as a camera
|
|
*
|
|
* History:
|
|
*
|
|
* 03/08/2001 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
BOOL GetDriverDLLVersion(DEVICE_INFO *pDeviceInfo, WCHAR *wszVersion, UINT uiSize)
|
|
{
|
|
BOOL bSuccess = FALSE;
|
|
if((NULL == wszVersion)||(NULL == pDeviceInfo)){
|
|
return bSuccess;
|
|
}
|
|
|
|
//
|
|
// clear the version string buffer
|
|
//
|
|
|
|
memset(wszVersion,0,uiSize);
|
|
|
|
//
|
|
// get COM DLL path from registry
|
|
//
|
|
|
|
CLSID clsid;
|
|
memset(&clsid,0,sizeof(clsid));
|
|
|
|
if (SUCCEEDED(CLSIDFromString(pDeviceInfo->wszUSDClassId, &clsid))) {
|
|
|
|
HKEY hk = NULL;
|
|
LONG lRet = 0;
|
|
WCHAR wszKey[MAX_PATH + 40];
|
|
|
|
//
|
|
// Look up the CLSID in HKEY_CLASSES_ROOT.
|
|
//
|
|
|
|
swprintf(wszKey, L"CLSID\\%s\\InProcServer32", pDeviceInfo->wszUSDClassId);
|
|
|
|
lRet = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszKey, 0, KEY_QUERY_VALUE, &hk);
|
|
if (lRet == ERROR_SUCCESS) {
|
|
|
|
WCHAR wszDll[MAX_PATH];
|
|
memset(wszDll,0,sizeof(wszDll));
|
|
|
|
LONG cb = 0;
|
|
|
|
cb = cbX(wszDll);
|
|
lRet = RegQueryValueW(hk, 0, wszDll, &cb);
|
|
|
|
if (lRet == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// get version information size
|
|
//
|
|
|
|
DWORD dwFileInfoVersionSize = GetFileVersionInfoSizeW(wszDll,NULL);
|
|
if (dwFileInfoVersionSize > 0) {
|
|
|
|
//
|
|
// allocate version information buffer
|
|
//
|
|
|
|
void *pFileVersionData = LocalAlloc(LPTR,dwFileInfoVersionSize);
|
|
if (pFileVersionData) {
|
|
memset(pFileVersionData,0,(dwFileInfoVersionSize));
|
|
|
|
//
|
|
// fill version information buffer
|
|
//
|
|
|
|
if (GetFileVersionInfoW(wszDll,NULL,dwFileInfoVersionSize, pFileVersionData)) {
|
|
VS_FIXEDFILEINFO *pFileVersionInfo = NULL;
|
|
UINT uLen = 0;
|
|
|
|
//
|
|
// extract file version from version information buffer
|
|
//
|
|
|
|
if (VerQueryValue(pFileVersionData,TEXT("\\"),(LPVOID*)&pFileVersionInfo, &uLen)) {
|
|
|
|
//
|
|
// write the dll version resource into the string buffer
|
|
//
|
|
|
|
wsprintf(wszVersion,L"%d.%d.%d.%d",
|
|
HIWORD(pFileVersionInfo->dwFileVersionMS),
|
|
LOWORD(pFileVersionInfo->dwFileVersionMS),
|
|
HIWORD(pFileVersionInfo->dwFileVersionLS),
|
|
LOWORD(pFileVersionInfo->dwFileVersionLS));
|
|
bSuccess = TRUE;
|
|
} else {
|
|
DBG_WRN(("GetDriverDLLVersion, VerQueryValue Failed"));
|
|
}
|
|
} else {
|
|
DBG_WRN(("GetDriverDLLVersion, GetFileVersionInfoW Failed"));
|
|
}
|
|
|
|
//
|
|
// free allocated memory
|
|
//
|
|
|
|
LocalFree(pFileVersionData);
|
|
pFileVersionData = NULL;
|
|
} else {
|
|
DBG_WRN(("GetDriverDLLVersion, Could not allocate memory for file version information"));
|
|
}
|
|
} else {
|
|
DBG_WRN(("GetDriverDLLVersion, File Version Information Size is < 0 (File may be missing version resource)"));
|
|
}
|
|
} else {
|
|
DBG_WRN(("GetDriverDLLVersion, No InprocServer32"));
|
|
}
|
|
|
|
//
|
|
// close registry KEY
|
|
//
|
|
|
|
RegCloseKey(hk);
|
|
|
|
} else {
|
|
DBG_WRN(("GetDriverDLLVersion, CLSID not registered"));
|
|
}
|
|
} else {
|
|
DBG_WRN(("GetDriverDLLVersion, Invalid CLSID string"));
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* CreateMSCRegEntries
|
|
*
|
|
* This helper function creates the registry sub-keys and value entries for
|
|
* an MSC Camera device.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* hDevRegKey - The relevent key under MSCDevList, which specifies
|
|
* which device key we're initializing.
|
|
* wszMountPoint - The mount point for a specified volume.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Status
|
|
*
|
|
* History:
|
|
*
|
|
* 04/07/2001 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HRESULT CreateMSCRegEntries(
|
|
HKEY hDevRegKey,
|
|
WCHAR *wszMountPoint)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (hDevRegKey && wszMountPoint) {
|
|
DWORD dwError = 0;
|
|
DWORD dwDisposition = 0;
|
|
HKEY hKey = NULL;
|
|
|
|
//
|
|
// Write the DeviceID. This is used to retsore event handlers for this device.
|
|
//
|
|
|
|
WCHAR wszInternalName[STI_MAX_INTERNAL_NAME_LENGTH];
|
|
|
|
//
|
|
// Make sure that there is enough space to enclose the mount point in {}.
|
|
//
|
|
if (lstrlenW(wszMountPoint) < (STI_MAX_INTERNAL_NAME_LENGTH - lstrlenW(L"{}"))) {
|
|
wsprintf(wszInternalName, L"{%ws}", wszMountPoint);
|
|
|
|
dwError = RegSetValueEx(hDevRegKey,
|
|
REGSTR_VAL_DEVICE_ID_W,
|
|
0,
|
|
REG_SZ,
|
|
(BYTE*)wszInternalName,
|
|
sizeof(wszInternalName));
|
|
}
|
|
|
|
//
|
|
// Create the DeviceData sub-key
|
|
//
|
|
dwError = RegCreateKeyExW(hDevRegKey,
|
|
REGSTR_VAL_DATA_W,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hKey,
|
|
&dwDisposition);
|
|
if (dwError == ERROR_SUCCESS) {
|
|
//
|
|
// We created the DeviceData sub-key. We need to add
|
|
// color profile entry
|
|
//
|
|
|
|
WCHAR wszSRGB[MAX_PATH];
|
|
DWORD dwSize = 0;
|
|
|
|
//
|
|
// We insert sRGB as the color profile. We don't hardcode the
|
|
// name, so call the API to get it... Notice
|
|
// that the entry is a double NULL terminated list, so we
|
|
// set the size parameter to exclude the last 2 characters,
|
|
// so we're guaranteed to have 2 NULLs at the end.
|
|
//
|
|
memset(wszSRGB, 0, sizeof(wszSRGB));
|
|
dwSize = sizeof(wszSRGB) - sizeof(L"\0\0");
|
|
if (GetStandardColorSpaceProfileW(NULL,
|
|
LCS_sRGB,
|
|
wszSRGB,
|
|
&dwSize))
|
|
{
|
|
//
|
|
// We must calculate the number of bytes in this string,
|
|
// remembering to include the size for two terminating NULLs.
|
|
//
|
|
dwSize = (lstrlenW(wszSRGB) * sizeof(wszSRGB[0])) + sizeof("\0\0");
|
|
|
|
//
|
|
// Let's write the color profile entry.
|
|
//
|
|
dwError = RegSetValueEx(hKey,
|
|
NULL,
|
|
0,
|
|
REG_BINARY,
|
|
(BYTE*)wszSRGB,
|
|
dwSize);
|
|
} else {
|
|
DBG_WRN(("CreateMSCRegEntries, GetStandardColorSpaceProfile failed!"));
|
|
}
|
|
|
|
//
|
|
// Nothing left to do with this key, so close it.
|
|
//
|
|
RegCloseKey(hKey);
|
|
hKey = NULL;
|
|
dwDisposition = 0;
|
|
}
|
|
|
|
//
|
|
// Create the Events sub-key
|
|
//
|
|
dwError = RegCreateKeyExW(hDevRegKey,
|
|
EVENTS,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hKey,
|
|
&dwDisposition);
|
|
if (dwError == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// We created the Events sub-key. Let's fill in some event info
|
|
//
|
|
WCHAR wszCLSID[39]; // {GUID} is 38 characters long, 39 including NULL
|
|
HKEY hKeyTemp = NULL;
|
|
|
|
if (StringFromGUID2(WIA_EVENT_DEVICE_CONNECTED, wszCLSID, sizeof(wszCLSID) / sizeof(wszCLSID[0]))) {
|
|
|
|
|
|
//
|
|
// Create the entry for WIA_EVENT_DEVICE_CONNECTED
|
|
//
|
|
dwError = RegCreateKeyExW(hKey,
|
|
WIA_EVENT_DEVICE_CONNECTED_STR,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hKeyTemp,
|
|
&dwDisposition);
|
|
if (dwError == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Fill in the values for the sub-key.
|
|
// The result is as follows:
|
|
// [Device connected]
|
|
// Default: "Device connected"
|
|
// GUID: "{a28bbade-x64b6-11d2-a231-00c0-4fa31809}"
|
|
// LaunchApplications: "*"
|
|
//
|
|
// Note that we don't care about error returns.
|
|
//
|
|
dwError = RegSetValueEx(hKeyTemp,
|
|
NULL,
|
|
0,
|
|
REG_SZ,
|
|
(BYTE*)WIA_EVENT_DEVICE_CONNECTED_STR,
|
|
sizeof(WIA_EVENT_DEVICE_CONNECTED_STR));
|
|
dwError = RegSetValueEx(hKeyTemp,
|
|
REGSTR_VAL_GUID_W,
|
|
0,
|
|
REG_SZ,
|
|
(BYTE*)wszCLSID,
|
|
sizeof(wszCLSID));
|
|
dwError = RegSetValueEx(hKeyTemp,
|
|
REGSTR_VAL_LAUNCH_APPS_W,
|
|
0,
|
|
REG_SZ,
|
|
(BYTE*)L"*",
|
|
sizeof(L"*"));
|
|
RegCloseKey(hKeyTemp);
|
|
hKeyTemp = NULL;
|
|
}
|
|
} else {
|
|
DBG_WRN(("::CreateMSCRegEntries, StringFromGUID2 for WIA_EVENT_DEVICE_CONNECTED failed!"));
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
hKey = NULL;
|
|
dwDisposition = 0;
|
|
}
|
|
} else {
|
|
DBG_WRN(("::CreateMSCRegEntries, Can't have NULL parameters!"));
|
|
}
|
|
|
|
return hr;
|
|
}
|