Archivo de implementación de "Hola mundo"
Este minidriver WIA es un archivo DLL sencillo que exporta dos funciones (vea "archivo de definición de Hola mundo") e implementa tres interfaces COM (consulte Proporcionar una interfaz COM). El siguiente ejemplo de código de minidriver WIA se puede compilar en un controlador de trabajo. El árbol de elementos que crea este minidriver WIA tiene un elemento raíz, pero no hay elementos secundarios y no puede transferir datos.
El archivo hellowld.cpp debe contener lo siguiente:
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <stdio.h>
#include <windows.h>
#include <initguid.h>
#include <sti.h>
#include <stiusd.h>
#include <wiamindr.h>
// {7C1E2309-A535-45b1-94B3-9A020EE600C6}
DEFINE_GUID(CLSID_HelloWorldWIADevice, 0x7c1e2309, 0xa535, 0x45b1, 0x94, 0xb3, 0x9a, 0x2, 0xe, 0xe6, 0x0, 0xc6);
#define WIA_DEVICE_ROOT_NAME L"Root" // THIS SHOULD NOT BE LOCALIZED
#define DEFAULT_LOCK_TIMEOUT 1000
class INonDelegatingUnknown {
public:
virtual STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,LPVOID *ppvObj) = 0;
virtual STDMETHODIMP_(ULONG) NonDelegatingAddRef() = 0;
virtual STDMETHODIMP_(ULONG) NonDelegatingRelease() = 0;
};
class CWIADevice : public INonDelegatingUnknown, // NonDelegatingUnknown
public IStiUSD, // STI USD interface
public IWiaMiniDrv // WIA Minidriver interface
{
public:
//////////////////////////////////////////////////////////////////////
// Constructor/Destructor Section //
//////////////////////////////////////////////////////////////////////
CWIADevice(LPUNKNOWN punkOuter) : m_cRef(1),
m_punkOuter(NULL),
m_pIStiDevice(NULL),
m_pIDrvItemRoot(NULL),
m_lClientsConnected(0) {
memset(m_WIAFormatInfo,0,sizeof(m_WIAFormatInfo));
if (punkOuter) {
m_punkOuter = punkOuter;
}
}
~CWIADevice() {
if(m_pIDrvItemRoot) {
HRESULT hr = m_pIDrvItemRoot->UnlinkItemTree(WiaItemTypeDisconnected);
m_pIDrvItemRoot->Release();
m_pIDrvItemRoot = NULL;
}
if(m_pIStiDevice) {
m_pIStiDevice->Release();
m_pIStiDevice = NULL;
}
}
private:
LONG m_cRef; // Device object reference count.
LONG m_lClientsConnected; // number of applications connected
IStiDevice *m_pIStiDevice; // STI device interface for locking
IWiaDrvItem *m_pIDrvItemRoot; // WIA root item
WIA_FORMAT_INFO m_WIAFormatInfo[2]; // WIA format information
LPUNKNOWN m_punkOuter; // Pointer to outer unknown.
public:
//////////////////////////////////////////////////////////////////////
// Standard COM Methods Section //
//////////////////////////////////////////////////////////////////////
STDMETHODIMP QueryInterface( REFIID riid, LPVOID * ppvObj)
{
if (!m_punkOuter) {
return E_NOINTERFACE;
}
return m_punkOuter->QueryInterface(riid,ppvObj);
}
STDMETHODIMP_(ULONG) AddRef()
{
if (!m_punkOuter) {
return 0;
}
return m_punkOuter->AddRef();
}
STDMETHODIMP_(ULONG) Release()
{
if (!m_punkOuter) {
return 0;
}
return m_punkOuter->Release();
}
//////////////////////////////////////////////////////////////////////
// IStiUSD Interface Section (for all WIA drivers) //
//////////////////////////////////////////////////////////////////////
STDMETHOD(Initialize)(THIS_
PSTIDEVICECONTROL pHelDcb,
DWORD dwStiVersion,
HKEY hParametersKey) {return S_OK;}
STDMETHOD(GetCapabilities)(THIS_ PSTI_USD_CAPS pDevCaps)
{
memset(pDevCaps, 0, sizeof(STI_USD_CAPS));
pDevCaps->dwVersion = STI_VERSION; // STI version
pDevCaps->dwGenericCaps = STI_GENCAP_WIA; // WIA support
return S_OK;
}
STDMETHOD(GetStatus)(THIS_ PSTI_DEVICE_STATUS pDevStatus){return E_NOTIMPL;}
STDMETHOD(DeviceReset)(THIS){return E_NOTIMPL;}
STDMETHOD(Diagnostic)(THIS_ LPDIAG pBuffer){return E_NOTIMPL;}
STDMETHOD(Escape)(THIS_
STI_RAW_CONTROL_CODE EscapeFunction,
LPVOID lpInData,
DWORD cbInDataSize,
LPVOID pOutData,
DWORD dwOutDataSize,
LPDWORD pdwActualData){return E_NOTIMPL;}
STDMETHOD(GetLastError)(THIS_ LPDWORD pdwLastDeviceError){return E_NOTIMPL;}
STDMETHOD(LockDevice)(THIS){return S_OK;}
STDMETHOD(UnLockDevice)(THIS){return S_OK;}
STDMETHOD(RawReadData)(THIS_
LPVOID lpBuffer,
LPDWORD lpdwNumberOfBytes,
LPOVERLAPPED lpOverlapped){return E_NOTIMPL;}
STDMETHOD(RawWriteData)(THIS_
LPVOID lpBuffer,
DWORD nNumberOfBytes,
LPOVERLAPPED lpOverlapped){return E_NOTIMPL;}
STDMETHOD(RawReadCommand)(THIS_
LPVOID lpBuffer,
LPDWORD lpdwNumberOfBytes,
LPOVERLAPPED lpOverlapped){return E_NOTIMPL;}
STDMETHOD(RawWriteCommand)(THIS_
LPVOID lpBuffer,
DWORD dwNumberOfBytes,
LPOVERLAPPED lpOverlapped){return E_NOTIMPL;}
STDMETHOD(SetNotificationHandle)(THIS_ HANDLE hEvent){return E_NOTIMPL;}
STDMETHOD(GetNotificationData)(THIS_ LPSTINOTIFY lpNotify){return E_NOTIMPL;}
STDMETHOD(GetLastErrorInfo)(THIS_ STI_ERROR_INFO *pLastErrorInfo){return E_NOTIMPL;}
//////////////////////////////////////////////////////////////////////
// IWiaMiniDrv Interface Section (for all WIA drivers) //
//////////////////////////////////////////////////////////////////////
STDMETHOD(drvInitializeWia)(THIS_
BYTE *pWiasContext,
LONG lFlags,
BSTR bstrDeviceID,
BSTR bstrRootFullItemName,
IUnknown *pStiDevice,
IUnknown *pIUnknownOuter,
IWiaDrvItem **ppIDrvItemRoot,
IUnknown **ppIUnknownInner,
LONG *plDevErrVal)
{
if ((!pWiasContext)||(!plDevErrVal)) {
return E_INVALIDARG;
}
HRESULT hr = S_OK;
*plDevErrVal = 0;
*ppIDrvItemRoot = NULL;
*ppIUnknownInner = NULL;
if(!m_pIStiDevice) {
m_pIStiDevice = reinterpret_cast<IStiDevice*>(pStiDevice);
}
if(!m_pIDrvItemRoot) {
LONG lItemFlags = WiaItemTypeFolder|WiaItemTypeDevice|WiaItemTypeRoot;
BSTR bstrRootItemName = SysAllocString(WIA_DEVICE_ROOT_NAME);
if (bstrRootItemName) {
hr = wiasCreateDrvItem(lItemFlags, // item flags
bstrRootItemName, // item name ("Root")
bstrRootFullItemName, // item full name ("0000\Root")
(IWiaMiniDrv*)this, // this WIA driver object
0, // size of context
NULL, // context
&m_pIDrvItemRoot); // created ROOT item
// (IWiaDrvItem interface)
if (S_OK == hr) {
InterlockedIncrement(&m_lClientsConnected);
}
SysFreeString(bstrRootItemName);
bstrRootItemName = NULL;
} else {
hr = E_OUTOFMEMORY;
}
}
*ppIDrvItemRoot = m_pIDrvItemRoot;
return hr;
}
STDMETHOD(drvAcquireItemData)(THIS_
BYTE *pWiasContext,
LONG lFlags,
PMINIDRV_TRANSFER_CONTEXT pmdtc,
LONG *plDevErrVal){return E_NOTIMPL;}
STDMETHOD(drvInitItemProperties)(THIS_
BYTE *pWiasContext,
LONG lFlags,
LONG *plDevErrVal){return S_OK;}
STDMETHOD(drvValidateItemProperties)(THIS_
BYTE *pWiasContext,
LONG lFlags,
ULONG nPropSpec,
const PROPSPEC *pPropSpec,
LONG *plDevErrVal){return E_NOTIMPL;}
STDMETHOD(drvWriteItemProperties)(THIS_
BYTE *pWiasContext,
LONG lFlags,
PMINIDRV_TRANSFER_CONTEXT pmdtc,
LONG *plDevErrVal){return E_NOTIMPL;}
STDMETHOD(drvReadItemProperties)(THIS_
BYTE *pWiasContext,
LONG lFlags,
ULONG nPropSpec,
const PROPSPEC *pPropSpec,
LONG *plDevErrVal){return E_NOTIMPL;}
STDMETHOD(drvLockWiaDevice)(THIS_
BYTE *pWiasContext,
LONG lFlags,
LONG *plDevErrVal)
{
if(m_pIStiDevice)
return m_pIStiDevice->LockDevice(DEFAULT_LOCK_TIMEOUT);
else
return S_OK;
}
STDMETHOD(drvUnLockWiaDevice)(THIS_
BYTE *pWiasContext,
LONG lFlags,
LONG *plDevErrVal)
{
if(m_pIStiDevice)
return m_pIStiDevice->UnLockDevice();
else
return S_OK;
}
STDMETHOD(drvAnalyzeItem)(THIS_
BYTE *pWiasContext,
LONG lFlags,
LONG *plDevErrVal){return E_NOTIMPL;}
STDMETHOD(drvGetDeviceErrorStr)(THIS_
LONG lFlags,
LONG lDevErrVal,
LPOLESTR *ppszDevErrStr,
LONG *plDevErr){return E_NOTIMPL;}
STDMETHOD(drvDeviceCommand)(THIS_
BYTE *pWiasContext,
LONG lFlags,
const GUID *plCommand,
IWiaDrvItem **ppWiaDrvItem,
LONG *plDevErrVal){return E_NOTIMPL;}
STDMETHOD(drvGetCapabilities)(THIS_
BYTE *pWiasContext,
LONG ulFlags,
LONG *pcelt,
WIA_DEV_CAP_DRV **ppCapabilities,
LONG *plDevErrVal)
{
*pcelt = 0;
return S_OK;
}
STDMETHOD(drvDeleteItem)(THIS_
BYTE *pWiasContext,
LONG lFlags,
LONG *plDevErrVal){return E_NOTIMPL;}
STDMETHOD(drvFreeDrvItemContext)(THIS_
LONG lFlags,
BYTE *pSpecContext,
LONG *plDevErrVal){return S_OK;}
STDMETHOD(drvGetWiaFormatInfo)(THIS_
BYTE *pWiasContext,
LONG lFlags,
LONG *pcelt,
WIA_FORMAT_INFO **ppwfi,
LONG *plDevErrVal)
{
if ((!pWiasContext)||(!plDevErrVal)||(!pcelt)||(!ppwfi)) {
return E_INVALIDARG;
}
if (m_WIAFormatInfo[0].lTymed == TYMED_NULL) {
m_WIAFormatInfo[0].guidFormatID = WiaImgFmt_MEMORYBMP;
m_WIAFormatInfo[0].lTymed = TYMED_CALLBACK;
m_WIAFormatInfo[1].guidFormatID = WiaImgFmt_BMP;
m_WIAFormatInfo[1].lTymed = TYMED_FILE;
}
*plDevErrVal = 0;
*ppwfi = &m_WIAFormatInfo[0];
*pcelt = 2; // number of formats in returned array
return S_OK;
}
STDMETHOD(drvNotifyPnpEvent)(THIS_
const GUID *pEventGUID,
BSTR bstrDeviceID,
ULONG ulReserved){return E_NOTIMPL;}
STDMETHOD(drvUnInitializeWia)(THIS_ BYTE *pWiasContext)
{
if(InterlockedDecrement(&m_lClientsConnected) < 0) {
m_lClientsConnected = 0;
}
if(m_lClientsConnected == 0) {
if(m_pIDrvItemRoot) {
HRESULT hr = m_pIDrvItemRoot->UnlinkItemTree(WiaItemTypeDisconnected);
m_pIDrvItemRoot->Release();
m_pIDrvItemRoot = NULL;
}
}
return S_OK;
}
//////////////////////////////////////////////////////////////////////
// INonDelegating Interface Section (for all WIA drivers) //
//////////////////////////////////////////////////////////////////////
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,LPVOID *ppvObj)
{
if (!ppvObj) {
return E_INVALIDARG;
}
*ppvObj = NULL;
if (IsEqualIID( riid, IID_IUnknown )) {
*ppvObj = static_cast<INonDelegatingUnknown*>(this);
} else if (IsEqualIID( riid, IID_IStiUSD )) {
*ppvObj = static_cast<IStiUSD*>(this);
} else if (IsEqualIID( riid, IID_IWiaMiniDrv )) {
*ppvObj = static_cast<IWiaMiniDrv*>(this);
} else {
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(*ppvObj)->AddRef();
return S_OK;
}
STDMETHODIMP_(ULONG) NonDelegatingAddRef()
{
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) NonDelegatingRelease()
{
if(InterlockedDecrement(&m_cRef) == 0) {
delete this;
return 0;
}
return m_cRef;
}
};
//////////////////////////////////////////////////////////////////////
// IClassFactory Interface Section (for all COM objects) //
//////////////////////////////////////////////////////////////////////
class CWIADeviceClassFactory : public IClassFactory {
public:
CWIADeviceClassFactory() : m_cRef(1) {}
~CWIADeviceClassFactory(){}
STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppv)
{
if (!ppv) {
return E_INVALIDARG;
}
*ppv = NULL;
HRESULT hr = E_NOINTERFACE;
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory)) {
*ppv = static_cast<IClassFactory*>(this);
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
hr = S_OK;
}
return hr;
}
STDMETHODIMP_(ULONG) AddRef()
{
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) Release()
{
if(InterlockedDecrement(&m_cRef) == 0) {
delete this;
return 0;
}
return m_cRef;
}
STDMETHODIMP CreateInstance(IUnknown __RPC_FAR *pUnkOuter,REFIID riid,void __RPC_FAR *__RPC_FAR *ppvObject)
{
if ((pUnkOuter)&&(!IsEqualIID(riid,IID_IUnknown))) {
return CLASS_E_NOAGGREGATION;
}
HRESULT hr = E_NOINTERFACE;
CWIADevice *pDev = new CWIADevice(pUnkOuter);
if (pDev) {
hr = pDev->NonDelegatingQueryInterface(riid,ppvObject);
pDev->NonDelegatingRelease();
} else {
hr = E_OUTOFMEMORY;
}
return hr;
}
STDMETHODIMP LockServer(BOOL fLock){return S_OK;}
private:
LONG m_cRef;
};
//////////////////////////////////////////////////////////////////////
// DLL Entry Point Section (for all COM objects, in a DLL) //
//////////////////////////////////////////////////////////////////////
extern "C" __declspec(dllexport) BOOL APIENTRY DllEntryPoint(HINSTANCE hinst,DWORD dwReason,LPVOID lpReserved)
{
switch (dwReason) {
case DLL_PROCESS_ATTACH:
break;
}
return TRUE;
}
extern "C" STDMETHODIMP DllCanUnloadNow(void){return S_OK;}
extern "C" STDAPI DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID *ppv)
{
if (!ppv) {
return E_INVALIDARG;
}
HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
if (IsEqualCLSID(rclsid, CLSID_HelloWorldWIADevice)) {
CWIADeviceClassFactory *pcf = new CWIADeviceClassFactory;
if (pcf) {
hr = pcf->QueryInterface(riid,ppv);
pcf->Release();
} else {
hr = E_OUTOFMEMORY;
}
}
return hr;
}