"헬로 월드" WIA Minidriver UI 확장 만들기
WIA 미니 드라이버 UI 확장은 몇 가지 함수를 내보내고 다음 4개의 IID(COM 인터페이스 식별자) 중 하나 이상을 구현하는 간단한 DLL입니다.
IID_IWiaUIExtensionIWiaUIExtension 인터페이스의 IID (인터페이스 식별자)입니다. 이 인터페이스는 내 컴퓨터 및 제어판 미니 드라이버 디바이스 아이콘을 바꾸고 Microsoft 일반 미니 드라이버 UI 대화 상자를 바꾸는 데 사용되는 표준 WIA 인터페이스입니다.
IID_IShellExtInitIShellExtInit 인터페이스의 IID 입니다. 속성 시트, 바로 가기 메뉴 및 끌어서 놓기 처리기(기본값이 아닌 끌어서 놓기 작업 중에 바로 가기 메뉴에 항목을 추가하는 확장)에 대한 셸 확장을 초기화하는 데 사용되는 표준 Windows Shell 인터페이스입니다.
IID_IContextMenuContextMenu 인터페이스의 IID입니다. 셸 개체(내 컴퓨터 및 제어판 WIA 미니 드라이버 아이콘)와 연결된 바로 가기 메뉴를 만들거나 병합하는 데 사용되는 표준 Windows Shell 인터페이스입니다.
IID_IShellPropSheetIShellPropSheet 인터페이스의 IID입니다 . 셸 개체(내 컴퓨터 및 제어판 WIA 미니 드라이버 아이콘)에 대해 표시된 속성 시트의 페이지를 추가하거나 바꾸는 데 사용되는 표준 Windows Shell 인터페이스입니다.
"헬로 월드" WIA 미니드라이버 UI 확장은 다음 파일로 구성됩니다.
hellowld.inf 이 파일은 설치 파일입니다(원래 hellowld 샘플을 사용하여 이 UI 확장을 설치하도록 수정됨).
hellowldui.def 두 COM 내보내기 DllGetClassObject 및 DllCanUnloadNow 를 포함하는 정의 파일입니다(둘 다 Windows SDK 설명서에 설명되어 있음).
hellowldui.cpp WIA UI 확장 구현입니다.
WIA UI 확장 설치
WIA UI 확장 DLL을 설치하려면 DeviceData 섹션 아래의 INF 파일에 UI 확장>의 DLL의 UI 클래스 ID={<CLSID}를 추가합니다. 이 CLSID를 사용하면 클라이언트가 CoCreateInstance(Microsoft Windows SDK 설명서에 설명됨)를 호출하고 WIA UI 확장의 지원되는 인터페이스를 가져올 수 있습니다.
다음 예제 INF 코드 조각은 '헬로 월드' WIA Minidriver 만들기의 WIA 미니 드라이버 샘플에서 파생됩니다. 기본적으로 사용되는 CLSID는 일반적인 대화 상자, 아이콘 및 속성 페이지에 대해 Microsoft에서 제공하는 CLSID여야 합니다.
더 쉽게 설치할 수 있도록 모든 WIA UI 확장 DLL은 COM 개체를 자체 등록하는 것이 좋습니다. 이 샘플에는 자체 등록 COM 개체가 포함되어 있지 않습니다.
[WIADevice.DeviceData]
Server=local
UI DLL=sti.dll
UI Class ID={4DB1AD10-3391-11D2-9A33-00C04FA36145}
다음 샘플은 UI 클래스 ID 하위 키를 hellowldui 샘플 UI 확장의 CLSID로 설정하는 완전한 INF 파일입니다.
; HELLOWLD.INF -- Hello World WIA Minidriver setup file (with a WIA UI extension DLL)
; Copyright (c) 2002 Hello World Company
; Manufacturer: Hello World Company
[Version]
Signature="$WINDOWS NT$"
Class=Image
ClassGUID={6bdd1fc6-810f-11d0-bec7-08002be2092f}
Provider=%Mfg%
DriverVer=06/26/2001,1.0.0.0
CatalogFile=wia.cat
PnpLockdown=1
[DestinationDirs]
DefaultDestDir=13
[Manufacturer]
%Mfg%=Models,NTx86
[Models.NTx86]
%WIADevice.DeviceDesc% = WIADevice.Scanner, HELLOWORLD_PNP_ID
[WIADevice.Scanner]
Include=sti.inf
Needs=STI.SerialSection
SubClass=StillImage
DeviceType=1
DeviceSubType=0x0
Capabilities=0x30
DeviceData=WIADevice.DeviceData
AddReg=WIADevice.AddReg
CopyFiles=WIADevice.CopyFiles
ICMProfiles="sRGB Color Space Profile.icm"
[WIADevice.Scanner.Services]
Include=sti.inf
Needs=STI.SerialSection.Services
[WIADevice.DeviceData]
Server=local
UI DLL=sti.dll
UI Class ID={7C1E2309-A535-45b1-94B3-9A020EE600C7}
[WIADevice.AddReg]
HKR,,HardwareConfig,1,1
HKR,,USDClass,,"{7C1E2309-A535-45b1-94B3-9A020EE600C6}"
HKCR,CLSID\{7C1E2309-A535-45b1-94B3-9A020EE600C6},,,"Hello World WIA Minidriver"
HKCR,CLSID\{7C1E2309-A535-45b1-94B3-9A020EE600C6}\InProcServer32,,,%13%\hellowld.dll
HKCR,CLSID\{7C1E2309-A535-45b1-94B3-9A020EE600C6}\InProcServer32,ThreadingModel,,Both
HKCR,CLSID\{7C1E2309-A535-45b1-94B3-9A020EE600C7},,,"Hello World WIA Minidriver UI Extension"
HKCR,CLSID\{7C1E2309-A535-45b1-94B3-9A020EE600C7}\InProcServer32,,,%13%\hellowldui.dll
HKCR,CLSID\{7C1E2309-A535-45b1-94B3-9A020EE600C7}\InProcServer32,ThreadingModel,,Both
HKCR,CLSID\{7C1E2309-A535-45b1-94B3-9A020EE600C7}\shellex\WiaDialogExtensionHandlers\{7C1E2309-A535-45b1-94B3-9A020EE600C7}
[WIADevice.CopyFiles]
hellowld.dll
hellowldui.dll
[SourceDisksFiles.x86]
hellowld.dll=1
hellowldui.dll=1
[SourceDisksNames.x86]
1=%Location%,,,
[Strings]
Mfg="Hello World Company"
WIADevice.DeviceDesc="Hello World WIA Minidriver"
Location="Hello World WIA Minidriver Installation Source"
hellowldui.def 파일에는 다음 코드가 포함되어야 합니다.
LIBRARY HELLOWLDUI
EXPORTS
DllGetClassObject PRIVATE
DllCanUnloadNow PRIVATE
hellowldui.cpp 파일에는 다음 코드가 포함되어야 합니다.
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <initguid.h>
#include <wiadevd.h>
#include <shobjidl.h>
#include <shlobj.h>
// {7C1E2309-A535-45b1-94B3-9A020EE600C7}
DEFINE_GUID(CLSID_HelloWorldWIAUIExtension, 0x7c1e2309, 0xa535, 0x45b1, 0x94, 0xb3, 0x9a, 0x2, 0xe, 0xe6, 0x0, 0xc7);
class CWIAUIExtension : public IWiaUIExtension, // WIA UI Extension interface
public IShellExtInit, // SHELL Extension interface
public IContextMenu, // SHELL context menu Extension interface
public IShellPropSheetExt // SHELL property sheet interface
{
public:
/////////////////////////////////////////////////////////////////////////
// Construction/Destruction Section //
/////////////////////////////////////////////////////////////////////////
CWIAUIExtension() : m_cRef(1) {
}
~CWIAUIExtension() {
}
private:
LONG m_cRef; // object reference count.
public:
/////////////////////////////////////////////////////////////////////////
// Standard COM Section //
/////////////////////////////////////////////////////////////////////////
STDMETHODIMP QueryInterface(REFIID riid,LPVOID *ppvObj)
{
if (!ppvObj) {
return E_INVALIDARG;
}
*ppvObj = NULL;
if (IsEqualIID( riid, IID_IUnknown )) {
*ppvObj = reinterpret_cast<IUnknown*>(this);
} else if (IsEqualIID( riid, IID_IWiaUIExtension )) {
*ppvObj = static_cast<IWiaUIExtension*>(this);
} else {
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(*ppvObj)->AddRef();
return S_OK;
}
STDMETHODIMP_(ULONG) AddRef()
{
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) Release()
{
if(InterlockedDecrement(&m_cRef) == 0) {
delete this;
return 0;
}
return m_cRef;
}
/////////////////////////////////////////////////////////////////////////
// IWiaUIExtension Interface Section //
/////////////////////////////////////////////////////////////////////////
STDMETHODIMP DeviceDialog( PDEVICEDIALOGDATA pDeviceDialogData ) {return E_NOTIMPL;}
STDMETHODIMP GetDeviceIcon( BSTR bstrDeviceId, HICON *phIcon, ULONG nSize ){
HRESULT hr = E_NOTIMPL;
HICON hIcon = reinterpret_cast<HICON>(LoadImage(NULL,
MAKEINTRESOURCE(IDI_APPLICATION),
IMAGE_ICON,
nSize,
nSize,
LR_SHARED));
if (hIcon) {
*phIcon = CopyIcon(hIcon);
hIcon = NULL;
hr = S_OK;
}
return hr;
}
STDMETHODIMP GetDeviceBitmapLogo( BSTR bstrDeviceId, HBITMAP *phBitmap, ULONG nMaxWidth, ULONG nMaxHeight ){return E_NOTIMPL;}
/////////////////////////////////////////////////////////////////////////
// IShellExtInit Interface Section //
/////////////////////////////////////////////////////////////////////////
STDMETHODIMP Initialize (LPCITEMIDLIST pidlFolder,LPDATAOBJECT lpdobj,HKEY hkeyProgID){return E_NOTIMPL;}
/////////////////////////////////////////////////////////////////////////
// IContextMenu Interface Section //
/////////////////////////////////////////////////////////////////////////
STDMETHODIMP QueryContextMenu (HMENU hmenu,UINT indexMenu,UINT idCmdFirst,UINT idCmdLast,UINT uFlags) {return E_NOTIMPL;}
STDMETHODIMP InvokeCommand (LPCMINVOKECOMMANDINFO lpici){return E_NOTIMPL;}
STDMETHODIMP GetCommandString (UINT_PTR idCmd, UINT uType,UINT* pwReserved,LPSTR pszName,UINT cchMax) {return E_NOTIMPL;}
/////////////////////////////////////////////////////////////////////////
// IShellPropSheetExt Interface Section //
/////////////////////////////////////////////////////////////////////////
STDMETHODIMP AddPages (LPFNADDPROPSHEETPAGE lpfnAddPage,LPARAM lParam){return E_NOTIMPL;}
STDMETHODIMP ReplacePage (UINT uPageID,LPFNADDPROPSHEETPAGE lpfnReplacePage,LPARAM lParam) {return E_NOTIMPL;}
};
/////////////////////////////////////////////////////////////////////////
// IClassFactory Interface Section (for all COM objects) //
/////////////////////////////////////////////////////////////////////////
class CWIAUIClassFactory : public IClassFactory {
public:
CWIAUIClassFactory() : m_cRef(1) {}
~CWIAUIClassFactory(){}
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;
CWIAUIExtension *pUIExt = new CWIAUIExtension();
if (pUIExt) {
hr = pUIExt->QueryInterface(riid,ppvObject);
pUIExt->Release();
} 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_HelloWorldWIAUIExtension)) {
CWIAUIClassFactory *pcf = new CWIAUIClassFactory;
if (pcf) {
hr = pcf->QueryInterface(riid,ppv);
pcf->Release();
} else {
hr = E_OUTOFMEMORY;
}
}
return hr;
}
사용자 지정 디바이스 아이콘 추가
앞의 샘플은 디바이스의 기본 아이콘을 바꾸는 방법의 예입니다. 기본 아이콘을 바꾸는 것은 둘 이상의 디바이스가 설치된 경우 사용자가 올바른 디바이스를 사용하도록 안내하는 이상적인 방법이 될 수 있습니다. 아이콘이 연결된 디바이스와 유사한 경우 사용자에게 더 직관적입니다.