首先,請考慮改爲編寫v4打印驅動程序。儘管很快v3驅動程序支持不可能在任何時候下降,但v4驅動程序肯定是新開發的途徑。他們也有一個用於回調的.Net API,它可以避免必須自己編寫互操作。 See PrinterExtensionSample
.
實現一個COM接口沒有一個TLB
爲了實現IPrintAsyncNotifyCallback
和IPrintAsyncNotifyChannel
,它refereces的IPrintAsyncNotifyDataObject
接口,我們可以發現在prnasnot.h
它們的定義,轉載如下。
// ... snip ...
DEFINE_GUID(IID_IPrintAsyncNotifyChannel, 0x4a5031b1, 0x1f3f, 0x4db0, 0xa4, 0x62, 0x45, 0x30, 0xed, 0x8b, 0x04, 0x51);
DEFINE_GUID(IID_IPrintAsyncNotifyCallback, 0x7def34c1, 0x9d92, 0x4c99, 0xb3, 0xb3, 0xdb, 0x94, 0xa9, 0xd4, 0x19, 0x1b);
DEFINE_GUID(IID_IPrintAsyncNotifyDataObject, 0x77cf513e, 0x5d49, 0x4789, 0x9f, 0x30, 0xd0, 0x82, 0x2b, 0x33, 0x5c, 0x0d);
// ... snip ...
DECLARE_INTERFACE_(IPrintAsyncNotifyDataObject, IUnknown)
{
// ... snip ...
};
// ... snip ...
DECLARE_INTERFACE_(IPrintAsyncNotifyChannel, IUnknown)
{
// ... snip ...
};
// ... snip ...
DECLARE_INTERFACE_(IPrintAsyncNotifyCallback, IUnknown)
{
STDMETHOD(QueryInterface)(
THIS_
_In_ REFIID riid,
_Outptr_ void **ppvObj
) PURE;
STDMETHOD_(ULONG, AddRef)(
THIS
) PURE;
STDMETHOD_(ULONG, Release)(
THIS
) PURE;
STDMETHOD(OnEventNotify)(
THIS_
_In_ IPrintAsyncNotifyChannel *pChannel,
_In_ IPrintAsyncNotifyDataObject *pData
) PURE;
STDMETHOD(ChannelClosed)(
THIS_
_In_ IPrintAsyncNotifyChannel *pChannel,
_In_ IPrintAsyncNotifyDataObject *pData
) PURE;
};
的IID
s的頂部和方法排序和簽名允許我們translate these to the appropriate ComImport
s。
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("77cf513e-5d49-4789-9f30-d0822b335c0d")]
public interface IPrintAsyncNotifyDataObject
{
void AcquireData(out IntPtr data, out uint cbData, out IntPtr schema);
void ReleaseData();
}
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("4a5031b1-1f3f-4db0-a462-4530ed8b0451")]
public interface IPrintAsyncNotifyChannel
{
void SendNotification(IPrintAsyncNotifyDataObject data);
void CloseChannel(IPrintAsyncNotifyDataObject data);
}
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("7def34c1-9d92-4c99-b3b3-db94a9d4191b")]
public interface IPrintAsyncNotifyCallback
{
void OnEventNotify(IPrintAsyncNotifyChannel channel, IPrintAsyncNotifyDataObject data);
void ChannelClosed(IPrintAsyncNotifyChannel channel, IPrintAsyncNotifyDataObject data);
}
public enum PrintAsyncNotifyUserFilter : uint
{
kPerUser = 0,
kAllUsers = 1
}
public enum PrintAsyncNotifyConversationStyle : uint
{
kBiDirectional = 0,
kUniDirectional = 1
}
尋找RegisterForPrintAsyncNotifications
由於C++樣本作品原樣,並且RegisterForPrintAsyncNotifications
是進口–而非宏觀–鏈接器將着眼於WinSpool.lib
文件的文件名爲找到相應的DLL 。我們可以使用dumpbin
來做同樣的事情。
c:\Drop>dumpbin -headers "C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10586.0\um\x64\WinSpool.Lib" > out.txt
// ... snip ...
Version : 0
Machine : 8664 (x64)
TimeDateStamp: 56F9F510 Mon Mar 28 22:22:56 2016
SizeOfData : 00000030
DLL name : WINSPOOL.DRV
Symbol name : RegisterForPrintAsyncNotifications
Type : code
Name type : name
Hint : 162
Name : RegisterForPrintAsyncNotifications
// ... snip ...
這表明RegisterForPrintAsyncNotifications
實際上是從WINSPOOL.DRV
導出。
[DllImport("WINSPOOL.DRV", PreserveSig = false, ExactSpelling = true)]
public static extern void RegisterForPrintAsyncNotifications(
[MarshalAs(UnmanagedType.LPWStr)] string name,
[MarshalAs(UnmanagedType.LPStruct)] Guid notificationType, PrintAsyncNotifyUserFilter filter,
PrintAsyncNotifyConversationStyle converstationStyle,
IPrintAsyncNotifyCallback callback, out PrintAsyncNotificationSafeHandle handle);
[DllImport("WINSPOOL.DRV", PreserveSig = true, ExactSpelling = true)]
public static extern int UnRegisterForPrintAsyncNotifications(IntPtr handle);
public sealed class PrintAsyncNotificationSafeHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public PrintAsyncNotificationSafeHandle()
: base(true)
{
}
protected override bool ReleaseHandle()
{
return UnRegisterForPrintAsyncNotifications(handle) == 0 /* S_OK */;
}
}