2016-11-06 73 views
0

我試圖從v3打印機驅動程序或端口監視器接收回調,但想從C#中執行此操作。 The docs say that we should be able to just pass一個實現IPrintAsyncNotifyCallbackRegisterForPrintAsyncNotifications的對象,並且在C++中有一個示例,但我找不到能夠在C#中實現此接口的TLB。我該如何註冊C#中的`IPrintAsyncNotifyCallback`#

另外,RegisterForPrintAsyncNotifications似乎不是從文檔(Spoolss.dll)中指定的dll導出的。

如何在沒有TLB的情況下實現IPrintAsyncNotifyCallback?我如何找到RegisterForPrintAsyncNotifications

回答

2

首先,請考慮改爲編寫v4打印驅動程序。儘管很快v3驅動程序支持不可能在任何時候下降,但v4驅動程序肯定是新開發的途徑。他們也有一個用於回調的.Net API,它可以避免必須自己編寫互操作。 See PrinterExtensionSample.

實現一個COM接口沒有一個TLB

爲了實現IPrintAsyncNotifyCallbackIPrintAsyncNotifyChannel,它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 ComImports

[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 */; 
    } 
} 
相關問題