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.
2524 lines
58 KiB
2524 lines
58 KiB
|
|
#include "stdafx.h"
|
|
#include "resource.h"
|
|
|
|
#include <process.h>
|
|
|
|
#include "bar.h"
|
|
#include "pbrush.h"
|
|
#include "imaging.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Trace
|
|
//
|
|
|
|
#ifdef DBG
|
|
|
|
void AFX_CDECL Trace(PCTSTR pszFormat, ...)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, pszFormat);
|
|
|
|
CString strMessage;
|
|
strMessage.FormatV(pszFormat, argList);
|
|
|
|
OutputDebugString(strMessage);
|
|
|
|
va_end(argList);
|
|
}
|
|
|
|
#else //DBG
|
|
|
|
inline void AFX_CDECL Trace(PCTSTR pszFormat, ...)
|
|
{
|
|
}
|
|
|
|
#endif DBG
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
CImagingMgr::~CImagingMgr()
|
|
{
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
CWIAMgr::CWIAMgr()
|
|
{
|
|
HRESULT hr;
|
|
|
|
m_pEventCallback = new CEventCallback();
|
|
|
|
if (m_pEventCallback)
|
|
{
|
|
hr = m_pEventCallback->Register();
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
m_pEventCallback.Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
HRESULT
|
|
CWIAMgr::SelectSource(
|
|
HWND hWndParent,
|
|
LONG lFlags
|
|
)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
|
|
// Create a connection to the local WIA device manager
|
|
|
|
CComPtr<IWiaDevMgr> pWiaDevMgr;
|
|
|
|
hr = pWiaDevMgr.CoCreateInstance(CLSID_WiaDevMgr, NULL, CLSCTX_ALL|CLSCTX_NO_FAILURE_LOG);
|
|
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
// clear the current selection (if any)
|
|
|
|
m_bstrDeviceID.Empty();
|
|
|
|
// display the device selection dialog
|
|
|
|
hr = pWiaDevMgr->SelectDeviceDlgID(
|
|
hWndParent,
|
|
StiDeviceTypeDefault,
|
|
lFlags,
|
|
&m_bstrDeviceID
|
|
);
|
|
|
|
theApp.RestoreWaitCursor();
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
Trace(_T("SelectDeviceDlgID HRESULT=%08x\n"), hr);
|
|
return hr;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
HRESULT
|
|
CWIAMgr::Select(
|
|
LPCTSTR pDeviceId
|
|
)
|
|
{
|
|
m_bstrDeviceID = pDeviceId;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
HRESULT ReadPropertyLong(IWiaItem *pWiaItem, PROPID propid, LONG *lResult)
|
|
{
|
|
if (!lResult)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
HRESULT hr = S_FALSE;
|
|
|
|
CComQIPtr<IWiaPropertyStorage> pWiaPropertyStorage(pWiaItem);
|
|
|
|
if (pWiaPropertyStorage == 0)
|
|
{
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
PROPSPEC PropSpec;
|
|
|
|
PropSpec.ulKind = PRSPEC_PROPID;
|
|
PropSpec.propid = propid;
|
|
|
|
PROPVARIANT PropVariant;
|
|
|
|
PropVariantInit(&PropVariant);
|
|
|
|
hr = pWiaPropertyStorage->ReadMultiple(1, &PropSpec, &PropVariant);
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
Trace(_T("ReadMultiple HRESULT=%08x\n"), hr);
|
|
return hr;
|
|
}
|
|
|
|
switch (PropVariant.vt)
|
|
{
|
|
case VT_I1: *lResult = (LONG) PropVariant.cVal; break;
|
|
case VT_UI1: *lResult = (LONG) PropVariant.bVal; break;
|
|
case VT_I2: *lResult = (LONG) PropVariant.iVal; break;
|
|
case VT_UI2: *lResult = (LONG) PropVariant.uiVal; break;
|
|
case VT_I4: *lResult = (LONG) PropVariant.lVal; break;
|
|
case VT_UI4: *lResult = (LONG) PropVariant.ulVal; break;
|
|
case VT_INT: *lResult = (LONG) PropVariant.intVal; break;
|
|
case VT_UINT: *lResult = (LONG) PropVariant.uintVal; break;
|
|
case VT_R4: *lResult = (LONG) (PropVariant.fltVal + 0.5); break;
|
|
case VT_R8: *lResult = (LONG) (PropVariant.dblVal + 0.5); break;
|
|
default: hr = S_FALSE; break;
|
|
}
|
|
|
|
PropVariantClear(&PropVariant);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
HRESULT
|
|
CWIAMgr::Acquire(
|
|
HWND hWndParent,
|
|
HGLOBAL *phDib
|
|
)
|
|
{
|
|
ASSERT(phDib != 0);
|
|
|
|
HRESULT hr;
|
|
|
|
// Create a connection to the local WIA device manager
|
|
|
|
CComPtr<IWiaDevMgr> pWiaDevMgr;
|
|
|
|
hr = pWiaDevMgr.CoCreateInstance(CLSID_WiaDevMgr, NULL, CLSCTX_ALL|CLSCTX_NO_FAILURE_LOG);
|
|
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
// Create the device object.
|
|
// Select the device first if
|
|
// no device has been selected before or
|
|
// we fail to create the device with the selected ID
|
|
|
|
CComPtr<IWiaItem> pRootItem;
|
|
|
|
if (!m_bstrDeviceID ||
|
|
!SUCCEEDED(pWiaDevMgr->CreateDevice(m_bstrDeviceID, &pRootItem)))
|
|
{
|
|
// clear the current selection (if any)
|
|
|
|
m_bstrDeviceID.Empty();
|
|
|
|
// display the device selection dialog
|
|
|
|
hr = pWiaDevMgr->SelectDeviceDlg(
|
|
hWndParent,
|
|
StiDeviceTypeDefault,
|
|
0,
|
|
&m_bstrDeviceID,
|
|
&pRootItem
|
|
);
|
|
|
|
theApp.RestoreWaitCursor();
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
Trace(_T("SelectDeviceDlg HRESULT=%08x\n"), hr);
|
|
return hr;
|
|
}
|
|
|
|
#ifndef USE_SELECTSOURCE_MENUITEM
|
|
|
|
// forget the current selection
|
|
|
|
m_bstrDeviceID.Empty();
|
|
|
|
#endif //!USE_SELECTSOURCE_MENUITEM
|
|
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
Trace(_T("CreateDevice HRESULT=%08x\n"), hr);
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
// display the image selection dialog and let the user
|
|
// select the item to be transferred
|
|
|
|
CComPtrArray<IWiaItem> ppIWiaItem;
|
|
|
|
hr = pRootItem->DeviceDlg(
|
|
hWndParent,
|
|
WIA_DEVICE_DIALOG_SINGLE_IMAGE,
|
|
WIA_INTENT_NONE,
|
|
&ppIWiaItem.ItemCount(),
|
|
&ppIWiaItem
|
|
);
|
|
|
|
theApp.RestoreWaitCursor();
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
Trace(_T("DeviceDlg HRESULT=%08x\n"), hr);
|
|
return hr;
|
|
}
|
|
|
|
if (ppIWiaItem.ItemCount() == 0)
|
|
{
|
|
Trace(_T("DeviceDlg returned 0 items\n"));
|
|
return E_FAIL;
|
|
}
|
|
|
|
// set the image transfer properties; we want a DIB memory transfer
|
|
|
|
TYMED tymed = (TYMED) TYMED_CALLBACK;
|
|
GUID guidFormat = WiaImgFmt_MEMORYBMP;
|
|
|
|
PROPSPEC PropSpec[2] = { 0 };
|
|
PROPVARIANT PropVariant[2] = { 0 };
|
|
|
|
PropSpec[0].ulKind = PRSPEC_PROPID;
|
|
PropSpec[0].propid = WIA_IPA_TYMED;
|
|
PropVariant[0].vt = VT_I4;
|
|
PropVariant[0].lVal = tymed;
|
|
|
|
PropSpec[1].ulKind = PRSPEC_PROPID;
|
|
PropSpec[1].propid = WIA_IPA_FORMAT;
|
|
PropVariant[1].vt = VT_CLSID;
|
|
PropVariant[1].puuid = &guidFormat;
|
|
|
|
CComQIPtr<IWiaPropertyStorage> pWiaPropertyStorage(ppIWiaItem[0]);
|
|
|
|
if (pWiaPropertyStorage == 0)
|
|
{
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
hr = pWiaPropertyStorage->WriteMultiple(
|
|
1,
|
|
&(PropSpec[0]),
|
|
&(PropVariant[0]),
|
|
WIA_IPA_FIRST
|
|
);
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
Trace(_T("WriteMultiple HRESULT=%08x\n"), hr);
|
|
return hr;
|
|
}
|
|
|
|
hr = pWiaPropertyStorage->WriteMultiple(
|
|
1,
|
|
&(PropSpec[1]),
|
|
&(PropVariant[1]),
|
|
WIA_IPA_FIRST
|
|
);
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
Trace(_T("WriteMultiple HRESULT=%08x\n"), hr);
|
|
return hr;
|
|
}
|
|
|
|
// now, determine the transfer buffer size
|
|
|
|
// 64k transfer size and double buffering seem to work fine;
|
|
// a smaller buffer considerably slows down the memory transfer
|
|
// and a larger buffer doesn't give much speed increase.
|
|
// If the device minimum is larger than 64k though, use that size...
|
|
|
|
LONG lBufferSize;
|
|
|
|
hr = ReadPropertyLong(ppIWiaItem[0], WIA_IPA_MIN_BUFFER_SIZE, &lBufferSize);
|
|
|
|
if (hr != S_OK || lBufferSize < 64*1024)
|
|
{
|
|
lBufferSize = 64*1024;
|
|
}
|
|
|
|
// setup the progress dialog
|
|
|
|
CComPtr<IWiaProgressDialog> pProgress;
|
|
|
|
hr = CoCreateInstance(
|
|
CLSID_WiaDefaultUi,
|
|
0,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IWiaProgressDialog,
|
|
(void**) &pProgress
|
|
);
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
pProgress = new CProgressDialog;
|
|
}
|
|
|
|
LONG nDeviceType;
|
|
|
|
hr = ReadPropertyLong(pRootItem, WIA_DIP_DEV_TYPE, &nDeviceType);
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
nDeviceType = 0;
|
|
}
|
|
|
|
LONG lAnimFlag;
|
|
|
|
switch (GET_STIDEVICE_TYPE(nDeviceType))
|
|
{
|
|
case StiDeviceTypeScanner:
|
|
lAnimFlag = WIA_PROGRESSDLG_ANIM_SCANNER_ACQUIRE;
|
|
break;
|
|
|
|
case StiDeviceTypeDigitalCamera:
|
|
lAnimFlag = WIA_PROGRESSDLG_ANIM_CAMERA_ACQUIRE;
|
|
break;
|
|
|
|
case StiDeviceTypeStreamingVideo:
|
|
lAnimFlag = WIA_PROGRESSDLG_ANIM_VIDEO_ACQUIRE;
|
|
break;
|
|
|
|
default:
|
|
lAnimFlag = WIA_PROGRESSDLG_NO_ANIM;
|
|
break;
|
|
}
|
|
|
|
pProgress->Create(hWndParent, lAnimFlag);
|
|
|
|
CString strDownloading;
|
|
strDownloading.LoadString(IDS_DOWNLOAD_IMAGE);
|
|
|
|
USES_CONVERSION;
|
|
pProgress->SetTitle(T2CW(strDownloading));
|
|
|
|
pProgress->SetMessage(L"");
|
|
|
|
pProgress->Show();
|
|
|
|
// init the data callback interface
|
|
|
|
CDataCallback *pDataCallback = new CDataCallback(pProgress);
|
|
|
|
if (!pDataCallback)
|
|
{
|
|
theApp.SetMemoryEmergency(TRUE);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
CComQIPtr<IWiaDataCallback> pIWiaDataCallback(pDataCallback);
|
|
|
|
ASSERT(pIWiaDataCallback != 0);
|
|
|
|
// initiate the transfer
|
|
|
|
CComQIPtr<IWiaDataTransfer> pIWiaDataTransfer(ppIWiaItem[0]);
|
|
|
|
if (pIWiaDataTransfer == 0)
|
|
{
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
WIA_DATA_TRANSFER_INFO WiaDataTransferInfo = { 0 };
|
|
|
|
WiaDataTransferInfo.ulSize = sizeof(WIA_DATA_TRANSFER_INFO);
|
|
WiaDataTransferInfo.ulBufferSize = 2 * lBufferSize;
|
|
WiaDataTransferInfo.bDoubleBuffer = TRUE;
|
|
|
|
// This *easy* solution will cause the mspaint UI to freeze during
|
|
// image transfer; this is possibly too long time to remain frozen.
|
|
// So we will create a worker thread to do the data transfer.
|
|
//
|
|
//hr = pIWiaDataTransfer->idtGetBandedData(
|
|
// &WiaDataTransferInfo,
|
|
// pIWiaDataCallback
|
|
//);
|
|
|
|
EnableWindow(hWndParent, FALSE);
|
|
|
|
hr = GetBandedData(CGetBandedDataThreadData(
|
|
pIWiaDataTransfer,
|
|
&WiaDataTransferInfo,
|
|
pIWiaDataCallback
|
|
));
|
|
|
|
EnableWindow(hWndParent, TRUE);
|
|
|
|
// check if the user has pressed cancel
|
|
|
|
if (pProgress)
|
|
{
|
|
BOOL bCancelled;
|
|
|
|
if (pProgress->Cancelled(&bCancelled) == S_OK && bCancelled)
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
pProgress->Destroy();
|
|
}
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
Trace(_T("idtGetBandedData HRESULT=%08x\n"), hr);
|
|
return hr;
|
|
}
|
|
|
|
// return the results
|
|
|
|
pDataCallback->PrintTimes();
|
|
|
|
*phDib = pDataCallback->GetBuffer();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
CWIAMgr::CGetBandedDataThreadData::CGetBandedDataThreadData(
|
|
IWiaDataTransfer *pIWiaDataTransfer,
|
|
WIA_DATA_TRANSFER_INFO *pWiaDataTransferInfo,
|
|
IWiaDataCallback *pIWiaDataCallback
|
|
) :
|
|
m_pIWiaDataTransfer(pIWiaDataTransfer),
|
|
m_pWiaDataTransferInfo(pWiaDataTransferInfo),
|
|
m_pIWiaDataCallback(pIWiaDataCallback)
|
|
{
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
HRESULT CWIAMgr::CGetBandedDataThreadData::Marshal()
|
|
{
|
|
HRESULT hr;
|
|
|
|
// marshal the IWiaDataTransfer interface
|
|
|
|
ASSERT(m_pIWiaDataTransfer != 0);
|
|
|
|
hr = CoMarshalInterThreadInterfaceInStream(
|
|
IID_IWiaDataTransfer,
|
|
m_pIWiaDataTransfer,
|
|
&m_pIWiaDataTransferStream
|
|
);
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
Trace(_T("CoMarshalInterThreadInterfaceInStream HRESULT=%08x\n"), hr);
|
|
return hr;
|
|
}
|
|
|
|
m_pIWiaDataTransfer.Release();
|
|
|
|
// marshal the IWiaDataCallback interface
|
|
|
|
ASSERT(m_pIWiaDataCallback != 0);
|
|
|
|
hr = CoMarshalInterThreadInterfaceInStream(
|
|
IID_IWiaDataCallback,
|
|
m_pIWiaDataCallback,
|
|
&m_pIWiaDataCallbackStream
|
|
);
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
Trace(_T("CoMarshalInterThreadInterfaceInStream HRESULT=%08x\n"), hr);
|
|
return hr;
|
|
}
|
|
|
|
m_pIWiaDataCallback.Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
HRESULT CWIAMgr::CGetBandedDataThreadData::Unmarshal()
|
|
{
|
|
HRESULT hr;
|
|
|
|
// unmarshal the IWiaDataTransfer interface
|
|
|
|
ASSERT(m_pIWiaDataTransferStream != 0);
|
|
|
|
hr = CoGetInterfaceAndReleaseStream(
|
|
m_pIWiaDataTransferStream,
|
|
IID_IWiaDataTransfer,
|
|
(void **) &m_pIWiaDataTransfer
|
|
);
|
|
|
|
// CoGetInterfaceAndReleaseStream should already have
|
|
// released the stream pointer, so set it to zero so that
|
|
// ~CGetBandedDataThreadData will not try to release it again
|
|
|
|
m_pIWiaDataTransferStream.Detach();
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
Trace(_T("CoGetInterfaceAndReleaseStream HRESULT=%08x\n"), hr);
|
|
return hr;
|
|
}
|
|
|
|
// unmarshal the IWiaDataCallback interface
|
|
|
|
ASSERT(m_pIWiaDataCallbackStream != 0);
|
|
|
|
hr = CoGetInterfaceAndReleaseStream(
|
|
m_pIWiaDataCallbackStream,
|
|
IID_IWiaDataCallback,
|
|
(void **) &m_pIWiaDataCallback
|
|
);
|
|
|
|
m_pIWiaDataCallbackStream.Detach();
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
Trace(_T("CoGetInterfaceAndReleaseStream HRESULT=%08x\n"), hr);
|
|
return hr;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
HRESULT CWIAMgr::GetBandedData(CGetBandedDataThreadData &ThreadData)
|
|
{
|
|
// marshal the interface pointers before passing them to another thread
|
|
|
|
HRESULT hr = ThreadData.Marshal();
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
// fire up the new thread
|
|
|
|
unsigned nThreadId;
|
|
|
|
HANDLE hThread = (HANDLE) _beginthreadex(
|
|
0,
|
|
0,
|
|
GetBandedDataThread,
|
|
&ThreadData,
|
|
0,
|
|
&nThreadId
|
|
);
|
|
|
|
if (hThread == 0)
|
|
{
|
|
Trace(_T("CreateThread LastError=%08x\n"), GetLastError());
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
// enter a msg loop while waiting for the thread to complete;
|
|
// this will keep the mspaint UI alive
|
|
|
|
while (MsgWaitForMultipleObjects(1, &hThread, FALSE, INFINITE, QS_ALLINPUT) == WAIT_OBJECT_0+1)
|
|
{
|
|
MSG msg;
|
|
|
|
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
theApp.RestoreWaitCursor();
|
|
}
|
|
|
|
// if we reach here, the thread must have ended; get the result
|
|
|
|
DWORD dwExitCode = S_FALSE;
|
|
|
|
GetExitCodeThread(hThread, &dwExitCode);
|
|
|
|
CloseHandle(hThread);
|
|
|
|
ASSERT(sizeof(DWORD) >= sizeof(HRESULT));
|
|
return (HRESULT) dwExitCode;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
unsigned WINAPI CWIAMgr::GetBandedDataThread(PVOID pVoid)
|
|
{
|
|
// Init COM for this thread
|
|
|
|
HRESULT hr = CoInitialize(0);
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
Trace(_T("CoInitialize HRESULT=%08x\n"), hr);
|
|
return (unsigned) hr;
|
|
}
|
|
|
|
CGetBandedDataThreadData *pThreadData = (CGetBandedDataThreadData *) pVoid;
|
|
|
|
ASSERT(pThreadData != 0);
|
|
|
|
if (pThreadData != 0)
|
|
{
|
|
// unmarshal the interface pointers before calling idtGetBandedData
|
|
|
|
hr = pThreadData->Unmarshal();
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
hr = pThreadData->m_pIWiaDataTransfer->idtGetBandedData(
|
|
pThreadData->m_pWiaDataTransferInfo,
|
|
pThreadData->m_pIWiaDataCallback
|
|
);
|
|
}
|
|
}
|
|
|
|
CoUninitialize();
|
|
|
|
ASSERT(sizeof(unsigned) >= sizeof(HRESULT));
|
|
return (unsigned) hr;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
int CWIAMgr::NumDevices(HWND /*hWndParent*/)
|
|
{
|
|
return m_pEventCallback ? m_pEventCallback->GetNumDevices() : 0;
|
|
}
|
|
|
|
#ifdef USE_TWAIN
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
CTwainMgr::CTwainMgr()
|
|
{
|
|
m_TwainState = State_1_Pre_Session;
|
|
|
|
// fill in the m_AppId struct with defaults
|
|
|
|
m_AppId.Id = 0;
|
|
m_AppId.Version.MajorNum = 1;
|
|
m_AppId.Version.MinorNum = 0;
|
|
m_AppId.Version.Language = TWLG_USA;
|
|
m_AppId.Version.Country = TWCY_USA;
|
|
strcpy(m_AppId.Version.Info, "FileDescription");
|
|
m_AppId.ProtocolMajor = TWON_PROTOCOLMAJOR;
|
|
m_AppId.ProtocolMinor = TWON_PROTOCOLMINOR;
|
|
m_AppId.SupportedGroups = DG_IMAGE | DG_CONTROL;
|
|
strcpy(m_AppId.Manufacturer, "CompanyName");
|
|
strcpy(m_AppId.ProductFamily, "ProductVersion");
|
|
strcpy(m_AppId.ProductName, "ProductName");
|
|
|
|
// reset m_SrcId
|
|
|
|
m_SrcId.Id = 0;
|
|
m_SrcId.ProductName[0] = '\0';
|
|
|
|
// Load TWAIN DLL
|
|
|
|
m_hTwainDll = LoadLibrary(_T("TWAIN_32.DLL"));
|
|
|
|
if (m_hTwainDll)
|
|
{
|
|
// Get the entry point
|
|
|
|
m_DSM_Entry = (DSMENTRYPROC) GetProcAddress(m_hTwainDll, "DSM_Entry");
|
|
|
|
if (m_DSM_Entry)
|
|
{
|
|
m_TwainState = State_2_Source_Manager_Loaded;
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
CTwainMgr::~CTwainMgr()
|
|
{
|
|
// Free the library if loaded
|
|
|
|
if (m_TwainState >= State_1_Pre_Session)
|
|
{
|
|
FreeLibrary(m_hTwainDll);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
HRESULT
|
|
CTwainMgr::SelectSource(
|
|
HWND hWndParent,
|
|
LONG /*lFlags*/
|
|
)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
TW_UINT16 rc = TWRC_FAILURE;
|
|
|
|
if (m_TwainState >= State_2_Source_Manager_Loaded)
|
|
{
|
|
__try
|
|
{
|
|
if (m_TwainState == State_2_Source_Manager_Loaded)
|
|
{
|
|
// Open the data source manager
|
|
|
|
rc = m_DSM_Entry(
|
|
&m_AppId,
|
|
0,
|
|
DG_CONTROL,
|
|
DAT_PARENT,
|
|
MSG_OPENDSM,
|
|
(TW_MEMREF) &hWndParent
|
|
);
|
|
|
|
if (rc != TWRC_SUCCESS)
|
|
{
|
|
__leave;
|
|
}
|
|
|
|
m_TwainState = State_3_Source_Manager_Open;
|
|
}
|
|
|
|
// pop up the selection dialog
|
|
|
|
rc = m_DSM_Entry(
|
|
&m_AppId,
|
|
0,
|
|
DG_CONTROL,
|
|
DAT_IDENTITY,
|
|
MSG_USERSELECT,
|
|
(TW_MEMREF) &m_SrcId
|
|
);
|
|
|
|
ASSERT(rc == TWRC_SUCCESS || rc == TWRC_CANCEL);
|
|
|
|
if (rc == TWRC_SUCCESS)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
__finally
|
|
{
|
|
if (m_TwainState == State_3_Source_Manager_Open)
|
|
{
|
|
// Close the data source manager
|
|
|
|
rc = m_DSM_Entry(
|
|
&m_AppId,
|
|
0,
|
|
DG_CONTROL,
|
|
DAT_PARENT,
|
|
MSG_CLOSEDSM,
|
|
(TW_MEMREF) &hWndParent
|
|
);
|
|
|
|
ASSERT(rc == TWRC_SUCCESS);
|
|
|
|
m_TwainState = State_2_Source_Manager_Loaded;
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
HRESULT
|
|
CTwainMgr::Select(
|
|
LPCTSTR pDeviceId
|
|
)
|
|
{
|
|
#ifdef UNICODE
|
|
WideCharToMultiByte(CP_ACP, 0, pDeviceId, -1,
|
|
m_SrcId.ProductName, sizeof(m_SrcId.ProductName), 0, 0);
|
|
#else //UNICODE
|
|
lstrcpyn(m_SrcId.ProductName, pDeviceId, sizeof(m_SrcId.ProductName));
|
|
#endif //UNICODE
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
HRESULT
|
|
CTwainMgr::Acquire(
|
|
HWND hWndParent,
|
|
HGLOBAL *phDib
|
|
)
|
|
{
|
|
ASSERT(phDib);
|
|
|
|
HRESULT hr = S_FALSE;
|
|
TW_UINT16 rc = TWRC_FAILURE;
|
|
|
|
if (m_TwainState >= State_2_Source_Manager_Loaded)
|
|
{
|
|
__try
|
|
{
|
|
if (m_TwainState == State_2_Source_Manager_Loaded)
|
|
{
|
|
// Open the data source manager
|
|
|
|
rc = m_DSM_Entry(
|
|
&m_AppId,
|
|
0,
|
|
DG_CONTROL,
|
|
DAT_PARENT,
|
|
MSG_OPENDSM,
|
|
(TW_MEMREF) &hWndParent
|
|
);
|
|
|
|
if (rc != TWRC_SUCCESS)
|
|
{
|
|
__leave;
|
|
}
|
|
|
|
m_TwainState = State_3_Source_Manager_Open;
|
|
}
|
|
|
|
#ifdef USE_SELECTSOURCE_MENUITEM
|
|
|
|
if (m_SrcId.ProductName[0] == '\0')
|
|
{
|
|
// if no data source is selected yet, get the default
|
|
|
|
rc = m_DSM_Entry(
|
|
&m_AppId,
|
|
0,
|
|
DG_CONTROL,
|
|
DAT_IDENTITY,
|
|
MSG_GETDEFAULT,
|
|
(TW_MEMREF) &m_SrcId
|
|
);
|
|
|
|
if (rc != TWRC_SUCCESS)
|
|
{
|
|
__leave;
|
|
}
|
|
}
|
|
|
|
#else //USE_SELECTSOURCE_MENUITEM
|
|
|
|
rc = m_DSM_Entry(
|
|
&m_AppId,
|
|
0,
|
|
DG_CONTROL,
|
|
DAT_IDENTITY,
|
|
MSG_USERSELECT,
|
|
(TW_MEMREF) &m_SrcId
|
|
);
|
|
|
|
ASSERT(rc == TWRC_SUCCESS || rc == TWRC_CANCEL);
|
|
|
|
if (rc != TWRC_SUCCESS)
|
|
{
|
|
__leave;
|
|
}
|
|
|
|
#endif //USE_SELECTSOURCE_MENUITEM
|
|
|
|
if (m_TwainState == State_3_Source_Manager_Open)
|
|
{
|
|
// open the data source
|
|
|
|
rc = m_DSM_Entry(
|
|
&m_AppId,
|
|
0,
|
|
DG_CONTROL,
|
|
DAT_IDENTITY,
|
|
MSG_OPENDS,
|
|
(TW_MEMREF) &m_SrcId
|
|
);
|
|
|
|
if (rc != TWRC_SUCCESS)
|
|
{
|
|
__leave;
|
|
}
|
|
|
|
m_TwainState = State_4_Source_Open;
|
|
}
|
|
|
|
// set the desired transfer options;
|
|
// we want to transfer a single 8-bit RGB image
|
|
|
|
SetCapability(CAP_XFERCOUNT, TWTY_INT16, 1);
|
|
SetCapability(ICAP_PIXELTYPE, TWTY_UINT32, TWPT_RGB);
|
|
SetCapability(ICAP_BITDEPTH, TWTY_UINT32, 8);
|
|
|
|
if (m_TwainState == State_4_Source_Open)
|
|
{
|
|
// enable the data source
|
|
|
|
TW_USERINTERFACE twUI;
|
|
|
|
twUI.ShowUI = TRUE;
|
|
twUI.hParent = hWndParent;
|
|
|
|
rc = m_DSM_Entry(
|
|
&m_AppId,
|
|
&m_SrcId,
|
|
DG_CONTROL,
|
|
DAT_USERINTERFACE,
|
|
MSG_ENABLEDS,
|
|
(TW_MEMREF) &twUI
|
|
);
|
|
|
|
theApp.RestoreWaitCursor();
|
|
|
|
if (rc != TWRC_SUCCESS)
|
|
{
|
|
__leave;
|
|
}
|
|
|
|
m_TwainState = State_5_Source_Enabled;
|
|
}
|
|
|
|
if (m_TwainState == State_5_Source_Enabled)
|
|
{
|
|
// Disable the parent window
|
|
|
|
EnableWindow(hWndParent, FALSE);
|
|
|
|
// Enter the message loop to transfer the image
|
|
|
|
MSG msg;
|
|
BOOL bDone = FALSE;
|
|
|
|
while (!bDone && GetMessage(&msg, 0, 0, 0))
|
|
{
|
|
// process the event through TWAIN
|
|
|
|
TW_EVENT twEvent;
|
|
|
|
twEvent.pEvent = &msg;
|
|
twEvent.TWMessage = MSG_NULL;
|
|
|
|
rc = m_DSM_Entry(
|
|
&m_AppId,
|
|
&m_SrcId,
|
|
DG_CONTROL,
|
|
DAT_EVENT,
|
|
MSG_PROCESSEVENT,
|
|
(TW_MEMREF) &twEvent
|
|
);
|
|
|
|
if (twEvent.TWMessage == MSG_CLOSEDSREQ)
|
|
{
|
|
bDone = TRUE;
|
|
hr = S_FALSE;
|
|
}
|
|
else if (twEvent.TWMessage == MSG_XFERREADY)
|
|
{
|
|
|
|
m_TwainState = State_6_Transfer_Ready;
|
|
|
|
TW_PENDINGXFERS twPendingXfers;
|
|
|
|
do
|
|
{
|
|
m_TwainState = State_7_Transferring;
|
|
|
|
rc = m_DSM_Entry(
|
|
&m_AppId,
|
|
&m_SrcId,
|
|
DG_IMAGE,
|
|
DAT_IMAGENATIVEXFER,
|
|
MSG_GET,
|
|
(TW_MEMREF) phDib
|
|
);
|
|
|
|
if (rc != TWRC_XFERDONE)
|
|
{
|
|
if (*phDib)
|
|
{
|
|
GlobalFree(*phDib);
|
|
}
|
|
|
|
__leave;
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
// End the transfer
|
|
|
|
rc = m_DSM_Entry(
|
|
&m_AppId,
|
|
&m_SrcId,
|
|
DG_CONTROL,
|
|
DAT_PENDINGXFERS,
|
|
MSG_ENDXFER,
|
|
(TW_MEMREF) &twPendingXfers
|
|
);
|
|
|
|
if (rc != TWRC_SUCCESS)
|
|
{
|
|
__leave;
|
|
}
|
|
|
|
m_TwainState = State_6_Transfer_Ready;
|
|
|
|
} while (twPendingXfers.Count != 0);
|
|
|
|
m_TwainState = State_5_Source_Enabled;
|
|
|
|
//exit after a single image transfer
|
|
|
|
bDone = TRUE;
|
|
}
|
|
|
|
if (rc == TWRC_NOTDSEVENT)
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
__finally
|
|
{
|
|
// enable the parent window upon exiting the message loop
|
|
|
|
EnableWindow(hWndParent, TRUE);
|
|
|
|
ASSERT(m_TwainState <= State_6_Transfer_Ready);
|
|
|
|
if (m_TwainState == State_6_Transfer_Ready)
|
|
{
|
|
TW_PENDINGXFERS twPendingXfers;
|
|
|
|
rc = m_DSM_Entry(
|
|
&m_AppId,
|
|
&m_SrcId,
|
|
DG_CONTROL,
|
|
DAT_PENDINGXFERS,
|
|
MSG_RESET,
|
|
(TW_MEMREF) &twPendingXfers
|
|
);
|
|
|
|
ASSERT(rc == TWRC_SUCCESS);
|
|
|
|
m_TwainState = State_5_Source_Enabled;
|
|
}
|
|
|
|
if (m_TwainState == State_5_Source_Enabled)
|
|
{
|
|
TW_USERINTERFACE twUI;
|
|
|
|
rc = m_DSM_Entry(
|
|
&m_AppId,
|
|
&m_SrcId,
|
|
DG_CONTROL,
|
|
DAT_USERINTERFACE,
|
|
MSG_DISABLEDS,
|
|
(TW_MEMREF) &twUI
|
|
);
|
|
|
|
ASSERT(rc == TWRC_SUCCESS);
|
|
|
|
m_TwainState = State_4_Source_Open;
|
|
}
|
|
|
|
if (m_TwainState == State_4_Source_Open)
|
|
{
|
|
rc = m_DSM_Entry(
|
|
&m_AppId,
|
|
0,
|
|
DG_CONTROL,
|
|
DAT_IDENTITY,
|
|
MSG_CLOSEDS,
|
|
(TW_MEMREF) &m_SrcId
|
|
);
|
|
|
|
ASSERT(rc == TWRC_SUCCESS);
|
|
|
|
m_TwainState = State_3_Source_Manager_Open;
|
|
}
|
|
|
|
if (m_TwainState == State_3_Source_Manager_Open)
|
|
{
|
|
rc = m_DSM_Entry(
|
|
&m_AppId,
|
|
0,
|
|
DG_CONTROL,
|
|
DAT_PARENT,
|
|
MSG_CLOSEDSM,
|
|
(TW_MEMREF) &hWndParent
|
|
);
|
|
|
|
ASSERT(rc == TWRC_SUCCESS);
|
|
|
|
m_TwainState = State_2_Source_Manager_Loaded;
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
int CTwainMgr::NumDevices(HWND hWndParent)
|
|
{
|
|
return 1; // this is too slow, better lie...
|
|
|
|
int nNumDevices = 0;
|
|
|
|
TW_UINT16 rc = TWRC_FAILURE;
|
|
|
|
// m_TwainState >= State_2 guarantees m_DSM_Entry != 0
|
|
|
|
if (m_TwainState >= State_2_Source_Manager_Loaded)
|
|
{
|
|
__try
|
|
{
|
|
if (m_TwainState == State_2_Source_Manager_Loaded)
|
|
{
|
|
// Open the data source manager
|
|
|
|
rc = m_DSM_Entry(
|
|
&m_AppId,
|
|
0,
|
|
DG_CONTROL,
|
|
DAT_PARENT,
|
|
MSG_OPENDSM,
|
|
(TW_MEMREF) &hWndParent
|
|
);
|
|
|
|
if (rc != TWRC_SUCCESS)
|
|
{
|
|
__leave;
|
|
}
|
|
|
|
m_TwainState = State_3_Source_Manager_Open;
|
|
}
|
|
|
|
// Enumerate the devices one by one
|
|
|
|
TW_IDENTITY SrcId;
|
|
|
|
rc = m_DSM_Entry(
|
|
&m_AppId,
|
|
0,
|
|
DG_CONTROL,
|
|
DAT_IDENTITY,
|
|
MSG_GETFIRST,
|
|
(TW_MEMREF) &SrcId
|
|
);
|
|
|
|
while (rc == TWRC_SUCCESS)
|
|
{
|
|
++nNumDevices;
|
|
|
|
rc = m_DSM_Entry(
|
|
&m_AppId,
|
|
0,
|
|
DG_CONTROL,
|
|
DAT_IDENTITY,
|
|
MSG_GETNEXT,
|
|
(TW_MEMREF) &SrcId
|
|
);
|
|
}
|
|
}
|
|
__finally
|
|
{
|
|
if (m_TwainState == State_3_Source_Manager_Open)
|
|
{
|
|
// Close the data source manager
|
|
|
|
rc = m_DSM_Entry(
|
|
&m_AppId,
|
|
0,
|
|
DG_CONTROL,
|
|
DAT_PARENT,
|
|
MSG_CLOSEDSM,
|
|
(TW_MEMREF) &hWndParent
|
|
);
|
|
|
|
ASSERT(rc == TWRC_SUCCESS);
|
|
|
|
m_TwainState = State_2_Source_Manager_Loaded;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nNumDevices;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
TW_UINT16
|
|
CTwainMgr::SetCapability(
|
|
TW_UINT16 Cap,
|
|
TW_UINT16 ItemType,
|
|
TW_UINT32 Item
|
|
)
|
|
{
|
|
TW_UINT16 rc = TWRC_FAILURE;
|
|
|
|
TW_CAPABILITY twCapability;
|
|
|
|
twCapability.Cap = Cap;
|
|
twCapability.ConType = TWON_ONEVALUE;
|
|
twCapability.hContainer = 0;
|
|
|
|
twCapability.hContainer = GlobalAlloc(
|
|
GMEM_MOVEABLE | GMEM_ZEROINIT,
|
|
sizeof(TW_ONEVALUE)
|
|
);
|
|
|
|
if (twCapability.hContainer)
|
|
{
|
|
pTW_ONEVALUE pVal = (pTW_ONEVALUE) GlobalLock(twCapability.hContainer);
|
|
|
|
if (pVal)
|
|
{
|
|
pVal->ItemType = ItemType;
|
|
pVal->Item = Item;
|
|
|
|
GlobalUnlock(twCapability.hContainer);
|
|
|
|
rc = m_DSM_Entry(
|
|
&m_AppId,
|
|
&m_SrcId,
|
|
DG_CONTROL,
|
|
DAT_CAPABILITY,
|
|
MSG_SET,
|
|
(TW_MEMREF) &twCapability
|
|
);
|
|
}
|
|
|
|
GlobalFree(twCapability.hContainer);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
TW_UINT16
|
|
CTwainMgr::GetCapability(
|
|
TW_UINT16 Cap,
|
|
pTW_UINT16 pItemType,
|
|
pTW_UINT32 pItem
|
|
)
|
|
{
|
|
TW_CAPABILITY twCapability;
|
|
|
|
twCapability.Cap = Cap;
|
|
twCapability.ConType = TWON_DONTCARE16;
|
|
twCapability.hContainer = 0;
|
|
|
|
TW_UINT16 rc = m_DSM_Entry(
|
|
&m_AppId,
|
|
&m_SrcId,
|
|
DG_CONTROL,
|
|
DAT_CAPABILITY,
|
|
MSG_GET,
|
|
(TW_MEMREF) &twCapability
|
|
);
|
|
|
|
if (twCapability.hContainer)
|
|
{
|
|
pTW_ONEVALUE pVal = (pTW_ONEVALUE) GlobalLock(twCapability.hContainer);
|
|
|
|
if (pVal)
|
|
{
|
|
if (pItemType)
|
|
{
|
|
*pItemType = pVal->ItemType;
|
|
}
|
|
|
|
if (pItem)
|
|
{
|
|
*pItem = pVal->Item;
|
|
}
|
|
}
|
|
|
|
GlobalFree(twCapability.hContainer);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
#endif //USE_TWAIN
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
HRESULT
|
|
WiaGetNumDevices(
|
|
IWiaDevMgr *_pWiaDevMgr,
|
|
ULONG *pulNumDevices
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
// Validate and initialize output parameters
|
|
|
|
if (pulNumDevices == 0)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
*pulNumDevices = 0;
|
|
|
|
// Create a connection to the local WIA device manager
|
|
|
|
CComPtr<IWiaDevMgr> pWiaDevMgr = _pWiaDevMgr;
|
|
|
|
if (pWiaDevMgr == 0)
|
|
{
|
|
hr = pWiaDevMgr.CoCreateInstance(CLSID_WiaDevMgr, NULL, CLSCTX_ALL|CLSCTX_NO_FAILURE_LOG);
|
|
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
// Get a list of all the WIA devices on the system
|
|
|
|
CComPtr<IEnumWIA_DEV_INFO> pIEnumWIA_DEV_INFO;
|
|
|
|
hr = pWiaDevMgr->EnumDeviceInfo(
|
|
0,
|
|
&pIEnumWIA_DEV_INFO
|
|
);
|
|
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
// Get the number of WIA devices
|
|
|
|
ULONG celt;
|
|
|
|
hr = pIEnumWIA_DEV_INFO->GetCount(&celt);
|
|
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
*pulNumDevices = celt;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
CEventCallback::CEventCallback()
|
|
{
|
|
m_cRef = 0;
|
|
m_nNumDevices = 0;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
HRESULT CEventCallback::Register()
|
|
{
|
|
HRESULT hr;
|
|
|
|
// Create a connection to the local WIA device manager
|
|
|
|
CComPtr<IWiaDevMgr> pWiaDevMgr;
|
|
|
|
hr = pWiaDevMgr.CoCreateInstance(CLSID_WiaDevMgr, NULL, CLSCTX_ALL|CLSCTX_NO_FAILURE_LOG);
|
|
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
// Get the count of all the WIA devices on the system
|
|
|
|
hr = WiaGetNumDevices(pWiaDevMgr, &m_nNumDevices);
|
|
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
// Register the callback interface
|
|
|
|
hr = pWiaDevMgr->RegisterEventCallbackInterface(
|
|
0,
|
|
0,
|
|
&WIA_EVENT_DEVICE_CONNECTED,
|
|
this,
|
|
&m_pConnectEventObject
|
|
);
|
|
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
hr = pWiaDevMgr->RegisterEventCallbackInterface(
|
|
0,
|
|
0,
|
|
&WIA_EVENT_DEVICE_DISCONNECTED,
|
|
this,
|
|
&m_pDisconnectEventObject
|
|
);
|
|
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
ULONG CEventCallback::GetNumDevices() const
|
|
{
|
|
return m_nNumDevices;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
STDMETHODIMP CEventCallback::QueryInterface(REFIID iid, LPVOID *ppvObj)
|
|
{
|
|
if (ppvObj == 0)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (iid == IID_IUnknown)
|
|
{
|
|
AddRef();
|
|
*ppvObj = (IUnknown *) this;
|
|
return S_OK;
|
|
}
|
|
|
|
if (iid == IID_IWiaEventCallback)
|
|
{
|
|
AddRef();
|
|
*ppvObj = (IWiaEventCallback *) this;
|
|
return S_OK;
|
|
}
|
|
|
|
*ppvObj = 0;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
STDMETHODIMP_(ULONG) CEventCallback::AddRef()
|
|
{
|
|
return InterlockedIncrement(&m_cRef);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
STDMETHODIMP_(ULONG) CEventCallback::Release()
|
|
{
|
|
ASSERT( 0 != m_cRef );
|
|
ULONG cRef = InterlockedDecrement(&m_cRef);
|
|
if (cRef == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
return cRef;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
STDMETHODIMP CEventCallback::ImageEventCallback(
|
|
LPCGUID pEventGuid,
|
|
BSTR bstrEventDescription,
|
|
BSTR bstrDeviceID,
|
|
BSTR bstrDeviceDescription,
|
|
DWORD dwDeviceType,
|
|
BSTR bstrFullItemName,
|
|
ULONG *pulEventType,
|
|
ULONG ulReserved
|
|
)
|
|
{
|
|
return WiaGetNumDevices(0, &m_nNumDevices);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
CDataCallback::CDataCallback(IWiaProgressDialog *pProgress)
|
|
{
|
|
m_cRef = 0;
|
|
m_hBuffer = 0;
|
|
m_lBufferSize = 0;
|
|
m_lDataSize = 0;
|
|
m_pProgress = pProgress;
|
|
|
|
#ifdef DBG
|
|
m_hDumpFile = CreateFile(_T("wiadump.bin"), GENERIC_WRITE,
|
|
FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
|
m_TimeDeviceBegin.QuadPart = 0;
|
|
m_TimeDeviceEnd.QuadPart = 0;
|
|
m_TimeProcessBegin.QuadPart = 0;
|
|
m_TimeProcessEnd.QuadPart = 0;
|
|
m_TimeClientBegin.QuadPart = 0;
|
|
m_TimeClientEnd.QuadPart = 0;
|
|
#endif //DBG
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
CDataCallback::~CDataCallback()
|
|
{
|
|
if (m_hBuffer)
|
|
{
|
|
GlobalFree(m_hBuffer);
|
|
}
|
|
|
|
#ifdef DBG
|
|
CloseHandle(m_hDumpFile);
|
|
#endif //DBG
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
HGLOBAL CDataCallback::GetBuffer()
|
|
{
|
|
HGLOBAL hBuffer = m_hBuffer;
|
|
|
|
m_hBuffer = 0;
|
|
m_lBufferSize = 0;
|
|
m_lDataSize = 0;
|
|
|
|
return hBuffer;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
STDMETHODIMP CDataCallback::QueryInterface(REFIID iid, LPVOID *ppvObj)
|
|
{
|
|
if (ppvObj == 0)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (iid == IID_IUnknown)
|
|
{
|
|
AddRef();
|
|
*ppvObj = (IUnknown*) this;
|
|
return S_OK;
|
|
}
|
|
|
|
if (iid == IID_IWiaDataCallback)
|
|
{
|
|
AddRef();
|
|
*ppvObj = (IWiaDataCallback *) this;
|
|
return S_OK;
|
|
}
|
|
|
|
*ppvObj = 0;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
STDMETHODIMP_(ULONG) CDataCallback::AddRef()
|
|
{
|
|
return InterlockedIncrement(&m_cRef);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
STDMETHODIMP_(ULONG) CDataCallback::Release()
|
|
{
|
|
ASSERT( 0 != m_cRef );
|
|
ULONG cRef = InterlockedDecrement(&m_cRef);
|
|
|
|
if (cRef == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
return cRef;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
STDMETHODIMP CDataCallback::BandedDataCallback(
|
|
LONG lReason,
|
|
LONG lStatus,
|
|
LONG lPercentComplete,
|
|
LONG lOffset,
|
|
LONG lLength,
|
|
LONG lReserved,
|
|
LONG lResLength,
|
|
PBYTE pbBuffer
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
Trace(
|
|
_T("DataCallback: Reason=%d Stat=%d %%=%d Offset=%d Length=%d Buf=%p\n"),
|
|
lReason, lStatus, lPercentComplete, lOffset, lLength, pbBuffer
|
|
);
|
|
|
|
// check if the user has pressed cancel
|
|
|
|
BOOL bCancelled;
|
|
|
|
if (m_pProgress && m_pProgress->Cancelled(&bCancelled) == S_OK && bCancelled)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
switch (lReason)
|
|
{
|
|
case IT_MSG_DATA_HEADER:
|
|
{
|
|
// allocate memory for the image if the size is given in the header
|
|
|
|
PWIA_DATA_CALLBACK_HEADER pHeader = (PWIA_DATA_CALLBACK_HEADER) pbBuffer;
|
|
|
|
if (pHeader && pHeader->lBufferSize)
|
|
{
|
|
hr = ReAllocBuffer(pHeader->lBufferSize);
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case IT_MSG_DATA:
|
|
{
|
|
QueryStartTimes(lStatus, lPercentComplete);
|
|
|
|
UpdateStatus(lStatus, lPercentComplete);
|
|
|
|
// if the buffer is not allocated yet and this is the first block,
|
|
// try to allocate a buffer according to the bitmap header info
|
|
|
|
if (m_lBufferSize == 0 && lOffset == 0)
|
|
{
|
|
LONG lBufferSize = FindDibSize(pbBuffer);
|
|
|
|
if (lBufferSize)
|
|
{
|
|
hr = ReAllocBuffer(lBufferSize);
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if the transfer goes past the buffer, try to expand it
|
|
|
|
if (lOffset + lLength > m_lBufferSize)
|
|
{
|
|
hr = ReAllocBuffer(lOffset + 2*lLength);
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
}
|
|
|
|
// keep track of data size
|
|
|
|
if (lOffset + lLength > m_lDataSize)
|
|
{
|
|
m_lDataSize = lOffset + lLength;
|
|
}
|
|
|
|
// copy the transfer buffer
|
|
|
|
PBYTE pBuffer = (PBYTE) GlobalLock(m_hBuffer);
|
|
|
|
if (pBuffer)
|
|
{
|
|
CopyMemory(pBuffer + lOffset, pbBuffer, lLength);
|
|
|
|
GlobalUnlock(m_hBuffer);
|
|
}
|
|
|
|
#ifdef DBG
|
|
DWORD nWritten;
|
|
SetFilePointer(m_hDumpFile, lOffset, 0, FILE_BEGIN);
|
|
WriteFile(m_hDumpFile, pbBuffer, lLength, &nWritten, 0);
|
|
#endif //DBG
|
|
|
|
QueryStopTimes(lStatus, lPercentComplete);
|
|
|
|
break;
|
|
}
|
|
|
|
case IT_MSG_STATUS:
|
|
{
|
|
// update the progress bar position
|
|
|
|
QueryStartTimes(lStatus, lPercentComplete);
|
|
|
|
UpdateStatus(lStatus, lPercentComplete);
|
|
|
|
QueryStopTimes(lStatus, lPercentComplete);
|
|
|
|
break;
|
|
}
|
|
|
|
case IT_MSG_TERMINATION:
|
|
{
|
|
PVOID pBuffer = GlobalLock(m_hBuffer);
|
|
|
|
if (pBuffer)
|
|
{
|
|
FixDibHeader(pBuffer, m_lDataSize);
|
|
|
|
GlobalUnlock(m_hBuffer);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case IT_MSG_NEW_PAGE:
|
|
{
|
|
// mspaint should not get this message, but...
|
|
|
|
PVOID pBuffer = GlobalLock(m_hBuffer);
|
|
|
|
if (pBuffer)
|
|
{
|
|
FixDibHeader(pBuffer, m_lDataSize);
|
|
|
|
GlobalUnlock(m_hBuffer);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
HRESULT CDataCallback::ReAllocBuffer(LONG lBufferSize)
|
|
{
|
|
// try to allocate the new buffer
|
|
|
|
Trace(_T("Allocating %d bytes for image data\n"), lBufferSize);
|
|
|
|
HGLOBAL hBuffer;
|
|
|
|
if (m_hBuffer == 0)
|
|
{
|
|
hBuffer = (PBYTE) GlobalAlloc(GMEM_MOVEABLE, lBufferSize);
|
|
}
|
|
else
|
|
{
|
|
hBuffer = (PBYTE) GlobalReAlloc(m_hBuffer, lBufferSize, 0);
|
|
}
|
|
|
|
if (hBuffer == 0)
|
|
{
|
|
theApp.SetMemoryEmergency(TRUE);
|
|
return S_FALSE;
|
|
}
|
|
|
|
// store this new buffer
|
|
|
|
m_hBuffer = hBuffer;
|
|
|
|
m_lBufferSize = lBufferSize;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
inline ULONG LineWidth(ULONG nWidth, ULONG nBitCount)
|
|
{
|
|
return (((nWidth * nBitCount) + 31) & ~31) >> 3;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
ULONG FindDibSize(LPCVOID pDib)
|
|
{
|
|
ULONG nHeaderSize = *(PDWORD)pDib;
|
|
|
|
// Do we recognize the header?
|
|
|
|
if (nHeaderSize != sizeof(BITMAPCOREHEADER) &&
|
|
nHeaderSize != sizeof(BITMAPINFOHEADER) &&
|
|
nHeaderSize != sizeof(BITMAPV4HEADER) &&
|
|
nHeaderSize != sizeof(BITMAPV5HEADER))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Start the calculation with the header size
|
|
|
|
ULONG nDibSize = nHeaderSize;
|
|
|
|
// is this an old style BITMAPCOREHEADER?
|
|
|
|
if (nHeaderSize == sizeof(BITMAPCOREHEADER))
|
|
{
|
|
PBITMAPCOREHEADER pbmch = (PBITMAPCOREHEADER) pDib;
|
|
|
|
// Add the color table size
|
|
|
|
if (pbmch->bcBitCount <= 8)
|
|
{
|
|
nDibSize += sizeof(RGBTRIPLE) * (1 << pbmch->bcBitCount);
|
|
}
|
|
|
|
// Add the bitmap size
|
|
|
|
nDibSize += LineWidth(pbmch->bcWidth, pbmch->bcBitCount) * pbmch->bcHeight;
|
|
}
|
|
else
|
|
{
|
|
// this is at least a BITMAPINFOHEADER
|
|
|
|
PBITMAPINFOHEADER pbmih = (PBITMAPINFOHEADER) pDib;
|
|
|
|
// Add the color table size
|
|
|
|
if (pbmih->biClrUsed != 0)
|
|
{
|
|
nDibSize += sizeof(RGBQUAD) * pbmih->biClrUsed;
|
|
}
|
|
else if (pbmih->biBitCount <= 8)
|
|
{
|
|
nDibSize += sizeof(RGBQUAD) * (1 << pbmih->biBitCount);
|
|
}
|
|
|
|
// Add the bitmap size
|
|
|
|
if (pbmih->biSizeImage != 0)
|
|
{
|
|
nDibSize += pbmih->biSizeImage;
|
|
}
|
|
else
|
|
{
|
|
// biSizeImage must be specified for compressed bitmaps
|
|
|
|
if (pbmih->biCompression != BI_RGB &&
|
|
pbmih->biCompression != BI_BITFIELDS)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
nDibSize += LineWidth(pbmih->biWidth, pbmih->biBitCount) * abs(pbmih->biHeight);
|
|
}
|
|
|
|
// Consider special cases
|
|
|
|
if (nHeaderSize == sizeof(BITMAPINFOHEADER))
|
|
{
|
|
// If this is a 16 or 32 bit bitmap and BI_BITFIELDS is used,
|
|
// bmiColors member contains three DWORD color masks.
|
|
// For V4 or V5 headers, this info is included the header
|
|
|
|
if (pbmih->biCompression == BI_BITFIELDS)
|
|
{
|
|
nDibSize += 3 * sizeof(DWORD);
|
|
}
|
|
}
|
|
else if (nHeaderSize >= sizeof(BITMAPV5HEADER))
|
|
{
|
|
// If this is a V5 header and an ICM profile is specified,
|
|
// we need to consider the profile data size
|
|
|
|
PBITMAPV5HEADER pbV5h = (PBITMAPV5HEADER) pDib;
|
|
|
|
// if there is some padding before the profile data, add it
|
|
|
|
if (pbV5h->bV5ProfileData > nDibSize)
|
|
{
|
|
nDibSize = pbV5h->bV5ProfileData;
|
|
}
|
|
|
|
// add the profile data size
|
|
|
|
nDibSize += pbV5h->bV5ProfileSize;
|
|
}
|
|
}
|
|
|
|
return nDibSize;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
ULONG FindDibOffBits(LPCVOID pDib)
|
|
{
|
|
ULONG nHeaderSize = *(PDWORD)pDib;
|
|
|
|
// Do we recognize the header?
|
|
|
|
if (nHeaderSize != sizeof(BITMAPCOREHEADER) &&
|
|
nHeaderSize != sizeof(BITMAPINFOHEADER) &&
|
|
nHeaderSize != sizeof(BITMAPV4HEADER) &&
|
|
nHeaderSize != sizeof(BITMAPV5HEADER))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Start the calculation with the header size
|
|
|
|
ULONG nOffBits = nHeaderSize;
|
|
|
|
// is this an old style BITMAPCOREHEADER?
|
|
|
|
if (nHeaderSize == sizeof(BITMAPCOREHEADER))
|
|
{
|
|
PBITMAPCOREHEADER pbmch = (PBITMAPCOREHEADER) pDib;
|
|
|
|
// Add the color table size
|
|
|
|
if (pbmch->bcBitCount <= 8)
|
|
{
|
|
nOffBits += sizeof(RGBTRIPLE) * (1 << pbmch->bcBitCount);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// this is at least a BITMAPINFOHEADER
|
|
|
|
PBITMAPINFOHEADER pbmih = (PBITMAPINFOHEADER) pDib;
|
|
|
|
// Add the color table size
|
|
|
|
if (pbmih->biClrUsed != 0)
|
|
{
|
|
nOffBits += sizeof(RGBQUAD) * pbmih->biClrUsed;
|
|
}
|
|
else if (pbmih->biBitCount <= 8)
|
|
{
|
|
nOffBits += sizeof(RGBQUAD) * (1 << pbmih->biBitCount);
|
|
}
|
|
|
|
// Consider special cases
|
|
|
|
if (nHeaderSize == sizeof(BITMAPINFOHEADER))
|
|
{
|
|
// If this is a 16 or 32 bit bitmap and BI_BITFIELDS is used,
|
|
// bmiColors member contains three DWORD color masks.
|
|
// For V4 or V5 headers, this info is included the header
|
|
|
|
if (pbmih->biCompression == BI_BITFIELDS)
|
|
{
|
|
nOffBits += 3 * sizeof(DWORD);
|
|
}
|
|
}
|
|
else if (nHeaderSize >= sizeof(BITMAPV5HEADER))
|
|
{
|
|
// If this is a V5 header and an ICM profile is specified,
|
|
// we need to consider the profile data size
|
|
|
|
PBITMAPV5HEADER pbV5h = (PBITMAPV5HEADER) pDib;
|
|
|
|
// if the profile data comes before the pixel data, add it
|
|
|
|
if (pbV5h->bV5ProfileData <= nOffBits)
|
|
{
|
|
nOffBits += pbV5h->bV5ProfileSize;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nOffBits;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
void FixDibHeader(LPVOID pDib, DWORD dwSize)
|
|
{
|
|
ULONG nHeaderSize = *(PDWORD)pDib;
|
|
|
|
// Do we recognize the header?
|
|
|
|
if (nHeaderSize != sizeof(BITMAPCOREHEADER) &&
|
|
nHeaderSize != sizeof(BITMAPINFOHEADER) &&
|
|
nHeaderSize != sizeof(BITMAPV4HEADER) &&
|
|
nHeaderSize != sizeof(BITMAPV5HEADER))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// is this an old style BITMAPCOREHEADER?
|
|
|
|
if (nHeaderSize == sizeof(BITMAPCOREHEADER))
|
|
{
|
|
PBITMAPCOREHEADER pbmch = (PBITMAPCOREHEADER) pDib;
|
|
|
|
// fix the height value if necessary
|
|
|
|
if (pbmch->bcHeight == 0)
|
|
{
|
|
// start the calculation with the header size
|
|
|
|
DWORD dwSizeImage = dwSize - nHeaderSize;
|
|
|
|
// subtract the color table size
|
|
|
|
if (pbmch->bcBitCount <= 8)
|
|
{
|
|
dwSizeImage -= sizeof(RGBTRIPLE) * (1 << pbmch->bcBitCount);
|
|
}
|
|
|
|
// calculate the height
|
|
|
|
pbmch->bcHeight = (WORD) (dwSizeImage / LineWidth(pbmch->bcWidth, pbmch->bcBitCount));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// this is at least a BITMAPINFOHEADER
|
|
|
|
PBITMAPINFOHEADER pbmih = (PBITMAPINFOHEADER) pDib;
|
|
|
|
// fix the height value if necessary
|
|
|
|
if (pbmih->biHeight == 0)
|
|
{
|
|
// find the size of the image data
|
|
|
|
DWORD dwSizeImage;
|
|
|
|
if (pbmih->biSizeImage != 0)
|
|
{
|
|
// if the size is specified in the header, take it
|
|
|
|
dwSizeImage = pbmih->biSizeImage;
|
|
}
|
|
else
|
|
{
|
|
// start the calculation with the header size
|
|
|
|
dwSizeImage = dwSize - nHeaderSize;
|
|
|
|
// subtract the color table size
|
|
|
|
if (pbmih->biClrUsed != 0)
|
|
{
|
|
dwSizeImage -= sizeof(RGBQUAD) * pbmih->biClrUsed;
|
|
}
|
|
else if (pbmih->biBitCount <= 8)
|
|
{
|
|
dwSizeImage -= sizeof(RGBQUAD) * (1 << pbmih->biBitCount);
|
|
}
|
|
|
|
// Consider special cases
|
|
|
|
if (nHeaderSize == sizeof(BITMAPINFOHEADER))
|
|
{
|
|
// If this is a 16 or 32 bit bitmap and BI_BITFIELDS is used,
|
|
// bmiColors member contains three DWORD color masks.
|
|
// For V4 or V5 headers, this info is included the header
|
|
|
|
if (pbmih->biCompression == BI_BITFIELDS)
|
|
{
|
|
dwSizeImage -= 3 * sizeof(DWORD);
|
|
}
|
|
}
|
|
else if (nHeaderSize >= sizeof(BITMAPV5HEADER))
|
|
{
|
|
// If this is a V5 header and an ICM profile is specified,
|
|
// we need to consider the profile data size
|
|
|
|
PBITMAPV5HEADER pbV5h = (PBITMAPV5HEADER) pDib;
|
|
|
|
// add the profile data size
|
|
|
|
dwSizeImage -= pbV5h->bV5ProfileSize;
|
|
}
|
|
|
|
// store the image size
|
|
|
|
pbmih->biSizeImage = dwSizeImage;
|
|
}
|
|
|
|
// finally, calculate the height
|
|
|
|
pbmih->biHeight = -(LONG) (dwSizeImage / LineWidth(pbmih->biWidth, pbmih->biBitCount));
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
void CDataCallback::UpdateStatus(LONG lStatus, LONG lPercentComplete)
|
|
{
|
|
if (m_pProgress)
|
|
{
|
|
m_pProgress->SetPercentComplete(lPercentComplete);
|
|
|
|
CString strFormat;
|
|
|
|
switch (lStatus)
|
|
{
|
|
case IT_STATUS_TRANSFER_FROM_DEVICE:
|
|
strFormat.LoadString(IDS_STATUS_TRANSFER_FROM_DEVICE);
|
|
break;
|
|
|
|
case IT_STATUS_PROCESSING_DATA:
|
|
strFormat.LoadString(IDS_STATUS_PROCESSING_DATA);
|
|
break;
|
|
|
|
case IT_STATUS_TRANSFER_TO_CLIENT:
|
|
strFormat.LoadString(IDS_STATUS_TRANSFER_TO_CLIENT);
|
|
break;
|
|
}
|
|
|
|
CString strStatusText;
|
|
strStatusText.Format(strFormat, lPercentComplete);
|
|
|
|
USES_CONVERSION;
|
|
m_pProgress->SetMessage(T2CW(strStatusText));
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
#ifdef DBG
|
|
|
|
void CDataCallback::QueryStartTimes(LONG lStatus, LONG lPercentComplete)
|
|
{
|
|
if (lStatus & IT_STATUS_TRANSFER_FROM_DEVICE &&
|
|
(lPercentComplete == 0 || m_TimeDeviceBegin.QuadPart == 0))
|
|
{
|
|
QueryPerformanceCounter(&m_TimeDeviceBegin);
|
|
}
|
|
|
|
if (lStatus & IT_STATUS_PROCESSING_DATA &&
|
|
(lPercentComplete == 0 || m_TimeProcessBegin.QuadPart == 0))
|
|
{
|
|
QueryPerformanceCounter(&m_TimeProcessBegin);
|
|
}
|
|
|
|
if (lStatus & IT_STATUS_TRANSFER_TO_CLIENT &&
|
|
(lPercentComplete == 0 || m_TimeClientBegin.QuadPart == 0))
|
|
{
|
|
QueryPerformanceCounter(&m_TimeClientBegin);
|
|
}
|
|
}
|
|
|
|
void CDataCallback::QueryStopTimes(LONG lStatus, LONG lPercentComplete)
|
|
{
|
|
if (lStatus & IT_STATUS_TRANSFER_FROM_DEVICE && lPercentComplete == 100)
|
|
{
|
|
QueryPerformanceCounter(&m_TimeDeviceEnd);
|
|
}
|
|
|
|
if (lStatus & IT_STATUS_PROCESSING_DATA && lPercentComplete == 100)
|
|
{
|
|
QueryPerformanceCounter(&m_TimeProcessEnd);
|
|
}
|
|
|
|
if (lStatus & IT_STATUS_TRANSFER_TO_CLIENT && lPercentComplete == 100)
|
|
{
|
|
QueryPerformanceCounter(&m_TimeClientEnd);
|
|
}
|
|
}
|
|
|
|
void CDataCallback::PrintTimes()
|
|
{
|
|
LARGE_INTEGER Freq;
|
|
QueryPerformanceFrequency(&Freq);
|
|
|
|
double nTimeDevice =
|
|
(double) (m_TimeDeviceEnd.QuadPart - m_TimeDeviceBegin.QuadPart) /
|
|
(double) Freq.QuadPart;
|
|
|
|
double nTimeProcess =
|
|
(double) (m_TimeProcessEnd.QuadPart - m_TimeProcessBegin.QuadPart) /
|
|
(double) Freq.QuadPart;
|
|
|
|
double nTimeClient =
|
|
(double) (m_TimeClientEnd.QuadPart - m_TimeClientBegin.QuadPart) /
|
|
(double) Freq.QuadPart;
|
|
|
|
Trace(
|
|
_T("TRANSFER_FROM_DEVICE = %.02lf secs\n")
|
|
_T("PROCESSING_DATA = %.02lf secs\n")
|
|
_T("TRANSFER_TO_CLIENT = %.02lf secs\n")
|
|
_T("\n"),
|
|
nTimeDevice,
|
|
nTimeProcess,
|
|
nTimeClient
|
|
);
|
|
}
|
|
|
|
#else //DBG
|
|
|
|
inline void CDataCallback::QueryStartTimes(LONG, LONG)
|
|
{
|
|
}
|
|
|
|
inline void CDataCallback::QueryStopTimes(LONG, LONG)
|
|
{
|
|
}
|
|
|
|
inline void CDataCallback::PrintTimes()
|
|
{
|
|
}
|
|
|
|
#endif //DBG
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//
|
|
|
|
CProgressDialog::CProgressDialog()
|
|
{
|
|
m_cRef = 0;
|
|
}
|
|
|
|
CProgressDialog::~CProgressDialog()
|
|
{
|
|
// remove the "downloading..." message from the status bar
|
|
|
|
if (g_pStatBarWnd)
|
|
{
|
|
g_pStatBarWnd->SetPaneText(0, _T(""));
|
|
}
|
|
}
|
|
|
|
STDMETHODIMP CProgressDialog::QueryInterface(REFIID iid, LPVOID *ppvObj)
|
|
{
|
|
if (ppvObj == 0)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (iid == IID_IUnknown)
|
|
{
|
|
AddRef();
|
|
*ppvObj = (IUnknown*) this;
|
|
return S_OK;
|
|
}
|
|
|
|
if (iid == IID_IWiaProgressDialog)
|
|
{
|
|
AddRef();
|
|
*ppvObj = (IWiaProgressDialog *) this;
|
|
return S_OK;
|
|
}
|
|
|
|
*ppvObj = 0;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CProgressDialog::AddRef()
|
|
{
|
|
return InterlockedIncrement(&m_cRef);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CProgressDialog::Release()
|
|
{
|
|
ASSERT( 0 != m_cRef );
|
|
LONG cRef = InterlockedDecrement(&m_cRef);
|
|
|
|
if (cRef == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
return cRef;
|
|
}
|
|
|
|
STDMETHODIMP CProgressDialog::Create(HWND hwndParent, LONG lFlags)
|
|
{
|
|
if (g_pStatBarWnd)
|
|
{
|
|
RECT r;
|
|
g_pStatBarWnd->GetItemRect(1, &r);
|
|
|
|
m_ProgressCtrl.Create(WS_CHILD | WS_VISIBLE, r, g_pStatBarWnd, 1);
|
|
m_ProgressCtrl.SetRange(0, 100);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CProgressDialog::Show()
|
|
{
|
|
m_ProgressCtrl.UpdateWindow();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CProgressDialog::Hide()
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CProgressDialog::Cancelled(BOOL *pbCancelled)
|
|
{
|
|
*pbCancelled = FALSE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CProgressDialog::SetTitle(LPCWSTR pszMessage)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CProgressDialog::SetMessage(LPCWSTR pszTitle)
|
|
{
|
|
if (g_pStatBarWnd)
|
|
{
|
|
USES_CONVERSION;
|
|
g_pStatBarWnd->SetPaneText(0, W2CT(pszTitle));
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CProgressDialog::SetPercentComplete(UINT nPercent)
|
|
{
|
|
m_ProgressCtrl.SetPos(nPercent);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CProgressDialog::Destroy()
|
|
{
|
|
return S_OK;
|
|
}
|
|
|