Следовал инструкциям Microsoft по внедрению приложения MFC GUI, совместимого с XP, для чтения изображений с принтера / сканера Canon MF6540.
С lpszFileName в STGMEDIUM, оставленным в NULL, idtGetData терпит неудачу с STG_E_MEDIUMFULL.
Если для lpszFileName задано значение L «c: \ tmp \ foo.bmp», где «c: \ tmp» — это существующая папка, происходит сбой idtGetData с 0xC0000005.
Как я могу, пожалуйста, idtGetData? Благодарю.
// WIADlg.cpp : implementation file
//
#include "stdafx.h"#include "WIA.h"#include "WIADlg.h"#include "WIADataCallback.h"#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif// CAboutDlg dialog used for App About
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// Dialog Data
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CWIADlg dialog
CWIADlg::CWIADlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CWIADlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_root = NULL;
m_scanner = NULL;
}
void CWIADlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CWIADlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDOK, &CWIADlg::OnBnClickedOk)
ON_BN_CLICKED(IDC_BUTTON_SCAN, &CWIADlg::OnBnClickedButtonScan)
END_MESSAGE_MAP()// CWIADlg message handlers
BOOL CWIADlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
CoInitialize(NULL);
HRESULT hr = CoCreateInstance(CLSID_WiaDevMgr, NULL, CLSCTX_LOCAL_SERVER, IID_IWiaDevMgr, (void**)&m_pWiaDevMgr);
if (FAILED(hr))
{
CString str;
str.Format("CoCreateInstance CLSID_WiaDevMsg failure %08X", hr);
MessageBox(str);
}
IEnumWIA_DEV_INFO *pWiaEnumDevInfo = NULL;
hr = m_pWiaDevMgr->EnumDeviceInfo(WIA_DEVINFO_ENUM_LOCAL, &pWiaEnumDevInfo);
if (SUCCEEDED(hr))
{
// Loop until you get an error or pWiaEnumDevInfo->Next returns S_FALSE to signal the end of the list.
while (S_OK == hr)
{
// Get the next device's property storage interface pointer
IWiaPropertyStorage *pWiaPropertyStorage = NULL;
hr = pWiaEnumDevInfo->Next(1, &pWiaPropertyStorage, NULL);
// pWiaEnumDevInfo->Next will return S_FALSE when the list is exhausted, so check for S_OK before using the returned value.
if (hr == S_OK)
{
// Do something with the device's IWiaPropertyStorage*
ReadSomeWiaProperties(pWiaPropertyStorage);
// Release the device's IWiaPropertyStorage*
pWiaPropertyStorage->Release();
pWiaPropertyStorage = NULL;
}
}
// If the result of the enumeration is S_FALSE (which is normal), change it to S_OK.
if (S_FALSE == hr)
{
hr = S_OK;
}
// Release the enumerator
pWiaEnumDevInfo->Release();
pWiaEnumDevInfo = NULL;
}
return TRUE; // return TRUE unless you set the focus to a control
}
void CWIADlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CWIADlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
// The system calls this function to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CWIADlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
HRESULT CWIADlg::ReadSomeWiaProperties(IWiaPropertyStorage *pWiaPropertyStorage)
{
// Declare PROPSPECs and PROPVARIANTs, and initialize them to zero.
PROPSPEC PropSpec[3] = {0};
PROPVARIANT PropVar[3] = {0};
// How many properties are you querying for?
const ULONG c_nPropertyCount = sizeof(PropSpec)/sizeof(PropSpec[0]);
// Define which properties you want to read:
// Device ID. This is what you would use to create the device.
PropSpec[0].ulKind = PRSPEC_PROPID;
PropSpec[0].propid = WIA_DIP_DEV_ID;
// Device Name
PropSpec[1].ulKind = PRSPEC_PROPID;
PropSpec[1].propid = WIA_DIP_DEV_NAME;
// Device description
PropSpec[2].ulKind = PRSPEC_PROPID;
PropSpec[2].propid = WIA_DIP_DEV_DESC;
// Ask for the property values
HRESULT hr = pWiaPropertyStorage->ReadMultiple(c_nPropertyCount, PropSpec, PropVar);
if (SUCCEEDED(hr))
{
// IWiaPropertyStorage::ReadMultiple will return S_FALSE if some
// properties could not be read, so you have to check the return
// types for each requested item.
CString str;
WIA_DEVICE *device = new WIA_DEVICE;
// Check the return type for the device ID
if (VT_BSTR == PropVar[0].vt)
{
// Do something with the device ID
TRACE(TEXT("WIA_DIP_DEV_ID: %ws\n"), PropVar[0].bstrVal);
device->deviceID.Format("%ws", PropVar[0].bstrVal);
device->bstrDeviceID = SysAllocString(PropVar[0].bstrVal);
}
// Check the return type for the device name
if (VT_BSTR == PropVar[1].vt)
{
// Do something with the device name
TRACE(TEXT("WIA_DIP_DEV_NAME: %ws\n"), PropVar[1].bstrVal);
device->deviceName.Format("%ws", PropVar[1].bstrVal);
}
// Check the return type for the device description
if (VT_BSTR == PropVar[2].vt)
{
// Do something with the device description
TRACE(TEXT("WIA_DIP_DEV_DESC: %ws\n"), PropVar[2].bstrVal);
device->deviceDesc.Format("%ws", PropVar[2].bstrVal);
}
CListBox *list = (CListBox*)GetDlgItem(IDC_LIST_WIA_DEVICES);
int nIndex = list->AddString((LPCTSTR)device->deviceName);
list->SetItemDataPtr(nIndex, device);
// Free the returned PROPVARIANTs
FreePropVariantArray(c_nPropertyCount, PropVar);
}
// Return the result of reading the properties
return hr;
}void CWIADlg::OnBnClickedOk()
{
// TODO: Add your control notification handler code here
CDialogEx::OnOK();
}void CWIADlg::OnBnClickedButtonScan()
{
// TODO: Add your control notification handler code here
CListBox *list = (CListBox*)GetDlgItem(IDC_LIST_WIA_DEVICES);
int nIndex = list->GetCurSel();
if (nIndex < 0)
{
MessageBox("No device selected");
return;
}
WIA_DEVICE *device = (WIA_DEVICE*)list->GetItemDataPtr(nIndex);
MessageBox(device->deviceName);
HRESULT hr = m_pWiaDevMgr->CreateDevice(device->bstrDeviceID, &m_root);
if (FAILED(hr))
{
CString str;
str.Format("CreateDevice failure %08X", hr);
MessageBox(str);
}
EnumerateItems(m_root);
TransferWiaItem(m_root, m_scanner);
}
HRESULT CWIADlg::EnumerateItems(IWiaItem *pWiaItem)
{
CString str;
// Get the item type for this item.
LONG lItemType = 0;
HRESULT hr = pWiaItem->GetItemType(&lItemType);
if (SUCCEEDED(hr))
{
str.Format("pWiaItem=%08X", pWiaItem);
if (lItemType & WiaItemTypeAnalyze)
str += " WiaItemTypeAnalyze";
if (lItemType & WiaItemTypeAudio)
str += " WiaItemTypeAudio";
if (lItemType & WiaItemTypeBurst)
str += " WiaItemTypeBurst";
if (lItemType & WiaItemTypeDeleted)
str += " WiaItemTypeDeleted";
if (lItemType & WiaItemTypeDevice)
str += " WiaItemTypeDevice";
if (lItemType & WiaItemTypeDisconnected)
str += " WiaItemTypeDisconnected";
if (lItemType & WiaItemTypeDocument)
str += " WiaItemTypeDocument";
if (lItemType & WiaItemTypeFile)
str += " WiaItemTypeFile";
if (lItemType & WiaItemTypeFolder)
str += " WiaItemTypeFolder";
if (lItemType & WiaItemTypeFree)
str += " WiaItemTypeFree";
if (lItemType & WiaItemTypeGenerated)
str += " WiaITemTypeGenerated";
if (lItemType & WiaItemTypeHasAttachments)
str += " WiaItemTypeHasAttachments";
if (lItemType & WiaItemTypeHPanorama)
str += " WiaItemTypeHPanorama";
if (lItemType & WiaItemTypeImage)
{
str += " WiaItemTypeImage";
m_scanner = pWiaItem;
}
if (lItemType & WiaItemTypeProgrammableDataSource)
str += " WiaItemTypeProgrammableDataSource";
if (lItemType & WiaItemTypeRemoved)
str += " WiaItemTypeRemoved";
if (lItemType & WiaItemTypeRoot)
str += " WiaItemTypeRoot";
if (lItemType & WiaItemTypeStorage)
str += " WiaItemTypeStorage";
if (lItemType & WiaItemTypeTransfer)
str += " WiaItemTypeTransfer";
// if (lItemType & WiaItemTypeTwainCapabilityPassThrough)
// str += " WiaItemTypeTwainCapabilityPassThrough";
if (lItemType & WiaItemTypeVideo)
str += " WiaItemTypeVideo";
if (lItemType & WiaItemTypeVPanorama)
str += " WiaItemTypeVPanorama";
MessageBox(str);
// If it is a folder, or it has attachments, enumerate its children.
if (lItemType & WiaItemTypeFolder || lItemType & WiaItemTypeHasAttachments)
{
// Get the child item enumerator for this item.
IEnumWiaItem *pEnumWiaItem = NULL;
hr = pWiaItem->EnumChildItems(&pEnumWiaItem);
if (SUCCEEDED(hr))
{
// Loop until you get an error or pEnumWiaItem->Next returns S_FALSE to signal the end of the list.
while (S_OK == hr)
{
str.Format("pEnumWiaItem=%08X", pEnumWiaItem);
MessageBox(str);
// Get the next child item.
IWiaItem *pChildWiaItem = NULL;
hr = pEnumWiaItem->Next(1, &pChildWiaItem, NULL);
// pEnumWiaItem->Next will return S_FALSE when the list is
// exhausted, so check for S_OK before using the returned
// value.
if (S_OK == hr)
{
str.Format("pChildWiaItem=%08X", pChildWiaItem);
MessageBox(str);
// Recurse into this item.
hr = EnumerateItems(pChildWiaItem);
#if 0
// Release this item.
str.Format("Releasing %08X", pChildWiaItem);
MessageBox(str);
pChildWiaItem->Release();
pChildWiaItem = NULL;
#endif
}
}
// If the result of the enumeration is S_FALSE (which is normal), change it to S_OK.
if (S_FALSE == hr)
{
hr = S_OK;
}
// Release the enumerator.
pEnumWiaItem->Release();
pEnumWiaItem = NULL;
}
}
}
return hr;
}
HRESULT CWIADlg::TransferWiaItem(IWiaItem *root, IWiaItem *scanner)
{
CString str;
// Get the IWiaPropertyStorage interface so you can set required properties.
IWiaPropertyStorage *pWiaPropertyStorage = NULL;
HRESULT hr = root->QueryInterface(IID_IWiaPropertyStorage, (void**)&pWiaPropertyStorage);
if (SUCCEEDED(hr))
{
// Prepare PROPSPECs and PROPVARIANTs for setting the media type and format
PROPSPEC PropSpec[2] = {0};
PROPVARIANT PropVariant[2] = {0};
const ULONG c_nPropCount = sizeof(PropVariant) / sizeof(PropVariant[0]);
// Use BMP as the output format
GUID guidOutputFormat = WiaImgFmt_BMP;
// Initialize the PROPSPECs
PropSpec[0].ulKind = PRSPEC_PROPID;
PropSpec[0].propid = WIA_IPA_FORMAT;
PropSpec[1].ulKind = PRSPEC_PROPID;
PropSpec[1].propid = WIA_IPA_TYMED;
// Initialize the PROPVARIANTs
PropVariant[0].vt = VT_CLSID;
PropVariant[0].puuid = &guidOutputFormat;
PropVariant[1].vt = VT_I4;
PropVariant[1].lVal = TYMED_FILE;
// Set the properties
hr = pWiaPropertyStorage->WriteMultiple(c_nPropCount, PropSpec, PropVariant, WIA_IPA_FIRST);
if (SUCCEEDED(hr))
{
// Get the IWiaDataTransfer interface
IWiaDataTransfer *pWiaDataTransfer = NULL;
hr = scanner->QueryInterface(IID_IWiaDataTransfer, (void**)&pWiaDataTransfer);
if (SUCCEEDED(hr))
{
#if 1
// Create our callback class
CWiaDataCallback *pCallback = new CWiaDataCallback;
if (pCallback)
{
// Get the IWiaDataCallback interface from our callback class.
IWiaDataCallback *pWiaDataCallback = NULL;
hr = pCallback->QueryInterface(IID_IWiaDataCallback, (void**)&pWiaDataCallback);
if (SUCCEEDED(hr))
{
AfxMessageBox("calling idtGetData");
// Perform the transfer using default settings
STGMEDIUM stgMedium = {0};
stgMedium.tymed = TYMED_FILE;
stgMedium.lpszFileName = L"c:\\tmp\\foo.bmp";
hr = pWiaDataTransfer->idtGetData(&stgMedium, pWiaDataCallback);
if (S_OK == hr)
{
// Print the filename (note that this filename is always a WCHAR string, not TCHAR).
str.Format("Transferred filename: %ws", stgMedium.lpszFileName);
AfxMessageBox(str);
// Release any memory associated with the stgmedium This will delete the file stgMedium.lpszFileName.
ReleaseStgMedium(&stgMedium);
}
else
{
str.Format("idtGetData failure=%08X", hr);
AfxMessageBox(str);
}
// Release the callback interface
pWiaDataCallback->Release();
pWiaDataCallback = NULL;
}
// Release our callback. It should now delete itself.
pCallback->Release();
pCallback = NULL;
}
#else
// Perform the transfer using default settings
STGMEDIUM stgMedium = {0};
stgMedium.tymed = TYMED_FILE;
// stgMedium.lpszFileName = L"c:\\tmp\\foo.bmp";
hr = pWiaDataTransfer->idtGetData(&stgMedium, NULL);
if (S_OK == hr)
{
// Print the filename (note that this filename is always a WCHAR string, not TCHAR).
str.Format(TEXT("Transferred filename: %ws"), stgMedium.lpszFileName);
MessageBox(str);
// Release any memory associated with the stgmedium This will delete the file stgMedium.lpszFileName.
ReleaseStgMedium(&stgMedium);
}
else
{
str.Format("idtGetData failure=%08X", hr);
MessageBox(str);
}
#endif
// Release the IWiaDataTransfer
pWiaDataTransfer->Release();
pWiaDataTransfer = NULL;
}
else
{
str.Format("TransferWiaItem::QueryInterface IID_IWiaDataTransfer failure=%08X", hr);
MessageBox(str);
}
}
else
{
str.Format("TransferWiaItem::WriteMultiple failure=%08X", hr);
MessageBox(str);
}
// Release the IWiaPropertyStorage
pWiaPropertyStorage->Release();
pWiaPropertyStorage = NULL;
}
else
{
str.Format("TransferWiaItem::QueryInterface IID_IWiaPropertyStorage failure=%08X", hr);
MessageBox(str);
}
return hr;
}
Задача ещё не решена.
Других решений пока нет …