仮想プリンタヌの実装䟋を䜿甚しおCで印刷デバむスを操䜜する

すべおにご挚拶。 今日の蚘事では、システムに新しい印刷モニタ​​ヌをむンストヌルするこずから、プリンタヌポヌトからプリンタヌデバむスドラむバヌによっお凊理されたドキュメントを受信するたで、印刷デバむスを操䜜するマネヌゞコヌドで独自の高レベルAPIを実装する方法に぀いお説明したす。



前回ず同様に、この蚘事は、ゞュニアおよびミドルマネゞメントの開発者ず知り合うのに圹立ちたす。 玠材を孊習するプロセスでは、 P / Invokeを䜿甚しおCで䜎レベルWinAPI DLLにアクセスする方法、印刷モニタ​​ヌ、プリンタヌドラむバヌ、システムから印刷デバむスをむンストヌル、構成、削陀する方法、デバむスから入力をリダむレクトするポヌトを開いおリンクする方法を孊習したすモニタヌに印刷しお、 マヌシャリングを適甚する重芁なポむントを理解したす。 たた、APIを䜿甚しおシステム内の印刷デバむスを䟿利に操䜜するためのAPIの䜿甚方法、プリンタヌからの印刷埌に凊理されたデヌタをむンタヌセプトする方法、およびそれらをサヌバヌに送信する方法を把握したす。



問題の声明



最初に、この蚘事で解決する必芁があるタスクのおおよそのリストの抂芁を提案したす。 次のようにしたす。





この蚘事のフレヌムワヌクでは、むタリアの開発者Lorenzo Montiによっお既に実装されおいるmfilemon.dll印刷モニタ​​ヌを䜿甚し、公匏のMicrosoft PostScriptプリンタヌドラむバヌをプリンタヌドラむバヌずしお䜿甚したす 。 実際、モニタヌの芁件ずタスクに応じお、モニタヌずドラむバヌはどれでもかたいたせん。



理論のビット



この蚘事では、ドキュメントを印刷するための理論的基瀎、PCL / PostScriptサポヌト付きプリンタヌずGDIプリンタヌおよびその他のベヌスの違いに぀いおは怜蚎したせん。 このトピックに関する必芁な情報はすべお、ネットワヌクのオヌプンスペヌスに豊富にありたす。 しかし、私たちのために蚭定されたタスクをどのように実珟するかをよりよく理解するには、ただ䜕かを知る必芁がありたす。



最も重芁なこずから始めたしょう-スプヌラヌサヌビスは、Windowsの印刷プロセスを制埡したす。 C/ Windows / System32 /ディレクトリには独自の䜎レベルドラむバwinspool.drvがありたす。これには、印刷サヌビスのシステムディレクトリずシステム内のデフォルトプリンタの名前の取埗から、印刷サヌビスにアクセスし、倚くのアクションを実行するための倚くの゚ントリポむントが含たれおいたす印刷ゞョブキュヌを䜿甚した操䜜。 winspool.hに加えお、独自のモニタヌおそらく、今埌の蚘事のいずれかで説明するを䜜成する堎合は、DDKのwinsplp.hも必芁です。これは、スプヌラヌ仕様に埓っおドラむバヌを構築するための远加機胜を提䟛したす。 。



さらに、Windowsのフル機胜の印刷デバむスは、簡単に蚀えば、モニタヌポヌトで開いおいる印刷モニタ​​ヌ、実際の印刷デバむスプリンタヌ、およびそのためのプリむンストヌルされたドラむバヌで構成されおいたす図1。 1぀のモニタヌで耇数のポヌトを䞀床に開くこずができ、耇数のプリンタヌを1぀のポヌトに䞀床に接続できたす。 これは、システムからコンポヌネントを削陀するずきに考慮する必芁がありたす。たずえば、特定のポヌトを削陀する堎合、最初にそれに接続されおいるすべおの印刷デバむスを砎棄する必芁がありたす。



図1



P /呌び出す



プラットフォヌム呌び出しサヌビスPInvokeは、マネヌゞコヌドC/ VBおよび.NETからアンマネヌゞコヌドC / C ++およびWinAPIで蚘述されたDLL゚ントリポむント関数にアクセスするためのプラットフォヌムです。 .NETから䜎レベルコヌドにアクセスするには、DLLの倖郚メ゜ッドず、それらで䜿甚される構造を蚘述する必芁がありたす。 各枝を䟋ごずに順番に怜蚎したす。



䟋1 winspool.drvドラむバヌからGetPrinterDriverDirectoryメ゜ッドを呌び出したす。

たず、メ゜ッドが返すものず、呌び出されたずきに匕数に䜕が必芁かを知る必芁がありたす。 これを行うには、 ドキュメントに移動し、メ゜ッドシグネチャの説明を読みたす。 将来的には、䜎レベルAPIのドキュメントを垞に参照する必芁があるこずに泚意しおください。これ以降、特定のメ゜ッド/構造を実装するずきにこのアクションの必芁性を瀺すこずはありたせん。 これらはデフォルトで必芁です。



BOOL GetPrinterDriverDirectory( _In_ LPTSTR pName, _In_ LPTSTR pEnvironment, _In_ DWORD Level, _Out_ LPBYTE pDriverDirectory, _In_ DWORD cbBuf, _Out_ LPDWORD pcbNeeded );
      
      





各関数パラメヌタの説明は、ドキュメントにも蚘茉されおいたす。 パラメヌタヌは入力のみIn、出力のみOut、入力ず出力の䞡方を同時にIn / Out、オプション他のパラメヌタヌに応じお入力たたは出力のいずれかにできるこずを理解するこずが重芁です。 たた、 WDT型にマッピングする必芁がある.NETのデヌタ型を知る必芁がありたすここでは、ほずんどの堎合、「重芁な.NET型に割り圓おられたメモリのサむズは、基本的なC ++型に割り圓おられたメモリのサむズに察応し、残りはIntPtrになりたす 」。



次に、受け取った情報に基づいお、Cのマネヌゞコヌドでメ゜ッドを説明したす。



 [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] extern bool GetPrinterDriverDirectory(string serverName, string environment, uint level, [Out] StringBuilder driverDirectory, uint bufferSize, ref uint bytesNeeded);
      
      





DllImportAttribute属性を䜿甚するず、䜎レベルの゚ントリポむントにアクセスするためのパラメヌタヌを指定できたす。 WinAPIでは、ほずんどの関数はUnicodeずANSIの2぀の䞻芁な゚ンコヌディングを考慮しお蚘述されおいたす。関数の末尟はそれぞれWずAです。 ゚ンコヌドで特定のメ゜ッドを参照する必芁があるが、説明したメ゜ッドのメむン名をリファクタリングしたくない堎合は、察応する属性匕数たずえば、GetPrinterDriverDirectoryWに枡すこずで゚ントリポむントの名前を明瀺的に指定できたす。 たた、匕数CharSet = CharSet.Unicodeを指定するこずを忘れないでくださいこの堎合、゚ンコヌドは自動的に決定されたす。 他のすべおの有甚な属性に぀いおは、 公匏ドキュメントで情報を芋぀けるこずができたす。



ほずんどの堎合、 InAttribute属性は省略できたす。 Cメ゜ッドの匕数は、デフォルトで倀によっお枡されたす。 枡された匕数の型が参照であるが、デヌタを出力する必芁がある堎合に、 OutAttribute属性を指定したす。 有効な型の匕数の出力には、 refを指定したす。 匕数を参照枡ししたす。



䟋2 winspool.drvドラむバヌからAddMonitorメ゜ッドを呌び出したす。



この䟋では、 MONITOR_INFO_2デヌタ構造を䜿甚したす。最初にCコヌドで説明する必芁がありたす。



 typedef struct _MONITOR_INFO_2 { LPTSTR pName; LPTSTR pEnvironment; LPTSTR pDLLName; } MONITOR_INFO_2, *PMONITOR_INFO_2; BOOL AddMonitor( _In_ LPTSTR pName, _In_ DWORD Level, _In_ LPBYTE pMonitors );
      
      





ここで、「フォヌク」蚀語を話す構造は、倀を栌玍する特定のサむズの割り圓おられたメモリセクションのセットであるこずを理解するこずが重芁です。 これらの各セクションは、特定のタむプのデヌタフィヌルドを衚したす。 フィヌルド名ずその属性、可倉型クラスに固有のメタデヌタ、デヌタストレヌゞに割り圓おられたメモリのサむズに぀いおは説明しおいたせん。 これは、構造䜓の名前だけでなく、構造䜓の名前も任意であり、割り圓おられたメモリサむズず各メンバヌの察応を芳察するこずが重芁であるこずを意味したす。 このような目的のために、メモリ内のクラスたたは構造のデヌタフィヌルドの物理的な配眮を制埡できるStructLayoutAttribute属性がありたす。 メモリ内のこれらのフィヌルドの配眮を制埡する方法は倚数ありたす。フィヌルドのオフセットを明瀺的に蚭定し、構造の絶察サむズを指定し、マヌシャリング方法の゚ンコヌディングを指定し、パッケヌゞ化し、フィヌルドセグメントを連続した順に配眮するこずなどができたす。 ここでこれらのメ゜ッドの実装の䟋を芋぀けるこずができたす 。 具䜓的には、LayoutKind.Sequentialを䜿甚しお指定する最埌のメ゜ッドは、タスクに最適です。



 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] struct MonitorInfo { [MarshalAs(UnmanagedType.LPTStr)] public string Name; [MarshalAs(UnmanagedType.LPTStr)] public string Environment; [MarshalAs(UnmanagedType.LPTStr)] public string DllName; } [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] static extern bool AddMonitor(string serverName, uint level, ref MonitorInfo monitor);
      
      





仕組み構造䜓を宣蚀し、属性でLayoutKind.Sequentialを䜿甚しおメモリ内のフィヌルドの配眮を指定し、フィヌルドデヌタ型を指定したした。WinAPIの堎合、構造䜓のデヌタ型は重芁です。぀たり、アンマネヌゞコヌドではsizeofです 。管理察象-Marshal.SizeOfで 。 それだけです



マヌシャリング



「マヌシャリング」別名「マヌシャリング」、別名「マヌシャリング」の抂念は、メモリに保存されたデヌタをある衚珟から別の衚珟に倉換するプロセスを説明したす。 䞀般的な.NETの堎合、特にP / Invokeの堎合、アンマネヌゞコヌドからCLRぞの型倉換です。 マヌシャリングにより、マネヌゞコヌドでメモリを操䜜しやすくなりたす。 これらの目的のために、2぀の䞻芁なクラス、 MarshalずMarshalAsAttributeが提䟛されおいたす。 MarshalAsAttribute属性を䜿甚するず、アンマネヌゞコヌドからマネヌゞコヌドぞの倉換の型䞀臎を明瀺的に蚭定できたす 型のシリアル化䞭のマッピングず同様。 これは、タむプフィヌルド、 paramを介した指定を持぀メ゜ッドパラメヌタヌ、およびreturnを介した戻り倀にのみ適甚できたす。 Marshalクラスには、ポむンタヌの操䜜、メモリの割り圓お、サむズ倉曎、シフトなどのための倚くの䟿利な静的メ゜ッドが含たれおいたす。 たた、 FlagsAttribute属性は圹に立ちたす。これにより、䜎レベルのビットフラグからenumのCぞの倉換を構成できたす。



将来のAPIアヌキテクチャ



理論が敎理されたら、将来のAPIのアヌキテクチャを怜蚎するずきが来たした。 特定の哲孊や最適な哲孊はありたせん。誰もが解決する問題の状態に応じお、コヌド蚭蚈の必芁なパタヌンを遞択したす。 今回のケヌスでは、次のこずを行うこずにしたした。将来のラむブラリのすべおのコヌドは、2぀の䞻芁なモゞュヌルで構成されたす-クラスの「ファクトリヌ」ずこれらのクラスを実装するむンタヌフェヌスです。 パブリック実装により、システムにむンストヌルされおいるすべおのコンポヌネントのリストの取埗、コンポヌネントのむンストヌル/アンむンストヌルなどが可胜になりたす。 内郚実装は、マヌシャリングずP / Invokeで機胜したす。 特定のケヌスに぀いおは、クラスのむンスタンスを䜜成し、それらのメ゜ッドを呌び出すこずができたす。基本的なケヌスに぀いおは、「工堎」に連絡したす。 芖芚的には、これはすべお次のように衚すこずができたす図2。







この蚘事のフレヌムワヌク内で問題を解決するには、IMonitor、IPort、IDriver、IPrinterの実装、PrintingApiファクトリクラス自䜓、および補助フラグが必芁です。 残りは今のずころ省略されおいたす。



コヌドベヌス



たず、すべおの印刷コンポヌネントの基本的なむンタヌフェヌスを䜜成したしょう。



 /// <summary> ///      ,    ( ,  , ). /// </summary> public interface IPrintableDevice { /// <summary> ///   . /// </summary> string Name { get; } /// <summary> ///      . /// </summary> /// <param name="serverName"> .</param> void Install(string serverName); /// <summary> ///      . /// </summary> /// <param name="serverName"> .</param> void Uninstall(string serverName); }
      
      





ここではすべおが単玔です。各コンポヌネントには、システムにむンストヌル/アンむンストヌルするための名前ず2぀の方法があり、リモヌトマシンで䜜業するこずができたす。



次に、工堎の基瀎を蚘述したす。



クラスPrintingApi
 /// <summary> ///  API     . /// </summary> public class PrintingApi { /// <summary> ///       P/Invoke. /// </summary> /// <param name="serverName"> .</param> /// <param name="level">  .</param> /// <param name="structs">   .</param> /// <param name="bufferSize"> .</param> /// <param name="bytesNeeded">     .</param> /// <param name="bufferReturnedLength">   .</param> /// <returns></returns> internal delegate bool EnumInfo(string serverName, uint level, IntPtr structs, uint bufferSize, ref uint bytesNeeded, ref uint bufferReturnedLength); /// <summary> ///       P/Invoke. /// </summary> /// <param name="serverName"> .</param> /// <param name="environment">.</param> /// <param name="level">  .</param> /// <param name="structs">   .</param> /// <param name="bufferSize"> .</param> /// <param name="bytesNeeded">     .</param> /// <param name="bufferReturnedLength">   .</param> /// <returns></returns> internal delegate bool EnumInfo2(string serverName, string environment, uint level, IntPtr structs, uint bufferSize, ref uint bytesNeeded, ref uint bufferReturnedLength); /// <summary> ///    <see cref="PrintingApi"/>. /// </summary> public static PrintingApi Factory { get; protected set; } /// <summary> ///    <see cref="PrintingApi"/>. /// </summary> static PrintingApi() { Factory = new PrintingApi(); } /// <summary> ///     Spooler API.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="serverName"> .</param> /// <param name="level"> .</param> /// <returns>   Spooler API.</returns> internal static T[] GetInfo<T>(EnumInfo handler, string serverName, uint level) where T : struct { uint bytesNeeded = 0; uint bufferReturnedLength = 0; if (handler(serverName, level, IntPtr.Zero, 0, ref bytesNeeded, ref bufferReturnedLength)) return null; int lastWin32Error = Marshal.GetLastWin32Error(); if (lastWin32Error != PrintingException.ErrorInsufficientBuffer) throw new PrintingException(lastWin32Error); IntPtr pointer = Marshal.AllocHGlobal((int)bytesNeeded); try { if (handler(serverName, level, pointer, bytesNeeded, ref bytesNeeded, ref bufferReturnedLength)) { IntPtr currentPointer = pointer; T[] dataCollection = new T[bufferReturnedLength]; Type type = typeof(T); for (int i = 0; i < bufferReturnedLength; i++) { dataCollection[i] = (T)Marshal.PtrToStructure(currentPointer, type); currentPointer = (IntPtr)(currentPointer.ToInt64() + Marshal.SizeOf(type)); } return dataCollection; } throw new PrintingException(Marshal.GetLastWin32Error()); } catch (Exception e) { throw new PrintingException(e.Message, e); } finally { Marshal.FreeHGlobal(pointer); } } /// <summary> ///     Spooler API.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="serverName"> .</param> /// <returns>   Spooler API.</returns> internal static T[] GetInfo<T>(EnumInfo handler, string serverName) where T : struct => GetInfo<T>(handler, serverName, 2); /// <summary> ///     Spooler API.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="level"> .</param> /// <returns>   Spooler API.</returns> internal static T[] GetInfo<T>(EnumInfo handler, uint level) where T : struct => GetInfo<T>(handler, null, level); /// <summary> ///     Spooler API.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <returns>   Spooler API.</returns> internal static T[] GetInfo<T>(EnumInfo handler) where T : struct => GetInfo<T>(handler, null); /// <summary> ///     Spooler API.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="serverName"> .</param> /// <param name="arg">  .</param> /// <param name="level"> .</param> /// <returns>   Spooler API.</returns> internal static T[] GetInfo<T>(EnumInfo2 handler, string serverName, string arg, uint level) where T : struct { uint bytesNeeded = 0; uint bufferReturnedLength = 0; if (handler(serverName, arg, level, IntPtr.Zero, 0, ref bytesNeeded, ref bufferReturnedLength)) return null; int lastWin32Error = Marshal.GetLastWin32Error(); if (lastWin32Error != PrintingException.ErrorInsufficientBuffer) throw new PrintingException(lastWin32Error); IntPtr pointer = Marshal.AllocHGlobal((int)bytesNeeded); try { if (handler(serverName, arg, level, pointer, bytesNeeded, ref bytesNeeded, ref bufferReturnedLength)) { IntPtr currentPointer = pointer; T[] dataCollection = new T[bufferReturnedLength]; Type type = typeof(T); for (int i = 0; i < bufferReturnedLength; i++) { dataCollection[i] = (T)Marshal.PtrToStructure(currentPointer, type); currentPointer = (IntPtr)(currentPointer.ToInt64() + Marshal.SizeOf(type)); } return dataCollection; } throw new PrintingException(Marshal.GetLastWin32Error()); } catch (Exception e) { throw new PrintingException(e.Message, e); } finally { Marshal.FreeHGlobal(pointer); } } /// <summary> ///     Spooler API.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="serverName"> .</param> /// <param name="arg">  .</param> /// <returns>   Spooler API.</returns> internal static T[] GetInfo<T>(EnumInfo2 handler, string serverName, string arg) where T : struct => GetInfo<T>(handler, serverName, arg, 2); /// <summary> ///     Spooler API.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="arg">  .</param> /// <param name="level"> .</param> /// <returns>   Spooler API.</returns> internal static T[] GetInfo<T>(EnumInfo2 handler, string arg, uint level) where T : struct => GetInfo<T>(handler, null, arg, level); /// <summary> ///     Spooler API.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="arg">  .</param> /// <returns>   Spooler API.</returns> internal static T[] GetInfo<T>(EnumInfo2 handler, string arg) where T : struct => GetInfo<T>(handler, null, arg); /// <summary> ///     Spooler API.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="level"> .</param> /// <returns>   Spooler API.</returns> internal static T[] GetInfo<T>(EnumInfo2 handler, uint level) where T : struct => GetInfo<T>(handler, null, level); /// <summary> ///     Spooler API.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <returns>   Spooler API.</returns> internal static T[] GetInfo<T>(EnumInfo2 handler) where T : struct => GetInfo<T>(handler, null); /// <summary> ///     Spooler API      True.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="serverName"> .</param> /// <param name="level"> .</param> /// <param name="dataCollection">   Spooler API.</param> /// <param name="e">,    .</param> /// <returns>True,    ,  False.</returns> internal static bool TryGetInfo<T>(EnumInfo handler, string serverName, uint level, out T[] dataCollection, out PrintingException e) where T : struct { dataCollection = null; e = null; try { dataCollection = GetInfo<T>(handler, serverName, level); return true; } catch (PrintingException ex) { e = ex; } return false; } /// <summary> ///     Spooler API      True.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="serverName"> .</param> /// <param name="level"> .</param> /// <param name="dataCollection">   Spooler API.</param> /// <returns>True,    ,  False.</returns> internal static bool TryGetInfo<T>(EnumInfo handler, string serverName, uint level, out T[] dataCollection) where T : struct => TryGetInfo(handler, serverName, level, out dataCollection, out PrintingException e); /// <summary> ///     Spooler API      True.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="serverName"> .</param> /// <param name="dataCollection">   Spooler API.</param> /// <param name="e">,    .</param> /// <returns>True,    ,  False.</returns> internal static bool TryGetInfo<T>(EnumInfo handler, string serverName, out T[] dataCollection, out PrintingException e) where T : struct => TryGetInfo(handler, serverName, 2, out dataCollection, out e); /// <summary> ///     Spooler API      True.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="serverName"> .</param> /// <param name="dataCollection">   Spooler API.</param> /// <returns>True,    ,  False.</returns> internal static bool TryGetInfo<T>(EnumInfo handler, string serverName, out T[] dataCollection) where T : struct => TryGetInfo(handler, serverName, 2, out dataCollection, out PrintingException e); /// <summary> ///     Spooler API      True.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="level"> .</param> /// <param name="dataCollection">   Spooler API.</param> /// <param name="e">,    .</param> /// <returns>True,    ,  False.</returns> internal static bool TryGetInfo<T>(EnumInfo handler, uint level, out T[] dataCollection, out PrintingException e) where T : struct => TryGetInfo(handler, null, level, out dataCollection, out e); /// <summary> ///     Spooler API      True.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="level"> .</param> /// <param name="dataCollection">   Spooler API.</param> /// <returns>True,    ,  False.</returns> internal static bool TryGetInfo<T>(EnumInfo handler, uint level, out T[] dataCollection) where T : struct => TryGetInfo(handler, null, level, out dataCollection, out PrintingException e); /// <summary> ///     Spooler API      True.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="dataCollection">   Spooler API.</param> /// <param name="e">,    .</param> /// <returns>True,    ,  False.</returns> internal static bool TryGetInfo<T>(EnumInfo handler, out T[] dataCollection, out PrintingException e) where T : struct => TryGetInfo(handler, null, out dataCollection, out e); /// <summary> ///     Spooler API      True.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="dataCollection">   Spooler API.</param> /// <returns>True,    ,  False.</returns> internal static bool TryGetInfo<T>(EnumInfo handler, out T[] dataCollection) where T : struct => TryGetInfo(handler, null, out dataCollection, out PrintingException e); /// <summary> ///     Spooler API      True.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="serverName"> .</param> /// <param name="arg">  .</param> /// <param name="level"> .</param> /// <param name="dataCollection">   Spooler API.</param> /// <param name="e">,    .</param> /// <returns>True,    ,  False.</returns> internal static bool TryGetInfo<T>(EnumInfo2 handler, string serverName, string arg, uint level, out T[] dataCollection, out PrintingException e) where T : struct { dataCollection = null; e = null; try { dataCollection = GetInfo<T>(handler, serverName, arg, level); return true; } catch (PrintingException ex) { e = ex; } return false; } /// <summary> ///     Spooler API      True.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="serverName"> .</param> /// <param name="arg">  .</param> /// <param name="level"> .</param> /// <param name="dataCollection">   Spooler API.</param> /// <returns>True,    ,  False.</returns> internal static bool TryGetInfo<T>(EnumInfo2 handler, string serverName, string arg, uint level, out T[] dataCollection) where T : struct => TryGetInfo(handler, serverName, arg, level, out dataCollection, out PrintingException e); /// <summary> ///     Spooler API      True.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="serverName"> .</param> /// <param name="arg">  .</param> /// <param name="dataCollection">   Spooler API.</param> /// <param name="e">,    .</param> /// <returns>True,    ,  False.</returns> internal static bool TryGetInfo<T>(EnumInfo2 handler, string serverName, string arg, out T[] dataCollection, out PrintingException e) where T : struct => TryGetInfo(handler, serverName, arg, 2, out dataCollection, out e); /// <summary> ///     Spooler API      True.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="serverName"> .</param> /// <param name="arg">  .</param> /// <param name="dataCollection">   Spooler API.</param> /// <returns>True,    ,  False.</returns> internal static bool TryGetInfo<T>(EnumInfo2 handler, string serverName, string arg, out T[] dataCollection) where T : struct => TryGetInfo(handler, serverName, arg, 2, out dataCollection, out PrintingException e); /// <summary> ///     Spooler API      True.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="arg">  .</param> /// <param name="level"> .</param> /// <param name="dataCollection">   Spooler API.</param> /// <param name="e">,    .</param> /// <returns>True,    ,  False.</returns> internal static bool TryGetInfo<T>(EnumInfo2 handler, string arg, uint level, out T[] dataCollection, out PrintingException e) where T : struct => TryGetInfo(handler, null, arg, level, out dataCollection, out e); /// <summary> ///     Spooler API      True.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="arg">  .</param> /// <param name="level"> .</param> /// <param name="dataCollection">   Spooler API.</param> /// <returns>True,    ,  False.</returns> internal static bool TryGetInfo<T>(EnumInfo2 handler, string arg, uint level, out T[] dataCollection) where T : struct => TryGetInfo(handler, null, arg, level, out dataCollection, out PrintingException e); /// <summary> ///     Spooler API      True.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="arg">  .</param> /// <param name="dataCollection">   Spooler API.</param> /// <param name="e">,    .</param> /// <returns>True,    ,  False.</returns> internal static bool TryGetInfo<T>(EnumInfo2 handler, string arg, out T[] dataCollection, out PrintingException e) where T : struct => TryGetInfo(handler, null, arg, out dataCollection, out e); /// <summary> ///     Spooler API      True.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="arg">  .</param> /// <param name="dataCollection">   Spooler API.</param> /// <returns>True,    ,  False.</returns> internal static bool TryGetInfo<T>(EnumInfo2 handler, string arg, out T[] dataCollection) where T : struct => TryGetInfo(handler, null, arg, out dataCollection, out PrintingException e); /// <summary> ///     Spooler API      True.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="level"> .</param> /// <param name="dataCollection">   Spooler API.</param> /// <param name="e">,    .</param> /// <returns>True,    ,  False.</returns> internal static bool TryGetInfo<T>(EnumInfo2 handler, uint level, out T[] dataCollection, out PrintingException e) where T : struct => TryGetInfo(handler, null, level, out dataCollection, out e); /// <summary> ///     Spooler API      True.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="level"> .</param> /// <param name="dataCollection">   Spooler API.</param> /// <returns>True,    ,  False.</returns> internal static bool TryGetInfo<T>(EnumInfo2 handler, uint level, out T[] dataCollection) where T : struct => TryGetInfo(handler, null, level, out dataCollection, out PrintingException e); /// <summary> ///     Spooler API      True.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="dataCollection">   Spooler API.</param> /// <param name="e">,    .</param> /// <returns>True,    ,  False.</returns> internal static bool TryGetInfo<T>(EnumInfo2 handler, out T[] dataCollection, out PrintingException e) where T : struct => TryGetInfo(handler, null, out dataCollection, out e); /// <summary> ///     Spooler API      True.       P/Invoke. /// </summary> /// <typeparam name="T"> .</typeparam> /// <param name="handler">-    Spooler API.</param> /// <param name="dataCollection">   Spooler API.</param> /// <returns>True,    ,  False.</returns> internal static bool TryGetInfo<T>(EnumInfo2 handler, out T[] dataCollection) where T : struct => TryGetInfo(handler, null, out dataCollection, out PrintingException e); }
      
      







文曞化されたコメントから、䜕が䜕であるかは明らかだず思いたす。singleton を䜿甚しお、静的コンストラクタヌでクラスの新しい静的むンスタンスを䜜成し、EnumInfoおよびEnumInfo2の 2぀のデリゲヌトを蚘述しお、将来のクラスでデヌタを受け取るためのネむティブメ゜ッドを呌び出し、ネむティブメ゜ッドでヘルパヌメ゜ッドを蚘述したす。



ほずんどの堎合、ネむティブメ゜ッドを操䜜するプロセス党䜓は、次の䞀連のアクションに削枛されたす。





char **バッファヌ文字列配列を操䜜するには、StringBuilderを䜿甚するこずをお勧めしたす。ポむンタヌで動䜜する既補のオヌバヌロヌドがあり、マヌシャリングに必芁なすべおの機胜も実装しおいたす。



䟋倖をキャッチしおスロヌするために、APIに別のクラスを提䟛したす。



クラスPrintingException
 /// <summary> ///    . /// </summary> [Serializable] public class PrintingException : Win32Exception { #region Error Codes /// <summary> ///   "  ". /// </summary> public const int ErrorFileNotFound = 2; /// <summary> ///   " ". /// </summary> public const int ErrorInsufficientBuffer = 122; /// <summary> ///   "  ". /// </summary> public const int ErrorModuleNotFound = 126; /// <summary> ///   "   ". /// </summary> public const int ErrorInvalidPrinterName = 1801; /// <summary> ///   "   ". /// </summary> public const int ErrorMonitorUnknown = 3000; /// <summary> ///   "   ". /// </summary> public const int ErrorPrinterDriverIsReadyUsed = 3001; /// <summary> ///   "    ". /// </summary> public const int ErrorPrinterJobFileNotFound = 3002; /// <summary> ///   "    StartDocPrinter". /// </summary> public const int ErrorStartDocPrinterNotCalling = 3003; /// <summary> ///   "    AddJob". /// </summary> public const int ErrorAddJobNotCalling = 3004; /// <summary> ///   "    ". /// </summary> public const int ErrorPrinterProcessorAlreadyInstalled = 3005; /// <summary> ///   "    ". /// </summary> public const int ErrorMonitorAlreadyInstalled = 3006; /// <summary> ///   "      ". /// </summary> public const int ErrorInvalidMonitor = 3007; /// <summary> ///   "     ". /// </summary> public const int ErrorMonitorIsReadyUsed = 3008; #endregion /// <summary> ///     <see cref="PrintingException"/>. /// </summary> public PrintingException() : base() { } /// <summary> ///     <see cref="PrintingException"/>. /// </summary> /// <param name="nativeErrorCode">  Win32.</param> public PrintingException(int nativeErrorCode) : base(nativeErrorCode) { } /// <summary> ///     <see cref="PrintingException"/>. /// </summary> /// <param name="message">  .</param> public PrintingException(string message) : base(message) { } /// <summary> ///     <see cref="PrintingException"/>. /// </summary> /// <param name="nativeErrorCode">  Win32.</param> /// <param name="message">  .</param> public PrintingException(int nativeErrorCode, string message) : base(nativeErrorCode, message) { } /// <summary> ///     <see cref="PrintingException"/>. /// </summary> /// <param name="message">  .</param> /// <param name="innerException"></param> public PrintingException(string message, Exception innerException) : base(message, innerException) { } /// <summary> ///     <see cref="PrintingException"/>. /// </summary> /// <param name="info">  .</param> /// <param name="context">  .</param> public PrintingException(SerializationInfo info, StreamingContext context) : base(info, context) { } }
      
      







ここでは、䟿宜䞊、印刷サヌビスを䜿甚する際のネむティブ゚ラヌの基本コヌドをすぐに芏定したした。



ここで、コヌドをより䟿利に䜿甚し、無効な匕数のネむティブメ゜ッドぞの転送を最小限に抑えるために、いく぀かの列挙型を実装する必芁がありたす。



 /// <summary> ///  . /// </summary> public enum Environment { /// <summary> ///   . /// </summary> Current, /// <summary> /// Windows NT x86. /// </summary> X86, /// <summary> /// Windows x64. /// </summary> X64, /// <summary> /// Windows IA64. /// </summary> IA64, } /// <summary> ///     . /// </summary> [Flags] public enum PortType { /// <summary> ///  . /// </summary> Write = 0x1, /// <summary> ///  . /// </summary> Read = 0x2, /// <summary> ///  . /// </summary> Redirected = 0x4, /// <summary> ///    . /// </summary> NetAttached = 0x8, } /// <summary> ///   . /// </summary> public enum DataType : uint { RAW = 1, LPR = 2, }
      
      





環境を文字列に、たたはその逆に倉換するには、2぀の拡匵メ゜ッドを実装したす。



 /// <summary> ///     . /// </summary> public static class PrintingExtensions { /// <summary> ///    ,   WinAPI. /// </summary> /// <param name="environment"> .</param> /// <returns>    .</returns> internal static string GetEnvironmentName(this Environment environment) { switch (environment) { default: return null; case Environment.X86: return "Windows x86"; case Environment.X64: return "Windows x64"; case Environment.IA64: return "Windows IA64"; } } /// <summary> ///  <see cref="Environment"/>,     . /// </summary> /// <param name="environmentString">   .</param> /// <returns><see cref="Environment"/>,     .</returns> internal static Environment GetEnvironment(this string environmentString) { environmentString = environmentString.ToLower(); if (environmentString.Contains("x86")) return Environment.X86; if (environmentString.Contains("x64")) return Environment.X64; if (environmentString.Contains("ia64")) return Environment.IA64; return Environment.Current; } }
      
      





2぀の拡匵メ゜ッドずenum Environmentの代わりに、通垞の文字列定数でうたくいくこずができたす。最初に環境の名前で無効なギャグを枡すこずを犁止したかっただけで、この方法で行きたしたが、同時に、事前定矩された制限された行セットから遞択する機胜を保持したす。



各クラスのコンポヌネントをむンストヌルおよび削陀するためのオヌバヌロヌドメ゜ッドを蚘述しないように、基本的な抜象クラスを実装したす。



抜象クラスPrintableDevice
 /// <summary> ///        . /// </summary> public abstract class PrintableDevice : IPrintableDevice { /// <summary> ///    . /// </summary> public virtual string Name { get; protected set; } /// <summary> ///     <see cref="PrintableDevice"/>. /// </summary> /// <param name="name"></param> /// <exception cref="ArgumentNullException"/> public PrintableDevice(string name) { if (string.IsNullOrEmpty(name)) throw new ArgumentNullException("name"); Name = name; } /// <summary> ///       . /// </summary> /// <param name="serverName"> .</param> /// <exception cref="FileNotFoundException" /> /// <exception cref="PrintingException" /> public abstract void Install(string serverName); /// <summary> ///       . /// </summary> /// <exception cref="FileNotFoundException" /> /// <exception cref="PrintingException" /> public void Install() => Install(null); /// <summary> ///       . /// </summary> /// <param name="serverName"> .</param> /// <param name="e">,    .</param> /// <returns>True,     ,  False.</returns> public bool TryInstall(string serverName, out PrintingException e) { e = null; try { Install(serverName); } catch (PrintingException ex) { e = ex; return false; } return true; } /// <summary> ///       . /// </summary> /// <param name="serverName"> .</param> /// <returns>True,     ,  False.</returns> public bool TryInstall(string serverName) => TryInstall(serverName, out PrintingException e); /// <summary> ///       . /// </summary> /// <param name="e">,    .</param> /// <returns>True,     ,  False.</returns> public bool TryInstall(out PrintingException e) => TryInstall(null, out e); /// <summary> ///       . /// </summary> /// <returns>True,     ,  False.</returns> public bool TryInstall() => TryInstall(out PrintingException e); /// <summary> ///       . /// </summary> /// <param name="serverName"> .</param> /// <exception cref="PrintingException" /> public abstract void Uninstall(string serverName); /// <summary> ///       . /// </summary> /// <exception cref="PrintingException" /> public void Uninstall() => Uninstall(null); /// <summary> ///       . /// </summary> /// <param name="serverName"> .</param> /// <param name="e">,    .</param> /// <returns>True,     ,  False.</returns> public bool TryUninstall(string serverName, out PrintingException e) { e = null; try { Uninstall(serverName); } catch (PrintingException ex) { e = ex; return false; } return true; } /// <summary> ///       . /// </summary> /// <param name="serverName"> .</param> /// <returns>True,     ,  False.</returns> public bool TryUninstall(string serverName) => TryUninstall(serverName, out PrintingException e); /// <summary> ///       . /// </summary> /// <param name="e">,    .</param> /// <returns>True,     ,  False.</returns> public bool TryUninstall(out PrintingException e) => TryUninstall(null, out e); /// <summary> ///       . /// </summary> /// <returns>True,     ,  False.</returns> public bool TryUninstall() => TryUninstall(out PrintingException e); }
      
      







プリントモニタヌ



印刷モニタ​​の実装を開始したす。たず、理論的な郚分ですでに説明したネむティブ構造が必芁です。



struct MonitorInfo
 /// <summary> ///        . /// </summary> [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] internal struct MonitorInfo { /// <summary> ///  . /// </summary> [MarshalAs(UnmanagedType.LPTStr)] public string Name; /// <summary> /// ,      (, Windows NT x86, Windows IA64  Windows x64). /// </summary> [MarshalAs(UnmanagedType.LPTStr)] public string Environment; /// <summary> ///   *.dll . /// </summary> [MarshalAs(UnmanagedType.LPTStr)] public string DllName; }
      
      







次に、印刷モニタ​​ヌを実装するためのむンタヌフェヌスが必芁です。



むンタヌフェヌスIMonitor
 /// <summary> ///       . /// </summary> public interface IMonitor : IPrintableDevice { /// <summary> /// ,      (, Windows NT x86, Windows IA64  Windows x64). /// </summary> Environment Environment { get; } /// <summary> ///   *.dll . /// </summary> string Dll { get; } }
      
      







今のずころこれで十分です。将来、ポリモヌフィズムに違反するこずなく機胜を拡匵する必芁がある堎合、むンタヌフェむスのおかげで、このタスクを簡単に実装できたす。



たた、蚘事の理論ブロックでシステムにモニタヌを远加するネむティブメ゜ッドに぀いおも説明したしたが、むンストヌルされたモニタヌのリストを取埗し、モニタヌを削陀しお、モニタヌのクラスを実装する方法に぀いお説明したす。



クラスモニタヌ
 /// <summary> ///      . /// </summary> public class Monitor : PrintableDevice, IMonitor { /// <summary> /// ,      (, Windows NT x86, Windows IA64  Windows x64). /// </summary> public virtual Environment Environment { get; protected set; } /// <summary> ///   *.dll . /// </summary> public virtual string Dll { get; protected set; } /// <summary> ///        . /// </summary> public static Monitor[] All { get { if (!PrintingApi.TryGetInfo(EnumMonitors, out MonitorInfo[] monitorInfo)) return null; Monitor[] monitors = new Monitor[monitorInfo.Length]; for (int i = 0; i < monitorInfo.Length; i++) monitors[i] = new Monitor(monitorInfo[i].Name, monitorInfo[i].DllName, monitorInfo[i].Environment.GetEnvironment()); return monitors; } } /// <summary> ///     <see cref="Monitor"/>. /// </summary> /// <param name="name">  .</param> /// <param name="dll">  *.dll .</param> /// <param name="environment">,      (, Windows NT x86, Windows IA64  Windows x64).</param> /// <exception cref="ArgumentNullException" /> public Monitor(string name, string dll, Environment environment) : base(name) { if (string.IsNullOrEmpty(dll)) throw new ArgumentNullException("dll"); Environment = environment; Dll = dll; } /// <summary> ///     <see cref="Monitor"/>. /// </summary> /// <param name="name">  .</param> /// <param name="dll">  *.dll .</param> /// <exception cref="ArgumentNullException" /> public Monitor(string name, string dll) : this(name, dll, Environment.Current) { } /// <summary> ///      . /// </summary> /// <param name="serverName"> .</param> /// <exception cref="FileNotFoundException"/> /// <exception cref="PrintingException"/> public override void Install(string serverName) { try { if (!File.Exists(Dll)) throw new FileNotFoundException("     ", Dll); string dllName = Path.GetFileName(Dll); string dllPath = Path.Combine(System.Environment.SystemDirectory, dllName); File.Copy(Dll, dllPath, true); MonitorInfo monitorInfo = new MonitorInfo { Name = Name, Environment = Environment.GetEnvironmentName(), DllName = File.Exists(dllPath) ? dllName : Dll, }; if (AddMonitor(serverName, 2, ref monitorInfo)) return; if (Marshal.GetLastWin32Error() == PrintingException.ErrorMonitorAlreadyInstalled && TryUninstall(serverName) && AddMonitor(serverName, 2, ref monitorInfo)) return; else throw new PrintingException(Marshal.GetLastWin32Error()); } catch (Exception e) { throw new PrintingException(e.Message, e); } } /// <summary> ///      . /// </summary> /// <param name="serverName"> .</param> /// <exception cref="PrintingException"/> public override void Uninstall(string serverName) { try { if (!All.Select(m => m.Name).Contains(Name)) return; /// TODO:      . if (DeleteMonitor(serverName, Environment.GetEnvironmentName(), Name)) return; if (Marshal.GetLastWin32Error() == PrintingException.ErrorMonitorUnknown) return; if (DeleteMonitor(serverName, Environment.GetEnvironmentName(), Name)) return; throw new PrintingException(Marshal.GetLastWin32Error()); } catch (Exception e) { throw new PrintingException(e.Message, e); } } #region Native /// <summary> ///      . /// </summary> /// <param name="serverName"> ,     .   null -    .</param> /// <param name="level">  .    2.</param> /// <param name="monitor">  <see cref="MonitorInfo"/>.</param> /// <returns>True,    ,  False.</returns> [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] internal static extern bool AddMonitor(string serverName, uint level, ref MonitorInfo monitor); /// <summary> ///       <see cref="MonitorInfo"/>. /// </summary> /// <param name="serverName"> ,      .   null -    .</param> /// <param name="level">  .    1  2.</param> /// <param name="monitors">     <see cref="MonitorInfo"/>.</param> /// <param name="bufferSize">    <see cref="MonitorInfo"/> ( ).</param> /// <param name="bytesNeeded">    .</param> /// <param name="bufferReturnedLength">  .</param> /// <returns>True,    ,  False.</returns> [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] internal static extern bool EnumMonitors(string serverName, uint level, IntPtr monitors, uint bufferSize, ref uint bytesNeeded, ref uint bufferReturnedLength); /// <summary> ///      . /// </summary> /// <param name="serverName"> ,     .   null -    .</param> /// <param name="environment">,      (, Windows x86, Windows IA64  Windows x64).</param> /// <param name="monitorName">  .</param> /// <returns>True,    ,  False.</returns> [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] internal static extern bool DeleteMonitor(string serverName, string environment, string monitorName); #endregion }
      
      







これで、同じクラスの印刷モニタ​​ヌを操䜜するために必芁な機胜がすべお揃いたした。ファクトリにモニタヌむンスタンスを䜜成するメ゜ッドも远加したす。



PrintingApiクラスの機胜を拡匵する
 /// <summary> ///       . /// </summary> public static Monitor[] Monitors => Monitor.All; /// <summary> ///      . /// </summary> /// <param name="name">  .</param> /// <param name="dll">   dll  .</param> /// <param name="environment">,      .</param> /// <param name="serverName"> ,      .</param> /// <returns>  .</returns> public Monitor CreateMonitor(string name, string dll, Environment environment, string serverName) { Monitor monitor = new Monitor(name, dll, environment); monitor.TryInstall(serverName); return monitor; } /// <summary> ///      . /// </summary> /// <param name="name">  .</param> /// <param name="dll">   dll  .</param> /// <param name="environment">,      .</param> /// <returns>  .</returns> public Monitor CreateMonitor(string name, string dll, Environment environment) => CreateMonitor(name, dll, environment, null); /// <summary> ///      . /// </summary> /// <param name="name">  .</param> /// <param name="dll">   dll  .</param> /// <param name="serverName"> ,      .</param> /// <returns>  .</returns> public Monitor CreateMonitor(string name, string dll, string serverName) => CreateMonitor(name, dll, Environment.Current, null); /// <summary> ///      . /// </summary> /// <param name="name">  .</param> /// <param name="dll">   dll  .</param> /// <returns>  .</returns> public Monitor CreateMonitor(string name, string dll) => CreateMonitor(name, dll, null);
      
      







コヌドの操䜜性を怜蚌したす。ナニットテストを远加し、䟿宜䞊、モニタヌDLLの名前ずパス定数を芏定し、メむンコヌドセグメントをカバヌするテストメ゜ッドを実装したす。



印刷モニタ​​ヌの単䜓テスト
 /// <summary> ///     <see cref="Monitor"/>. /// </summary> [TestClass] public class MonitorTests { /// <summary> ///  . /// </summary> protected const string MonitorName = "Test Monitor"; /// <summary> ///   dll . /// </summary> protected const string MonitorDll = "D:/Printing Tests/mfilemon.dll"; /// <summary> ///    dll . /// </summary> protected const string FailedMonitorDll = "noexist.dll"; /// <summary> ///    . /// </summary> [TestMethod] public void InstallTest() { Monitor monitor = new Monitor(MonitorName, MonitorDll); monitor.Install(); Assert.IsTrue(Monitor.All.Select(m => m.Name).Contains(MonitorName)); } /// <summary> ///    . /// </summary> [TestMethod] public void UninstallTest() { Monitor monitor = new Monitor(MonitorName, MonitorDll); monitor.Uninstall(); Assert.IsFalse(Monitor.All.Select(m => m.Name).Contains(MonitorName)); } /// <summary> ///        . /// </summary> [TestMethod] public void TryInstallTest() { Monitor monitor = new Monitor(MonitorName, MonitorDll); bool f = monitor.TryInstall(); Assert.IsTrue(f); Assert.IsTrue(Monitor.All.Select(m => m.Name).Contains(MonitorName)); } /// <summary> ///        . /// </summary> [TestMethod] public void TryUninstallTest() { Monitor monitor = new Monitor(MonitorName, MonitorDll); bool f = monitor.TryUninstall(); Assert.IsTrue(f); Assert.IsFalse(Monitor.All.Select(m => m.Name).Contains(MonitorName)); } /// <summary> ///     . /// </summary> [TestMethod] [ExpectedException(typeof(PrintingException))] public void InstallFailedTest() { Monitor monitor = new Monitor(MonitorName, FailedMonitorDll); monitor.Install(); Assert.IsFalse(Monitor.All.Select(m => m.Name).Contains(MonitorName)); } /// <summary> ///         . /// </summary> [TestMethod] public void TryInstallFailedTest() { Monitor monitor = new Monitor(MonitorName, FailedMonitorDll); bool f = monitor.TryInstall(); Assert.IsFalse(f); Assert.IsFalse(Monitor.All.Select(m => m.Name).Contains(MonitorName)); }
      
      







プリントモニタヌをテストディレクトリmfilemon.dllにドロップするこずを忘れないでください。



枯



ポヌトに぀いおも同じこずを行いたす。たず、IPortが必芁です。



むンタヌフェむスiport
 /// <summary> ///       . /// </summary> public interface IPort : IPrintableDevice { /// <summary> /// ,    . /// </summary> IMonitor Monitor { get; } /// <summary> ///  . /// </summary> string Description { get; } /// <summary> ///  . /// </summary> PortType Type { get; } }
      
      







次に、ネむティブポヌトのデヌタ構造に぀いお説明したす。



struct portInfo
 /// <summary> ///      . /// </summary> [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct PortInfo { /// <summary> ///    (, "LPT1:"). /// </summary> [MarshalAs(UnmanagedType.LPTStr)] public string PortName; /// <summary> ///     (, "PJL monitor").    null. /// </summary> [MarshalAs(UnmanagedType.LPTStr)] public string MonitorName; /// <summary> ///   (,  <see cref="PortName"/>  "LPT1:", <see cref="Description"/>   "printer port").    null. /// </summary> [MarshalAs(UnmanagedType.LPTStr)] public string Description; /// <summary> ///  . /// </summary> public PortType Type; /// <summary> /// .    0. /// </summary> internal uint Reserved; }
      
      







スプヌラヌは、ポヌトを開閉する2぀の方法を提䟛したす。1぀目は基本的なAddPort / DeletePortメ゜ッドを䜿甚する方法、2぀目はXcvDataツヌルずその䞊のさたざたなヘルパヌを䜿甚する方法です。2番目のオプションが望たしいのは、最初のケヌスでは、むンストヌルプロセスのダむアログボックスぞのポむンタが必芁ですが、これは必芁ありたせん。XCVには、さらに次のものが必芁です。



列挙型PrinterAccess-プリンタヌデヌタぞのアクセス暩
 /// <summary> ///    . /// </summary> internal enum PrinterAccess { /// <summary> ///     . /// </summary> ServerAdmin = 0x01, /// <summary> ///     . /// </summary> ServerEnum = 0x02, /// <summary> ///     . /// </summary> PrinterAdmin = 0x04, /// <summary> ///     . /// </summary> PrinterUse = 0x08, /// <summary> ///      . /// </summary> JobAdmin = 0x10, /// <summary> ///    . /// </summary> JobRead = 0x20, /// <summary> ///   . /// </summary> StandardRightsRequired = 0x000F0000, /// <summary> ///   . /// </summary> PrinterAllAccess = (StandardRightsRequired | PrinterAdmin | PrinterUse), }
      
      







struct PrinterDefaults-XcvDataのプリンタヌ蚭定
 /// <summary> ///     <see cref="Port.XcvData(IntPtr, string, IntPtr, uint, IntPtr, uint, out uint, out uint)"/>. /// </summary> [StructLayout(LayoutKind.Sequential)] internal struct PrinterDefaults { /// <summary> ///   (   null). /// </summary> public IntPtr DataType; /// <summary> ///   (   null). /// </summary> public IntPtr DevMode; /// <summary> ///    . /// </summary> public PrinterAccess DesiredAccess; }
      
      







struct PortData-XcvDataのポヌトデヌタ構造
 /// <summary> ///     <see cref="Port.XcvData(System.IntPtr, string, System.IntPtr, uint, System.IntPtr, uint, out uint, out uint)"/>. /// </summary> [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] internal struct PortData { /// <summary> ///  . /// </summary> [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] public string PortName; /// <summary> ///   (   1). /// </summary> public uint Version; /// <summary> /// . /// </summary> public DataType Protocol; /// <summary> ///   . /// </summary> public uint BufferSize; /// <summary> ///   . /// </summary> public uint ReservedSize; /// <summary> ///  . /// </summary> [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 49)] public string HostAddress; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)] public string SNMPCommunity; public uint DoubleSpool; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)] public string Queue; /// <summary> /// IP-. /// </summary> [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] public string IPAddress; /// <summary> ///  . /// </summary> [MarshalAs(UnmanagedType.ByValArray, SizeConst = 540)] public byte[] Reserved; /// <summary> ///  . /// </summary> public uint PortNumber; public uint SNMPEnabled; public uint SNMPDevIndex; }
      
      







列挙型XcvDataType-XcvDataの操䜜タむプ
 /// <summary> ///    <see cref="Port.XcvData(IntPtr, string, IntPtr, uint, IntPtr, uint, out uint, out uint)"/>. /// </summary> internal enum XcvDataType { /// <summary> ///   . /// </summary> AddPort, /// <summary> ///   . /// </summary> DeletePort, }
      
      







さお、これでポヌトクラスを実装するために必芁なものがすべお揃いたした。



クラスポヌト
 /// <summary> ///     . /// </summary> public class Port : PrintableDevice, IPort { /// <summary> /// ,    . /// </summary> public virtual IMonitor Monitor { get; protected set; } /// <summary> ///  . /// </summary> public virtual string Description { get; protected set; } /// <summary> ///  . /// </summary> public virtual PortType Type { get; protected set; } /// <summary> ///        . /// </summary> public static Port[] All { get { if (!PrintingApi.TryGetInfo(EnumPorts, out PortInfo[] portInfo)) return null; Port[] ports = new Port[portInfo.Length]; for (int i = 0; i < portInfo.Length; i++) ports[i] = new Port(portInfo[i].PortName, portInfo[i].Description, portInfo[i].Type, portInfo[i].MonitorName); return ports; } } /// <summary> ///     <see cref="Port"/>. /// </summary> /// <param name="name"> .</param> /// <param name="description"> .</param> /// <param name="type"> .</param> /// <param name="monitorName">  ,    .</param> /// <exception cref="ArgumentNullException"/> /// <exception cref="PrintingException"/> public Port(string name, string description, PortType type, string monitorName) : base(name) { Description = description; Type = type; Monitor[] monitors = PrintingApi.Monitors; if (monitors.Select(m => m.Name).Contains(monitorName)) Monitor = monitors.Where(m => m.Name == monitorName).FirstOrDefault(); } /// <summary> ///     <see cref="Port"/>. /// </summary> /// <param name="name"> .</param> /// <param name="description"> .</param> /// <param name="type"> .</param> /// <param name="monitor"> ,    .</param> /// <exception cref="ArgumentNullException"/> /// <exception cref="PrintingException"/> public Port(string name, string description, PortType type, IMonitor monitor) : this(name, description, type, monitor?.Name) { } /// <summary> ///     <see cref="Port"/>. /// </summary> /// <param name="name"> .</param> /// <param name="description"> .</param> /// <param name="type"> .</param> /// <exception cref="ArgumentNullException"/> /// <exception cref="PrintingException"/> public Port(string name, string description, PortType type) : this(name, description, type, null as string) { } /// <summary> ///     <see cref="Port"/>. /// </summary> /// <param name="name"> .</param> /// <param name="description"> .</param> /// <param name="monitorName">  ,    .</param> /// <exception cref="ArgumentNullException"/> /// <exception cref="PrintingException"/> public Port(string name, string description, string monitorName) : this(name, description, PortType.Redirected, monitorName) { } /// <summary> ///     <see cref="Port"/>. /// </summary> /// <param name="name"> .</param> /// <param name="description"> .</param> /// <param name="monitor"> ,    .</param> /// <exception cref="ArgumentNullException"/> /// <exception cref="PrintingException"/> public Port(string name, string description, IMonitor monitor) : this(name, description, PortType.Redirected, monitor) { } /// <summary> ///     <see cref="Port"/>. /// </summary> /// <param name="name"> .</param> /// <param name="description"> .</param> /// <exception cref="ArgumentNullException"/> /// <exception cref="PrintingException"/> public Port(string name, string description) : this(name, description, null as string) { } /// <summary> ///     <see cref="Port"/>. /// </summary> /// <param name="name"> .</param> /// <param name="monitor"> ,    .</param> /// <exception cref="ArgumentNullException"/> /// <exception cref="PrintingException"/> public Port(string name, IMonitor monitor) : this(name, null, monitor) { } /// <summary> ///     <see cref="Port"/>. /// </summary> /// <param name="name"> .</param> /// <param name="type"> .</param> /// <exception cref="ArgumentNullException"/> /// <exception cref="PrintingException"/> public Port(string name, PortType type) : this(name, null, type) { } /// <summary> ///     <see cref="Port"/>. /// </summary> /// <param name="name"> .</param> /// <exception cref="ArgumentNullException"/> /// <exception cref="PrintingException"/> public Port(string name) : this(name, null as string) { } /// <summary> ///     . /// </summary> /// <param name="serverName"> .</param> /// <exception cref="FileNotFoundException"/> /// <exception cref="PrintingException"/> public override void Install(string serverName) { try { if (All.Select(p => p.Name).Contains(Name)) Uninstall(serverName); PrinterDefaults defaults = new PrinterDefaults { DesiredAccess = PrinterAccess.ServerAdmin }; if (!OpenPrinter($",XcvMonitor {Monitor.Name}", out IntPtr printerHandle, ref defaults)) throw new PrintingException(Marshal.GetLastWin32Error()); PortData portData = new PortData { Version = 1, Protocol = DataType.RAW, PortNumber = 9100, // 9100 = RAW, 515 = LPR. ReservedSize = 0, PortName = Name, IPAddress = serverName, SNMPCommunity = "public", SNMPEnabled = 1, SNMPDevIndex = 1, }; uint size = (uint)Marshal.SizeOf(portData); portData.BufferSize = size; IntPtr pointer = Marshal.AllocHGlobal((int)size); Marshal.StructureToPtr(portData, pointer, true); try { IntPtr outputData = IntPtr.Zero; uint outputDataSize = 0; if (!XcvData(printerHandle, Enum.GetName(typeof(XcvDataType), XcvDataType.AddPort), pointer, size, outputData, outputDataSize, out uint outputNeeded, out uint status)) throw new PrintingException(Marshal.GetLastWin32Error()); } catch (Exception e) { throw new PrintingException(e.Message, e); } finally { Marshal.FreeHGlobal(pointer); ClosePrinter(printerHandle); } } catch (Exception e) { throw new PrintingException(e.Message, e); } } /// <summary> ///     . /// </summary> /// <param name="serverName"> .</param> /// <exception cref="FileNotFoundException"/> /// <exception cref="PrintingException"/> public override void Uninstall(string serverName) { try { if (!All.Select(p => p.Name).Contains(Name)) return; /// TODO:   ,   . PrinterDefaults defaults = new PrinterDefaults { DesiredAccess = PrinterAccess.ServerAdmin }; if (!OpenPrinter($",XcvPort {Name}", out IntPtr printerHandle, ref defaults)) throw new PrintingException(Marshal.GetLastWin32Error()); PortData portData = new PortData { Version = 1, Protocol = DataType.RAW, PortNumber = 9100, ReservedSize = 0, PortName = Name, IPAddress = serverName, SNMPCommunity = "public", SNMPEnabled = 1, SNMPDevIndex = 1, }; uint size = (uint)Marshal.SizeOf(portData); portData.BufferSize = size; IntPtr pointer = Marshal.AllocHGlobal((int)size); Marshal.StructureToPtr(portData, pointer, true); try { IntPtr outputData = IntPtr.Zero; uint outputDataSize = 0; if (!XcvData(printerHandle, Enum.GetName(typeof(XcvDataType), XcvDataType.DeletePort), pointer, size, outputData, outputDataSize, out uint outputNeeded, out uint status)) throw new PrintingException(Marshal.GetLastWin32Error()); } catch (Exception e) { throw new PrintingException(e.Message, e); } finally { Marshal.FreeHGlobal(pointer); ClosePrinter(printerHandle); } } catch (Exception e) { throw new PrintingException(e.Message, e); } } #region Native /// <summary> ///    . /// </summary> /// <param name="printerName"> .</param> /// <param name="printer">  .</param> /// <param name="printerDefaults">  <see cref="XcvData(IntPtr, string, IntPtr, uint, IntPtr, uint, out uint, out uint)"/>.</param> /// <returns>True,    ,  False.</returns> [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] internal static extern bool OpenPrinter(string printerName, out IntPtr printer, ref PrinterDefaults printerDefaults); /// <summary> ///   . /// </summary> /// <param name="printer"> .</param> /// <returns>True,    ,  False.</returns> [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] internal static extern bool ClosePrinter(IntPtr printer); /// <summary> ///    . /// </summary> /// <param name="printer">  .</param> /// <param name="dataType"> .</param> /// <param name="inputData"> .</param> /// <param name="inputDataSize">   .</param> /// <param name="outputData"> .</param> /// <param name="outputDataSize">   .</param> /// <param name="outputNeeded">    .</param> /// <param name="status"> .</param> /// <returns>True,    ,  False.</returns> [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] internal static extern bool XcvData(IntPtr printer, string dataType, IntPtr inputData, uint inputDataSize, IntPtr outputData, uint outputDataSize, out uint outputNeeded, out uint status); /// <summary> ///       <see cref="PortInfo"/>. /// </summary> /// <param name="serverName"> ,      .   null -    .</param> /// <param name="level">  .    1  2.</param> /// <param name="ports">     <see cref="PortInfo"/>.</param> /// <param name="bufferSize">    <see cref="PortInfo"/> ( ).</param> /// <param name="bytesNeeded">    .</param> /// <param name="bufferReturnedLength">  .</param> /// <returns>True,    ,  False.</returns> [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] internal static extern bool EnumPorts(string serverName, uint level, IntPtr ports, uint bufferSize, ref uint bytesNeeded, ref uint bufferReturnedLength); #endregion }
      
      







次に、ポヌトを操䜜するための機胜を導入しお、PrintingApiを拡匵したす。



PrintingApiぞのポヌトメ゜ッドの远加
 /// <summary> ///        . /// </summary> public static Port[] Ports => Port.All; /// <summary> ///      . /// </summary> /// <param name="name"> .</param> /// <param name="description"> .</param> /// <param name="type"> .</param> /// <param name="monitor"> ,    .</param> /// <param name="serverName"> .</param> /// <returns>  .</returns> public Port OpenPort(string name, string description, PortType type, Monitor monitor, string serverName) { Port port = new Port(name, description, type, monitor); monitor.TryInstall(serverName); return port; } /// <summary> ///      . /// </summary> /// <param name="name"> .</param> /// <param name="description"> .</param> /// <param name="type"> .</param> /// <param name="monitor"> ,    .</param> /// <returns>  .</returns> public Port OpenPort(string name, string description, PortType type, Monitor monitor) => OpenPort(name, description, type, monitor, null); /// <summary> ///      . /// </summary> /// <param name="name"> .</param> /// <param name="description"> .</param> /// <param name="type"> .</param> /// <param name="serverName"> .</param> /// <returns>  .</returns> public Port OpenPort(string name, string description, PortType type, string serverName) => OpenPort(name, description, type, null, serverName); /// <summary> ///      . /// </summary> /// <param name="name"> .</param> /// <param name="description"> .</param> /// <param name="type"> .</param> /// <returns>  .</returns> public Port OpenPort(string name, string description, PortType type) => OpenPort(name, description, type, null as string); /// <summary> ///      . /// </summary> /// <param name="name"> .</param> /// <param name="description"> .</param> /// <param name="monitor"> ,    .</param> /// <param name="serverName"> .</param> /// <returns>  .</returns> public Port OpenPort(string name, string description, Monitor monitor, string serverName) => OpenPort(name, description, PortType.Redirected, monitor, serverName); /// <summary> ///      . /// </summary> /// <param name="name"> .</param> /// <param name="description"> .</param> /// <param name="monitor"> ,    .</param> /// <returns>  .</returns> public Port OpenPort(string name, string description, Monitor monitor) => OpenPort(name, description, monitor, null); /// <summary> ///      . /// </summary> /// <param name="name"> .</param> /// <param name="monitor"> ,    .</param> /// <param name="serverName"> .</param> /// <returns>  .</returns> public Port OpenPort(string name, Monitor monitor, string serverName) => OpenPort(name, null, monitor, serverName); /// <summary> ///      . /// </summary> /// <param name="name"> .</param> /// <param name="monitor"> ,    .</param> /// <returns>  .</returns> public Port OpenPort(string name, Monitor monitor) => OpenPort(name, monitor, null); /// <summary> ///      . /// </summary> /// <param name="name"> .</param> /// <param name="type"> .</param> /// <param name="serverName"> .</param> /// <returns>  .</returns> public Port OpenPort(string name, PortType type, string serverName) => OpenPort(name, null, type, serverName); /// <summary> ///      . /// </summary> /// <param name="name"> .</param> /// <param name="type"> .</param> /// <returns>  .</returns> public Port OpenPort(string name, PortType type) => OpenPort(name, type, null); /// <summary> ///      . /// </summary> /// <param name="name"> .</param> /// <param name="description"> .</param> /// <param name="serverName"> .</param> /// <returns>  .</returns> public Port OpenPort(string name, string description, string serverName) => OpenPort(name, description, null, serverName); /// <summary> ///      . /// </summary> /// <param name="name"> .</param> /// <param name="description"> .</param> /// <returns>  .</returns> public Port OpenPort(string name, string description) => OpenPort(name, description, null as string); /// <summary> ///      . /// </summary> /// <param name="name"> .</param> /// <returns>  .</returns> public Port OpenPort(string name) => OpenPort(name, null as string);
      
      







たた、TODOの代わりにモニタヌの削陀メ゜ッドにチェックを远加するこずを忘れないでください



 IEnumerable<Port> openPorts = Port.All.Where(p => p.Monitor?.Name == Name); foreach (Port openPort in openPorts) openPort.Uninstall(serverName);
      
      





これで、コヌドが機胜しおいるこずを確認し、次のステップに進むこずができたす。



印刷ポヌトを操䜜するための単䜓テスト
 /// <summary> ///     <see cref="Port"/>. /// </summary> [TestClass] public class PortTests { /// <summary> ///  . /// </summary> protected const string PortName = "TESTPORT:"; /// <summary> ///  . /// </summary> protected const string PortDescription = "Description for " + PortName; /// <summary> ///  . /// </summary> protected const string MonitorName = "mfilemon"; /// <summary> ///   . /// </summary> protected const string FailedMonitorName = "noexist"; /// <summary> ///    . /// </summary> [TestMethod] public void InstallTest() { Port port = new Port(PortName, PortDescription, MonitorName); port.Install(); Assert.IsTrue(Port.All.Select(p => p.Name).Contains(PortName)); } /// <summary> ///    . /// </summary> [TestMethod] public void UninstallTest() { Port port = new Port(PortName, PortDescription, MonitorName); port.Uninstall(); Assert.IsFalse(Port.All.Select(p => p.Name).Contains(PortName)); } /// <summary> ///        . /// </summary> [TestMethod] public void TryInstallTest() { Port port = new Port(PortName, PortDescription, MonitorName); bool f = port.TryInstall(); Assert.IsTrue(f); Assert.IsTrue(Port.All.Select(p => p.Name).Contains(PortName)); } /// <summary> ///        . /// </summary> [TestMethod] public void TryUninstallTest() { Port port = new Port(PortName, PortDescription, MonitorName); bool f = port.TryUninstall(); Assert.IsTrue(f); Assert.IsFalse(Port.All.Select(p => p.Name).Contains(PortName)); } /// <summary> ///     . /// </summary> [TestMethod] [ExpectedException(typeof(PrintingException))] public void InstallFailedTest() { Port port = new Port(PortName, PortDescription, MonitorName); port.Install(); Assert.IsFalse(Port.All.Select(p => p.Name).Contains(PortName)); } /// <summary> ///         . /// </summary> [TestMethod] public void TryInstallFailedTest() { Port port = new Port(PortName, PortDescription, FailedMonitorName); bool f = port.TryUninstall(); Assert.IsTrue(f); Assert.IsFalse(Port.All.Select(p => p.Name).Contains(PortName)); } }
      
      







プリンタヌドラむバヌ



ドラむバヌの堎合、すべおはモニタヌの堎合ずたったく同じです。最初に、ネむティブデヌタ構造、次にむンタヌフェむス、むンタヌフェむスの実装、API機胜の拡匵、テストを説明したす。最初にドラむバヌファむルをテストディレクトリにドロップするこずを忘れないでください。



struct DriverInfo
 /// <summary> ///         . /// </summary> [StructLayout(LayoutKind.Sequential)] public struct DriverInfo { /// <summary> ///    ,     .   - 3  4 (V3  V4    ). /// </summary> public uint Version; /// <summary> ///   (, "QMS 810"). /// </summary> [MarshalAs(UnmanagedType.LPTStr)] public string Name; /// <summary> /// ,      (, Windows x86, Windows IA64  Windows x64). /// </summary> [MarshalAs(UnmanagedType.LPTStr)] public string Environment; /// <summary> ///         (, "C:\DRIVERS\Pscript.dll"). /// </summary> [MarshalAs(UnmanagedType.LPTStr)] public string DriverPath; /// <summary> ///         (, "C:\DRIVERS\Qms810.ppd"). /// </summary> [MarshalAs(UnmanagedType.LPTStr)] public string DataFile; /// <summary> ///      dll    (, "C:\DRIVERS\Pscriptui.dll"). /// </summary> [MarshalAs(UnmanagedType.LPTStr)] public string ConfigFile; /// <summary> ///      dll  HLP-  (, "C:\DRIVERS\Pscript.hlp"). /// </summary> [MarshalAs(UnmanagedType.LPTStr)] public string HelpFile; /// <summary> ///  . /// </summary> [MarshalAs(UnmanagedType.LPTStr)] public string DependentFiles; /// <summary> ///  . /// </summary> [MarshalAs(UnmanagedType.LPTStr)] public string MonitorName; /// <summary> ///     . /// </summary> [MarshalAs(UnmanagedType.LPTStr)] public string DefaultDataType; }
      
      







むンタヌフェヌスidriver
 /// <summary> ///       . /// </summary> public interface IDriver : IPrintableDevice { /// <summary> ///  . /// </summary> IMonitor Monitor { get; } /// <summary> ///    ,     .   - 3  4 (V3  V4    ). /// </summary> uint Version { get; } /// <summary> /// ,      (, Windows x86, Windows IA64  Windows x64). /// </summary> Environment Environment { get; } /// <summary> ///         (, "C:\DRIVERS\Pscript.dll"). /// </summary> string Dll { get; } /// <summary> ///         (, "C:\DRIVERS\Qms810.ppd"). /// </summary> string DataFile { get; } /// <summary> ///      dll    (, "C:\DRIVERS\Pscriptui.dll"). /// </summary> string ConfigFile { get; } /// <summary> ///      dll  HLP-  (, "C:\DRIVERS\Pscript.hlp"). /// </summary> string HelpFile { get; } /// <summary> ///  . /// </summary> string DependentFiles { get; } /// <summary> ///     . /// </summary> DataType DefaultDataType { get; } }
      
      







クラスドラむバヌ
 /// <summary> ///       . /// </summary> public class Driver : PrintableDevice, IDriver { /// <summary> ///  . /// </summary> public virtual IMonitor Monitor { get; protected set; } /// <summary> ///    ,     .   - 3  4 (V3  V4    ). /// </summary> public virtual uint Version { get; protected set; } /// <summary> /// ,     . /// </summary> public virtual Environment Environment { get; protected set; } /// <summary> ///        . /// </summary> public virtual string Dll { get; protected set; } /// <summary> ///        . /// </summary> public virtual string DataFile { get; protected set; } /// <summary> ///      dll   . /// </summary> public virtual string ConfigFile { get; protected set; } /// <summary> ///      dll  HLP- . /// </summary> public virtual string HelpFile { get; protected set; } /// <summary> ///  . /// </summary> public virtual string DependentFiles { get; protected set; } /// <summary> ///     . /// </summary> public virtual DataType DefaultDataType { get; protected set; } /// <summary> ///      . /// </summary> public static string Directory { get; protected set; } /// <summary> ///        . /// </summary> public static Driver[] All { get { if (!PrintingApi.TryGetInfo(EnumPrinterDrivers, 3, out DriverInfo[] driverInfo)) return null; Driver[] drivers = new Driver[driverInfo.Length]; for (int i = 0; i < driverInfo.Length; i++) drivers[i] = new Driver(driverInfo[i].Name, driverInfo[i].DriverPath, driverInfo[i].DataFile, driverInfo[i].ConfigFile, driverInfo[i].HelpFile, driverInfo[i].Version, driverInfo[i].Environment.GetEnvironment(), (DataType)Enum.Parse(typeof(DataType), driverInfo[i].DefaultDataType ?? "RAW", true), driverInfo[i].DependentFiles, driverInfo[i].MonitorName); return drivers; } } /// <summary> ///     <see cref="Driver"/>. /// </summary> /// <param name="name"> .</param> /// <param name="dll">        (, "C:\DRIVERS\Pscript.dll").</param> /// <param name="dataFile">        (, "C:\DRIVERS\Qms810.ppd").</param> /// <param name="configFile">     dll    (, "C:\DRIVERS\Pscriptui.dll").</param> /// <param name="helpFile">     dll  HLP-  (, "C:\DRIVERS\Pscript.hlp").</param> /// <param name="version">   ,     .   - 3  4 (V3  V4    ).</param> /// <param name="environment">,      (, Windows x86, Windows IA64  Windows x64).</param> /// <param name="defaultDataType">    .</param> /// <param name="dependentFiles"> .</param> /// <param name="monitorName">  .</param> public Driver(string name, string dll, string dataFile, string configFile, string helpFile, uint version, Environment environment, DataType defaultDataType, string dependentFiles, string monitorName) : base(name) { Dll = dll; DataFile = dataFile; ConfigFile = configFile; HelpFile = helpFile; Version = version; Environment = environment; DefaultDataType = defaultDataType; DependentFiles = dependentFiles; Monitor[] monitors = PrintingApi.Monitors; if (monitors.Select(m => m.Name).Contains(monitorName)) Monitor = monitors.Where(m => m.Name == monitorName).FirstOrDefault(); } /// <summary> ///     <see cref="Driver"/>. /// </summary> /// <param name="name"> .</param> /// <param name="dll">        (, "C:\DRIVERS\Pscript.dll").</param> /// <param name="dataFile">        (, "C:\DRIVERS\Qms810.ppd").</param> /// <param name="configFile">     dll    (, "C:\DRIVERS\Pscriptui.dll").</param> /// <param name="helpFile">     dll  HLP-  (, "C:\DRIVERS\Pscript.hlp").</param> /// <param name="version">   ,     .   - 3  4 (V3  V4    ).</param> /// <param name="environment">,      (, Windows x86, Windows IA64  Windows x64).</param> /// <param name="defaultDataType">    .</param> /// <param name="dependentFiles"> .</param> /// <param name="monitor"> .</param> public Driver(string name, string dll, string dataFile, string configFile, string helpFile, uint version, Environment environment, DataType defaultDataType, string dependentFiles, IMonitor monitor) : this(name, dll, dataFile, configFile, helpFile, version, environment, defaultDataType, dependentFiles, monitor?.Name) { } /// <summary> ///     <see cref="Driver"/>. /// </summary> /// <param name="name"> .</param> /// <param name="dll">        (, "C:\DRIVERS\Pscript.dll").</param> /// <param name="dataFile">        (, "C:\DRIVERS\Qms810.ppd").</param> /// <param name="configFile">     dll    (, "C:\DRIVERS\Pscriptui.dll").</param> /// <param name="helpFile">     dll  HLP-  (, "C:\DRIVERS\Pscript.hlp").</param> /// <param name="version">   ,     .   - 3  4 (V3  V4    ).</param> /// <param name="environment">,      (, Windows x86, Windows IA64  Windows x64).</param> /// <param name="defaultDataType">    .</param> /// <param name="monitorName">  .</param> public Driver(string name, string dll, string dataFile, string configFile, string helpFile, uint version, Environment environment, DataType defaultDataType, string monitorName) : this(name, dll, dataFile, configFile, helpFile, version, environment, defaultDataType, null, monitorName) { } /// <summary> ///     <see cref="Driver"/>. /// </summary> /// <param name="name"> .</param> /// <param name="dll">        (, "C:\DRIVERS\Pscript.dll").</param> /// <param name="dataFile">        (, "C:\DRIVERS\Qms810.ppd").</param> /// <param name="configFile">     dll    (, "C:\DRIVERS\Pscriptui.dll").</param> /// <param name="helpFile">     dll  HLP-  (, "C:\DRIVERS\Pscript.hlp").</param> /// <param name="version">   ,     .   - 3  4 (V3  V4    ).</param> /// <param name="environment">,      (, Windows x86, Windows IA64  Windows x64).</param> /// <param name="defaultDataType">    .</param> /// <param name="monitor"> .</param> public Driver(string name, string dll, string dataFile, string configFile, string helpFile, uint version, Environment environment, DataType defaultDataType, IMonitor monitor) : this(name, dll, dataFile, configFile, helpFile, version, environment, defaultDataType, monitor?.Name) { } /// <summary> ///     <see cref="Driver"/>. /// </summary> /// <param name="name"> .</param> /// <param name="dll">        (, "C:\DRIVERS\Pscript.dll").</param> /// <param name="dataFile">        (, "C:\DRIVERS\Qms810.ppd").</param> /// <param name="configFile">     dll    (, "C:\DRIVERS\Pscriptui.dll").</param> /// <param name="helpFile">     dll  HLP-  (, "C:\DRIVERS\Pscript.hlp").</param> /// <param name="version">   ,     .   - 3  4 (V3  V4    ).</param> /// <param name="environment">,      (, Windows x86, Windows IA64  Windows x64).</param> /// <param name="monitorName">  .</param> public Driver(string name, string dll, string dataFile, string configFile, string helpFile, uint version, Environment environment, string monitorName) : this(name, dll, dataFile, configFile, helpFile, version, environment, DataType.RAW, monitorName) { } /// <summary> ///     <see cref="Driver"/>. /// </summary> /// <param name="name"> .</param> /// <param name="dll">        (, "C:\DRIVERS\Pscript.dll").</param> /// <param name="dataFile">        (, "C:\DRIVERS\Qms810.ppd").</param> /// <param name="configFile">     dll    (, "C:\DRIVERS\Pscriptui.dll").</param> /// <param name="helpFile">     dll  HLP-  (, "C:\DRIVERS\Pscript.hlp").</param> /// <param name="version">   ,     .   - 3  4 (V3  V4    ).</param> /// <param name="environment">,      (, Windows x86, Windows IA64  Windows x64).</param> /// <param name="monitor"> .</param> public Driver(string name, string dll, string dataFile, string configFile, string helpFile, uint version, Environment environment, IMonitor monitor) : this(name, dll, dataFile, configFile, helpFile, version, environment, monitor?.Name) { } /// <summary> ///     <see cref="Driver"/>. /// </summary> /// <param name="name"> .</param> /// <param name="dll">        (, "C:\DRIVERS\Pscript.dll").</param> /// <param name="dataFile">        (, "C:\DRIVERS\Qms810.ppd").</param> /// <param name="configFile">     dll    (, "C:\DRIVERS\Pscriptui.dll").</param> /// <param name="helpFile">     dll  HLP-  (, "C:\DRIVERS\Pscript.hlp").</param> /// <param name="version">   ,     .   - 3  4 (V3  V4    ).</param> /// <param name="monitorName">  .</param> public Driver(string name, string dll, string dataFile, string configFile, string helpFile, uint version, string monitorName) : this(name, dll, dataFile, configFile, helpFile, version, Environment.Current, monitorName) { } /// <summary> ///     <see cref="Driver"/>. /// </summary> /// <param name="name"> .</param> /// <param name="dll">        (, "C:\DRIVERS\Pscript.dll").</param> /// <param name="dataFile">        (, "C:\DRIVERS\Qms810.ppd").</param> /// <param name="configFile">     dll    (, "C:\DRIVERS\Pscriptui.dll").</param> /// <param name="helpFile">     dll  HLP-  (, "C:\DRIVERS\Pscript.hlp").</param> /// <param name="version">   ,     .   - 3  4 (V3  V4    ).</param> /// <param name="monitor"> .</param> public Driver(string name, string dll, string dataFile, string configFile, string helpFile, uint version, IMonitor monitor) : this(name, dll, dataFile, configFile, helpFile, version, monitor?.Name) { } /// <summary> ///     <see cref="Driver"/>. /// </summary> /// <param name="name"> .</param> /// <param name="dll">        (, "C:\DRIVERS\Pscript.dll").</param> /// <param name="dataFile">        (, "C:\DRIVERS\Qms810.ppd").</param> /// <param name="configFile">     dll    (, "C:\DRIVERS\Pscriptui.dll").</param> /// <param name="helpFile">     dll  HLP-  (, "C:\DRIVERS\Pscript.hlp").</param> /// <param name="monitorName">  .</param> public Driver(string name, string dll, string dataFile, string configFile, string helpFile, string monitorName) : this(name, dll, dataFile, configFile, helpFile, 3, monitorName) { } /// <summary> ///     <see cref="Driver"/>. /// </summary> /// <param name="name"> .</param> /// <param name="dll">        (, "C:\DRIVERS\Pscript.dll").</param> /// <param name="dataFile">        (, "C:\DRIVERS\Qms810.ppd").</param> /// <param name="configFile">     dll    (, "C:\DRIVERS\Pscriptui.dll").</param> /// <param name="helpFile">     dll  HLP-  (, "C:\DRIVERS\Pscript.hlp").</param> /// <param name="monitor"> .</param> public Driver(string name, string dll, string dataFile, string configFile, string helpFile, IMonitor monitor) : this(name, dll, dataFile, configFile, helpFile, monitor?.Name) { } /// <summary> ///     <see cref="Driver"/>. /// </summary> /// <param name="name"> .</param> /// <param name="dll">        (, "C:\DRIVERS\Pscript.dll").</param> /// <param name="dataFile">        (, "C:\DRIVERS\Qms810.ppd").</param> /// <param name="configFile">     dll    (, "C:\DRIVERS\Pscriptui.dll").</param> /// <param name="monitorName">  .</param> public Driver(string name, string dll, string dataFile, string configFile, string monitorName) : this(name, dll, dataFile, configFile, null, monitorName) { } /// <summary> ///     <see cref="Driver"/>. /// </summary> /// <param name="name"> .</param> /// <param name="dll">        (, "C:\DRIVERS\Pscript.dll").</param> /// <param name="dataFile">        (, "C:\DRIVERS\Qms810.ppd").</param> /// <param name="configFile">     dll    (, "C:\DRIVERS\Pscriptui.dll").</param> /// <param name="monitor"> .</param> public Driver(string name, string dll, string dataFile, string configFile, IMonitor monitor) : this(name, dll, dataFile, configFile, monitor?.Name) { } /// <summary> ///     <see cref="Driver"/>. /// </summary> /// <param name="name"> .</param> /// <param name="dll">        (, "C:\DRIVERS\Pscript.dll").</param> /// <param name="dataFile">        (, "C:\DRIVERS\Qms810.ppd").</param> /// <param name="configFile">     dll    (, "C:\DRIVERS\Pscriptui.dll").</param> public Driver(string name, string dll, string dataFile, string configFile) : this(name, dll, dataFile, configFile, null as string) { } /// <summary> ///    <see cref="Driver"/>. /// </summary> static Driver() { uint length = 1024; StringBuilder driverDirectory = new StringBuilder((int)length); uint bytesNeeded = 0; if (!GetPrinterDriverDirectory(null, null, 1, driverDirectory, length, ref bytesNeeded)) throw new PrintingException(Marshal.GetLastWin32Error()); Directory = driverDirectory.ToString(); } /// <summary> ///     . /// </summary> /// <param name="serverName"> .</param> public override void Install(string serverName) { try { if (!File.Exists(Dll)) throw new PrintingException($"     '{Dll}'"); if (!File.Exists(DataFile)) throw new PrintingException($"     '{DataFile}'"); if (!File.Exists(ConfigFile)) throw new PrintingException($"     '{ConfigFile}'"); if (All.Select(d => d.Name).Contains(Name)) Uninstall(serverName); string systemDriverPath = Path.Combine(Directory, Path.GetFileName(Dll)); string systemDataPath = Path.Combine(Directory, Path.GetFileName(DataFile)); string systemConfigPath = Path.Combine(Directory, Path.GetFileName(ConfigFile)); string systemHelpPath = Path.Combine(Directory, Path.GetFileName(HelpFile)); File.Copy(Dll, systemDriverPath, true); File.Copy(DataFile, systemDataPath, true); File.Copy(ConfigFile, systemConfigPath, true); if (File.Exists(HelpFile)) File.Copy(HelpFile, systemHelpPath, true); DriverInfo driverInfo = new DriverInfo { Version = Version, Name = Name, Environment = Environment.GetEnvironmentName(), DriverPath = File.Exists(systemDriverPath) ? systemDriverPath : Dll, DataFile = File.Exists(systemDataPath) ? systemDataPath : DataFile, ConfigFile = File.Exists(systemConfigPath) ? systemConfigPath : ConfigFile, HelpFile = File.Exists(systemHelpPath) ? systemHelpPath : HelpFile, DependentFiles = DependentFiles, MonitorName = Monitor?.Name, DefaultDataType = Enum.GetName(typeof(DataType), DefaultDataType), }; if (AddPrinterDriver(serverName, Version, ref driverInfo)) return; int lastWin32ErrorCode = Marshal.GetLastWin32Error(); if (lastWin32ErrorCode == 0) return; throw new PrintingException(lastWin32ErrorCode); } catch (Exception e) { throw new PrintingException(e.Message, e); } } /// <summary> ///     . /// </summary> /// <param name="serverName"> .</param> public override void Uninstall(string serverName) { try { if (!All.Select(d => d.Name).Contains(Name)) return; /// TODO:   ,  . if (DeletePrinterDriver(serverName, Environment.GetEnvironmentName(), Name)) return; throw new PrintingException(Marshal.GetLastWin32Error()); } catch (Exception e) { throw new PrintingException(e.Message, e); } } #region Native /// <summary> ///         . /// </summary> /// <param name="serverName"> ,         .   null -   .</param> /// <param name="environment">,      (, Windows x86, Windows IA64  Windows x64).</param> /// <param name="level">  .    1.</param> /// <param name="driverDirectory">   .</param> /// <param name="bufferSize">    .</param> /// <param name="bytesNeeded">   .</param> /// <returns>True,    ,  False.</returns> [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] internal static extern bool GetPrinterDriverDirectory(string serverName, string environment, uint level, [Out] StringBuilder driverDirectory, uint bufferSize, ref uint bytesNeeded); /// <summary> ///    . /// </summary> /// <param name="serverName"> .</param> /// <param name="level">  .    1, 2, 3, 4, 5, 6  8.</param> /// <param name="driverInfo"> .</param> /// <returns>True,    ,  False.</returns> [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] internal static extern bool AddPrinterDriver(string serverName, uint level, ref DriverInfo driverInfo); /// <summary> ///       <see cref="DriverInfo"/>. /// </summary> /// <param name="serverName"> ,      .   null -    .</param> /// <param name="environment"> (, Windows x86, Windows IA64, Windows x64,  Windows NT R4000).    null, ///     ( ).    "all",       , ///       .</param> /// <param name="level">  .    1, 2, 3, 4, 5, 6  8.</param> /// <param name="drivers">     <see cref="DriverInfo"/>.</param> /// <param name="bufferSize">    <see cref="DriverInfo"/> ( ).</param> /// <param name="bytesNeeded">    .</param> /// <param name="bufferReturnedLength">  .</param> /// <returns>True,    ,  False.</returns> [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] internal static extern bool EnumPrinterDrivers(string serverName, string environment, uint level, IntPtr drivers, uint bufferSize, ref uint bytesNeeded, ref uint bufferReturnedLength); /// <summary> ///    . /// </summary> /// <param name="serverName"> .</param> /// <param name="environment"> (, Windows x86, Windows IA64, Windows x64,  Windows NT R4000).    null, ///     ( ).    "all",       , ///       .</param> /// <param name="driverName"> .</param> /// <returns>True,    ,  False.</returns> [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] internal static extern bool DeletePrinterDriver(string serverName, string environment, string driverName); #endregion }
      
      







ドラむバヌメ゜ッドでPrintingApiを拡匵する
 /// <summary> ///        . /// </summary> public static Driver[] Drivers => Driver.All; /// <summary> ///     . /// </summary> /// <param name="name"> .</param> /// <param name="dll">        (, "C:\DRIVERS\Pscript.dll").</param> /// <param name="dataFile">        (, "C:\DRIVERS\Qms810.ppd").</param> /// <param name="configFile">     dll    (, "C:\DRIVERS\Pscriptui.dll").</param> /// <param name="helpFile">     dll  HLP-  (, "C:\DRIVERS\Pscript.hlp").</param> /// <param name="version">   ,     .   - 3  4 (V3  V4    ).</param> /// <param name="environment">,      (, Windows x86, Windows IA64  Windows x64).</param> /// <param name="defaultDataType">    .</param> /// <param name="dependentFiles"> .</param> /// <param name="monitor"> .</param> /// <param name="serverName"> .</param> /// <returns>  .</returns> public Driver InstallDriver(string name, string dll, string dataFile, string configFile, string helpFile, uint version, Environment environment, DataType defaultDataType, string dependentFiles, Monitor monitor, string serverName) { Driver driver = new Driver(name, dll, dataFile, configFile, helpFile, version, environment, defaultDataType, dependentFiles, monitor); driver.TryInstall(serverName); return driver; } /// <summary> ///     . /// </summary> /// <param name="name"> .</param> /// <param name="dll">        (, "C:\DRIVERS\Pscript.dll").</param> /// <param name="dataFile">        (, "C:\DRIVERS\Qms810.ppd").</param> /// <param name="configFile">     dll    (, "C:\DRIVERS\Pscriptui.dll").</param> /// <param name="helpFile">     dll  HLP-  (, "C:\DRIVERS\Pscript.hlp").</param> /// <param name="version">   ,     .   - 3  4 (V3  V4    ).</param> /// <param name="environment">,      (, Windows x86, Windows IA64  Windows x64).</param> /// <param name="defaultDataType">    .</param> /// <param name="dependentFiles"> .</param> /// <param name="monitor"> .</param> /// <returns>  .</returns> public Driver InstallDriver(string name, string dll, string dataFile, string configFile, string helpFile, uint version, Environment environment, DataType defaultDataType, string dependentFiles, Monitor monitor) => InstallDriver(name, dll, dataFile, configFile, helpFile, version, environment, defaultDataType, dependentFiles, monitor, null); /// <summary> ///     . /// </summary> /// <param name="name"> .</param> /// <param name="dll">        (, "C:\DRIVERS\Pscript.dll").</param> /// <param name="dataFile">        (, "C:\DRIVERS\Qms810.ppd").</param> /// <param name="configFile">     dll    (, "C:\DRIVERS\Pscriptui.dll").</param> /// <param name="helpFile">     dll  HLP-  (, "C:\DRIVERS\Pscript.hlp").</param> /// <param name="version">   ,     .   - 3  4 (V3  V4    ).</param> /// <param name="environment">,      (, Windows x86, Windows IA64  Windows x64).</param> /// <param name="defaultDataType">    .</param> /// <param name="dependentFiles"> .</param> /// <param name="serverName"> .</param> /// <returns>  .</returns> public Driver InstallDriver(string name, string dll, string dataFile, string configFile, string helpFile, uint version, Environment environment, DataType defaultDataType, string dependentFiles, string serverName) => InstallDriver(name, dll, dataFile, configFile, helpFile, version, environment, defaultDataType, dependentFiles, null, serverName); /// <summary> ///     . /// </summary> /// <param name="name"> .</param> /// <param name="dll">        (, "C:\DRIVERS\Pscript.dll").</param> /// <param name="dataFile">        (, "C:\DRIVERS\Qms810.ppd").</param> /// <param name="configFile">     dll    (, "C:\DRIVERS\Pscriptui.dll").</param> /// <param name="helpFile">     dll  HLP-  (, "C:\DRIVERS\Pscript.hlp").</param> /// <param name="version">   ,     .   - 3  4 (V3  V4    ).</param> /// <param name="environment">,      (, Windows x86, Windows IA64  Windows x64).</param> /// <param name="defaultDataType">    .</param> /// <param name="dependentFiles"> .</param> /// <returns>  .</returns> public Driver InstallDriver(string name, string dll, string dataFile, string configFile, string helpFile, uint version, Environment environment, DataType defaultDataType, string dependentFiles) => InstallDriver(name, dll, dataFile, configFile, helpFile, version, environment, defaultDataType, dependentFiles, null as string); /// <summary> ///     . /// </summary> /// <param name="name"> .</param> /// <param name="dll">        (, "C:\DRIVERS\Pscript.dll").</param> /// <param name="dataFile">        (, "C:\DRIVERS\Qms810.ppd").</param> /// <param name="configFile">     dll    (, "C:\DRIVERS\Pscriptui.dll").</param> /// <param name="helpFile">     dll  HLP-  (, "C:\DRIVERS\Pscript.hlp").</param> /// <param name="version">   ,     .   - 3  4 (V3  V4    ).</param> /// <param name="environment">,      (, Windows x86, Windows IA64  Windows x64).</param> /// <param name="defaultDataType">    .</param> /// <returns>  .</returns> public Driver InstallDriver(string name, string dll, string dataFile, string configFile, string helpFile, uint version, Environment environment, DataType defaultDataType) => InstallDriver(name, dll, dataFile, configFile, helpFile, version, environment, defaultDataType, null); /// <summary> ///     . /// </summary> /// <param name="name"> .</param> /// <param name="dll">        (, "C:\DRIVERS\Pscript.dll").</param> /// <param name="dataFile">        (, "C:\DRIVERS\Qms810.ppd").</param> /// <param name="configFile">     dll    (, "C:\DRIVERS\Pscriptui.dll").</param> /// <param name="helpFile">     dll  HLP-  (, "C:\DRIVERS\Pscript.hlp").</param> /// <param name="version">   ,     .   - 3  4 (V3  V4    ).</param> /// <param name="environment">,      (, Windows x86, Windows IA64  Windows x64).</param> /// <param name="serverName"> .</param> /// <returns>  .</returns> public Driver InstallDriver(string name, string dll, string dataFile, string configFile, string helpFile, uint version, Environment environment, string serverName) => InstallDriver(name, dll, dataFile, configFile, helpFile, version, environment, DataType.RAW, serverName); /// <summary> ///     . /// </summary> /// <param name="name"> .</param> /// <param name="dll">        (, "C:\DRIVERS\Pscript.dll").</param> /// <param name="dataFile">        (, "C:\DRIVERS\Qms810.ppd").</param> /// <param name="configFile">     dll    (, "C:\DRIVERS\Pscriptui.dll").</param> /// <param name="helpFile">     dll  HLP-  (, "C:\DRIVERS\Pscript.hlp").</param> /// <param name="version">   ,     .   - 3  4 (V3  V4    ).</param> /// <param name="environment">,      (, Windows x86, Windows IA64  Windows x64).</param> /// <returns>  .</returns> public Driver InstallDriver(string name, string dll, string dataFile, string configFile, string helpFile, uint version, Environment environment) => InstallDriver(name, dll, dataFile, configFile, helpFile, version, environment, null); /// <summary> ///     . /// </summary> /// <param name="name"> .</param> /// <param name="dll">        (, "C:\DRIVERS\Pscript.dll").</param> /// <param name="dataFile">        (, "C:\DRIVERS\Qms810.ppd").</param> /// <param name="configFile">     dll    (, "C:\DRIVERS\Pscriptui.dll").</param> /// <param name="helpFile">     dll  HLP-  (, "C:\DRIVERS\Pscript.hlp").</param> /// <param name="version">   ,     .   - 3  4 (V3  V4    ).</param> /// <param name="serverName"> .</param> /// <returns>  .</returns> public Driver InstallDriver(string name, string dll, string dataFile, string configFile, string helpFile, uint version, string serverName) => InstallDriver(name, dll, dataFile, configFile, helpFile, version, Environment.Current, serverName); /// <summary> ///     . /// </summary> /// <param name="name"> .</param> /// <param name="dll">        (, "C:\DRIVERS\Pscript.dll").</param> /// <param name="dataFile">        (, "C:\DRIVERS\Qms810.ppd").</param> /// <param name="configFile">     dll    (, "C:\DRIVERS\Pscriptui.dll").</param> /// <param name="helpFile">     dll  HLP-  (, "C:\DRIVERS\Pscript.hlp").</param> /// <param name="version">   ,     .   - 3  4 (V3  V4    ).</param> /// <returns>  .</returns> public Driver InstallDriver(string name, string dll, string dataFile, string configFile, string helpFile, uint version) => InstallDriver(name, dll, dataFile, configFile, helpFile, version, null); /// <summary> ///     . /// </summary> /// <param name="name"> .</param> /// <param name="dll">        (, "C:\DRIVERS\Pscript.dll").</param> /// <param name="dataFile">        (, "C:\DRIVERS\Qms810.ppd").</param> /// <param name="configFile">     dll    (, "C:\DRIVERS\Pscriptui.dll").</param> /// <param name="helpFile">     dll  HLP-  (, "C:\DRIVERS\Pscript.hlp").</param> /// <param name="serverName"> .</param> /// <returns>  .</returns> public Driver InstallDriver(string name, string dll, string dataFile, string configFile, string helpFile, string serverName) => InstallDriver(name, dll, dataFile, configFile, helpFile, 3, serverName); /// <summary> ///     . /// </summary> /// <param name="name"> .</param> /// <param name="dll">        (, "C:\DRIVERS\Pscript.dll").</param> /// <param name="dataFile">        (, "C:\DRIVERS\Qms810.ppd").</param> /// <param name="configFile">     dll    (, "C:\DRIVERS\Pscriptui.dll").</param> /// <param name="helpFile">     dll  HLP-  (, "C:\DRIVERS\Pscript.hlp").</param> /// <returns>  .</returns> public Driver InstallDriver(string name, string dll, string dataFile, string configFile, string helpFile) => InstallDriver(name, dll, dataFile, configFile, helpFile, null); /// <summary> ///     . /// </summary> /// <param name="name"> .</param> /// <param name="dll">        (, "C:\DRIVERS\Pscript.dll").</param> /// <param name="dataFile">        (, "C:\DRIVERS\Qms810.ppd").</param> /// <param name="configFile">     dll    (, "C:\DRIVERS\Pscriptui.dll").</param> /// <returns>  .</returns> public Driver InstallDriver(string name, string dll, string dataFile, string configFile) => InstallDriver(name, dll, dataFile, configFile, null);
      
      







モニタヌの削陀方法で、印刷モニタ​​ヌに関連付けられおいるドラむバヌの削陀を远加したす
 IEnumerable<Driver> drivers = Driver.All.Where(d => d.Monitor?.Name == Name); foreach (Driver driver in drivers) driver.Uninstall(serverName);
      
      







単䜓テストを䜿甚したテスト
 /// <summary> ///     <see cref="Driver"/>. /// </summary> [TestClass] public class DriverTests { /// <summary> ///  . /// </summary> protected const string DriverName = "Test Driver"; /// <summary> ///  . /// </summary> protected const string MonitorName = "mfilemon"; /// <summary> ///   . /// </summary> protected const string FailedMonitorName = "noexist"; protected const string DllPath = "D:/Printing Tests/pscript.dll"; protected const string DataPath = "D:/Printing Tests/testprinter.ppd"; protected const string ConfigPath = "D:/Printing Tests/pscriptui.dll"; protected const string HelpPath = "D:/Printing Tests/pscript.hlp"; /// <summary> ///    . /// </summary> [TestMethod] public void InstallTest() { Driver driver = new Driver(DriverName, DllPath, DataPath, ConfigPath, HelpPath, MonitorName); driver.Install(); Assert.IsTrue(Driver.All.Select(d => d.Name).Contains(DriverName)); } /// <summary> ///    . /// </summary> [TestMethod] public void UninstallTest() { Driver driver = new Driver(DriverName, DllPath, DataPath, ConfigPath, HelpPath, MonitorName); driver.Uninstall(); Assert.IsFalse(Driver.All.Select(d => d.Name).Contains(DriverName)); } /// <summary> ///        . /// </summary> [TestMethod] public void TryInstallTest() { Driver driver = new Driver(DriverName, DllPath, DataPath, ConfigPath, HelpPath, MonitorName); bool f = driver.TryInstall(); Assert.IsTrue(f); Assert.IsTrue(Driver.All.Select(d => d.Name).Contains(DriverName)); } /// <summary> ///        . /// </summary> [TestMethod] public void TryUninstallTest() { Driver driver = new Driver(DriverName, DllPath, DataPath, ConfigPath, HelpPath, MonitorName); bool f = driver.TryUninstall(); Assert.IsTrue(f); Assert.IsFalse(Driver.All.Select(d => d.Name).Contains(DriverName)); } /// <summary> ///     . /// </summary> [TestMethod] [ExpectedException(typeof(PrintingException))] public void InstallFailedTest() { Driver driver = new Driver(DriverName, DllPath + "failed", DataPath, ConfigPath, HelpPath, FailedMonitorName); driver.Install(); Assert.IsFalse(Driver.All.Select(d => d.Name).Contains(DriverName)); } /// <summary> ///         . /// </summary> [TestMethod] public void TryInstallFailedTest() { Driver driver = new Driver(DriverName, DllPath + "failed", DataPath, ConfigPath, HelpPath, FailedMonitorName); bool f = driver.TryInstall(); Assert.IsTrue(f); Assert.IsFalse(Driver.All.Select(d => d.Name).Contains(DriverName)); } }
      
      







印刷装眮



そしお、今床は、おそらく、UIず印刷モニタ​​ヌの間の関係を提䟛する最も重芁なコンポヌネントであるプリンタヌを実装するずきです。以前の操䜜ずの違いもほずんどありたせん。



struct PrinterInfo
 /// <summary> ///    . /// </summary> [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct PrinterInfo { /// <summary> ///  . /// </summary> [MarshalAs(UnmanagedType.LPTStr)] public string ServerName; /// <summary> ///  . /// </summary> [MarshalAs(UnmanagedType.LPTStr)] public string PrinterName; /// <summary> ///   . /// </summary> [MarshalAs(UnmanagedType.LPTStr)] public string ShareName; /// <summary> ///  ,   . /// </summary> [MarshalAs(UnmanagedType.LPTStr)] public string PortName; /// <summary> ///   . /// </summary> [MarshalAs(UnmanagedType.LPTStr)] public string DriverName; /// <summary> ///  . /// </summary> [MarshalAs(UnmanagedType.LPTStr)] public string Comment; /// <summary> ///  . /// </summary> [MarshalAs(UnmanagedType.LPTStr)] public string Location; public IntPtr DevMode; [MarshalAs(UnmanagedType.LPTStr)] public string SepFile; /// <summary> ///  ,   . /// </summary> [MarshalAs(UnmanagedType.LPTStr)] public string PrintProcessor; /// <summary> ///    . /// </summary> [MarshalAs(UnmanagedType.LPTStr)] public string DataType; [MarshalAs(UnmanagedType.LPTStr)] public string Parameters; public IntPtr SecurityDescriptor; public uint Attributes; public uint Priority; public uint DefaultPriority; public uint StartTime; public uint UntilTime; public uint Status; public uint cJobs; public uint AveragePPM; }
      
      







むンストヌルされおいるプリンタヌのリストを取埗するには、フラグも必芁です。



列挙型PrinterEnumFlag
 /// <summary> ///       . /// </summary> [Flags] internal enum PrinterEnumFlag { Default = 0x00000001, Local = 0x00000002, Connections = 0x00000004, Favorite = 0x00000004, Name = 0x00000008, Remote = 0x00000010, Shared = 0x00000020, Network = 0x00000040, Expand = 0x00004000, Container = 0x00008000, IconMask = 0x00ff0000, Icon1 = 0x00010000, Icon2 = 0x00020000, Icon3 = 0x00040000, Icon4 = 0x00080000, Icon5 = 0x00100000, Icon6 = 0x00200000, Icon7 = 0x00400000, Icon8 = 0x00800000, Hide = 0x01000000, All = 0x02000000, Category3D = 0x04000000, }
      
      







むンタヌフェむスIPrinter
 /// <summary> ///     . /// </summary> public interface IPrinter : IPrintableDevice { /// <summary> /// ,    . /// </summary> IPort Port { get; } /// <summary> /// ,    . /// </summary> IDriver Driver { get; } /// <summary> ///   . /// </summary> string ShareName { get; } /// <summary> ///  ,    . /// </summary> string ServerName { get; } /// <summary> ///   . /// </summary> string Description { get; } /// <summary> ///  . /// </summary> string Location { get; } string SepFile { get; } /// <summary> ///  . /// </summary> string Parameters { get; } /// <summary> ///   . /// </summary> DataType DataType { get; } }
      
      







クラスプリンタヌ
 /// <summary> ///   . /// </summary> public class Printer : PrintableDevice, IPrinter { /// <summary> /// ,    . /// </summary> public virtual IPort Port { get; protected set; } /// <summary> /// ,    . /// </summary> public virtual IDriver Driver { get; protected set; } /// <summary> ///   . /// </summary> public virtual string ShareName { get; protected set; } /// <summary> ///   . /// </summary> public virtual string Description { get; protected set; } /// <summary> ///   . /// </summary> public virtual DataType DataType { get; protected set; } /// <summary> ///   . /// </summary> public virtual string Processor { get; protected set; } /// <summary> ///  ,    . /// </summary> public virtual string ServerName { get; protected set; } /// <summary> ///  . /// </summary> public virtual string Location { get; protected set; } /// <summary> ///  . /// </summary> public virtual string Parameters { get; protected set; } public virtual string SepFile { get; protected set; } /// <summary> ///      . /// </summary> public static Printer Default { get { uint length = 0; if (GetDefaultPrinter(null, ref length)) return null; int lastWin32Error = Marshal.GetLastWin32Error(); if (lastWin32Error != PrintingException.ErrorInsufficientBuffer) throw new PrintingException(lastWin32Error); StringBuilder printerName = new StringBuilder((int)length); if (!GetDefaultPrinter(printerName, ref length)) throw new PrintingException(Marshal.GetLastWin32Error()); string name = printerName.ToString(); return All.Where(p => p.Name == name).FirstOrDefault(); } set { if (!SetDefaultPrinter(value?.Name)) throw new PrintingException(Marshal.GetLastWin32Error()); } } /// <summary> ///      . /// </summary> public static Printer[] All { get { uint bytesNeeded = 0; uint bufferReturnedLength = 0; uint level = 2; PrinterEnumFlag flags = PrinterEnumFlag.Local | PrinterEnumFlag.Network; if (EnumPrinters(flags, null, level, IntPtr.Zero, 0, ref bytesNeeded, ref bufferReturnedLength)) return null; int lastWin32Error = Marshal.GetLastWin32Error(); if (lastWin32Error != PrintingException.ErrorInsufficientBuffer) throw new PrintingException(lastWin32Error); IntPtr printersPtr = Marshal.AllocHGlobal((int)bytesNeeded); try { if (EnumPrinters(flags, null, level, printersPtr, bytesNeeded, ref bytesNeeded, ref bufferReturnedLength)) { IntPtr currentPrinterPtr = printersPtr; PrinterInfo[] printerInfo = new PrinterInfo[bufferReturnedLength]; Printer[] printers = new Printer[bufferReturnedLength]; Type type = typeof(PrinterInfo); for (int i = 0; i < bufferReturnedLength; i++) { printerInfo[i] = (PrinterInfo)Marshal.PtrToStructure(currentPrinterPtr, type); currentPrinterPtr = (IntPtr)(currentPrinterPtr.ToInt64() + Marshal.SizeOf(type)); printers[i] = new Printer(printerInfo[i].PrinterName, printerInfo[i].PortName, printerInfo[i].DriverName, printerInfo[i].PrintProcessor, printerInfo[i].ShareName, printerInfo[i].ServerName, printerInfo[i].Comment, (DataType)Enum.Parse(typeof(DataType), printerInfo[i].DataType), printerInfo[i].Location, printerInfo[i].Parameters, printerInfo[i].SepFile); } return printers; } throw new PrintingException(Marshal.GetLastWin32Error()); } catch { return null; } finally { Marshal.FreeHGlobal(printersPtr); } } } /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="portName"> .</param> /// <param name="driverName"> .</param> /// <param name="processorName">  .</param> /// <param name="shareName">  .</param> /// <param name="serverName"> .</param> /// <param name="description"> .</param> /// <param name="dataType">  .</param> /// <param name="location"> .</param> /// <param name="parameters"> .</param> /// <param name="sepFile"></param> public Printer(string name, string portName, string driverName, string processorName, string shareName, string serverName, string description, DataType dataType, string location, string parameters, string sepFile) : base(name) { Port[] ports = PrintingApi.Ports; Driver[] drivers = PrintingApi.Drivers; if (ports.Select(p => p.Name).Contains(portName)) Port = ports.Where(p => p.Name == portName).FirstOrDefault(); if (drivers.Select(d => d.Name).Contains(driverName)) Driver = drivers.Where(d => d.Name == driverName).FirstOrDefault(); Processor = processorName; ShareName = shareName; ServerName = serverName; Description = description; DataType = dataType; Location = location; Parameters = parameters; SepFile = sepFile; } /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="port">,    .</param> /// <param name="driver">,    .</param> /// <param name="processorName">  .</param> /// <param name="shareName">  .</param> /// <param name="serverName"> .</param> /// <param name="description"> .</param> /// <param name="dataType">  .</param> /// <param name="location"> .</param> /// <param name="parameters"> .</param> /// <param name="sepFile"></param> public Printer(string name, IPort port, IDriver driver, string processorName, string shareName, string serverName, string description, DataType dataType, string location, string parameters, string sepFile) : this(name, port?.Name, driver?.Name, processorName, shareName, serverName, description, dataType, location, parameters, sepFile) { } /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="portName"> .</param> /// <param name="driverName"> .</param> /// <param name="processorName">  .</param> /// <param name="shareName">  .</param> /// <param name="serverName"> .</param> /// <param name="description"> .</param> /// <param name="dataType">  .</param> /// <param name="location"> .</param> /// <param name="parameters"> .</param> public Printer(string name, string portName, string driverName, string processorName, string shareName, string serverName, string description, DataType dataType, string location, string parameters) : this(name, portName, driverName, processorName, shareName, serverName, description, dataType, location, parameters, null) { } /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="port">,    .</param> /// <param name="driver">,    .</param> /// <param name="processorName">  .</param> /// <param name="shareName">  .</param> /// <param name="serverName"> .</param> /// <param name="description"> .</param> /// <param name="dataType">  .</param> /// <param name="location"> .</param> /// <param name="parameters"> .</param> public Printer(string name, IPort port, IDriver driver, string processorName, string shareName, string serverName, string description, DataType dataType, string location, string parameters) : this(name, port?.Name, driver?.Name, processorName, shareName, serverName, description, dataType, location, parameters) { } /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="portName"> .</param> /// <param name="driverName"> .</param> /// <param name="processorName">  .</param> /// <param name="shareName">  .</param> /// <param name="serverName"> .</param> /// <param name="description"> .</param> /// <param name="dataType">  .</param> /// <param name="location"> .</param> public Printer(string name, string portName, string driverName, string processorName, string shareName, string serverName, string description, DataType dataType, string location) : this(name, portName, driverName, processorName, shareName, serverName, description, dataType, location, null) { } /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="port">,    .</param> /// <param name="driver">,    .</param> /// <param name="processorName">  .</param> /// <param name="shareName">  .</param> /// <param name="serverName"> .</param> /// <param name="description"> .</param> /// <param name="dataType">  .</param> /// <param name="location"> .</param> public Printer(string name, IPort port, IDriver driver, string processorName, string shareName, string serverName, string description, DataType dataType, string location) : this(name, port?.Name, driver?.Name, processorName, shareName, serverName, description, dataType, location) { } /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="portName"> .</param> /// <param name="driverName"> .</param> /// <param name="processorName">  .</param> /// <param name="shareName">  .</param> /// <param name="serverName"> .</param> /// <param name="description"> .</param> /// <param name="dataType">  .</param> public Printer(string name, string portName, string driverName, string processorName, string shareName, string serverName, string description, DataType dataType) : this(name, portName, driverName, processorName, shareName, serverName, description, dataType, null) { } /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="port">,    .</param> /// <param name="driver">,    .</param> /// <param name="processorName">  .</param> /// <param name="shareName">  .</param> /// <param name="serverName"> .</param> /// <param name="description"> .</param> /// <param name="dataType">  .</param> public Printer(string name, IPort port, IDriver driver, string processorName, string shareName, string serverName, string description, DataType dataType) : this(name, port?.Name, driver?.Name, processorName, shareName, serverName, description, dataType) { } /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="portName"> .</param> /// <param name="driverName"> .</param> /// <param name="processorName">  .</param> /// <param name="shareName">  .</param> /// <param name="serverName"> .</param> /// <param name="description"> .</param> public Printer(string name, string portName, string driverName, string processorName, string shareName, string serverName, string description) : this(name, portName, driverName, processorName, shareName, serverName, description, DataType.RAW) { } /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="port">,    .</param> /// <param name="driver">,    .</param> /// <param name="processorName">  .</param> /// <param name="shareName">  .</param> /// <param name="serverName"> .</param> /// <param name="description"> .</param> public Printer(string name, IPort port, IDriver driver, string processorName, string shareName, string serverName, string description) : this(name, port?.Name, driver?.Name, processorName, shareName, serverName, description) { } /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="portName"> .</param> /// <param name="driverName"> .</param> /// <param name="processorName">  .</param> /// <param name="shareName">  .</param> /// <param name="serverName"> .</param> public Printer(string name, string portName, string driverName, string processorName, string shareName, string serverName) : this(name, portName, driverName, processorName, shareName, serverName, null) { } /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="port">,    .</param> /// <param name="driver">,    .</param> /// <param name="processorName">  .</param> /// <param name="shareName">  .</param> /// <param name="serverName"> .</param> public Printer(string name, IPort port, IDriver driver, string processorName, string shareName, string serverName) : this(name, port?.Name, driver?.Name, processorName, shareName, serverName) { } /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="portName"> .</param> /// <param name="driverName"> .</param> /// <param name="processorName">  .</param> /// <param name="shareName">  .</param> public Printer(string name, string portName, string driverName, string processorName, string shareName) : this(name, portName, driverName, processorName, shareName, null) { } /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="port">,    .</param> /// <param name="driver">,    .</param> /// <param name="processorName">  .</param> /// <param name="shareName">  .</param> public Printer(string name, IPort port, IDriver driver, string processorName, string shareName) : this(name, port?.Name, driver?.Name, processorName, shareName) { } /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="portName"> .</param> /// <param name="driverName"> .</param> /// <param name="processorName">  .</param> public Printer(string name, string portName, string driverName, string processorName) : this(name, portName, driverName, processorName, null) { } /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="port">,    .</param> /// <param name="driver">,    .</param> /// <param name="processorName">  .</param> public Printer(string name, IPort port, IDriver driver, string processorName) : this(name, port?.Name, driver?.Name, processorName) { } /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="portName"> .</param> /// <param name="driverName"> .</param> public Printer(string name, string portName, string driverName) : this(name, portName, driverName, "WinPrint") { } /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="port">,    .</param> /// <param name="driver">,    .</param> public Printer(string name, IPort port, IDriver driver) : this(name, port?.Name, driver?.Name) { } /// <summary> ///    . /// </summary> /// <param name="serverName"> .</param> public override void Install(string serverName) { try { if (All.Select(p => p.Name).Contains(Name)) Uninstall(serverName); PrinterInfo printerInfo = new PrinterInfo { ServerName = serverName, PrinterName = Name, ShareName = ShareName, PortName = Port?.Name, DriverName = Driver?.Name, Comment = Description, Location = Location, DevMode = new IntPtr(0), SepFile = SepFile, PrintProcessor = Processor, DataType = Enum.GetName(typeof(DataType), DataType), Parameters = Parameters, SecurityDescriptor = new IntPtr(0), }; if (AddPrinter(serverName, 2, ref printerInfo)) return; int lastWin32ErrorCode = Marshal.GetLastWin32Error(); if (lastWin32ErrorCode == 0) return; throw new PrintingException(lastWin32ErrorCode); } catch (Exception e) { throw new PrintingException(e.Message, e); } } /// <summary> ///    . /// </summary> /// <param name="serverName"> .</param> public override void Uninstall(string serverName) { try { if (!All.Select(p => p.Name).Contains(Name)) return; PrinterDefaults defaults = new PrinterDefaults { DesiredAccess = PrinterAccess.PrinterAllAccess }; if (!NET.Port.OpenPrinter(Name, out IntPtr printerHandle, ref defaults)) throw new PrintingException(Marshal.GetLastWin32Error()); if (!DeletePrinter(printerHandle)) { int lastWin32ErrorCode = Marshal.GetLastWin32Error(); if (lastWin32ErrorCode == PrintingException.ErrorInvalidPrinterName) return; throw new PrintingException(lastWin32ErrorCode); } NET.Port.ClosePrinter(printerHandle); } catch (Exception e) { throw new PrintingException(e.Message, e); } } #region Native /// <summary> ///    . /// </summary> /// <param name="serverName"> .</param> /// <param name="level"> .</param> /// <param name="printerInfo"> .</param> /// <returns>True,    ,  False.</returns> [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true, CallingConvention = CallingConvention.StdCall)] internal static extern bool AddPrinter(string serverName, uint level, [In] ref PrinterInfo printerInfo); /// <summary> ///   ,     . /// </summary> /// <param name="printerName"> .</param> /// <param name="bytesNeeded">   .</param> /// <returns>True,    ,  False.</returns> [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] internal static extern bool GetDefaultPrinter([Out] StringBuilder printerName, ref uint bytesNeeded); /// <summary> ///     . /// </summary> /// <param name="printerName">    .</param> /// <returns>True,    ,  False.</returns> [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] internal static extern bool SetDefaultPrinter(string printerName); /// <summary> ///      . /// </summary> /// <param name="flags">   .</param> /// <param name="serverName"> .</param> /// <param name="level"> .</param> /// <param name="printers">   .</param> /// <param name="bufferSize"> .</param> /// <param name="bytesNeeded">       .</param> /// <param name="bufferReturnedLength">  .</param> /// <returns>True,    ,  False.</returns> [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] internal static extern bool EnumPrinters(PrinterEnumFlag flags, string serverName, uint level, IntPtr printers, uint bufferSize, ref uint bytesNeeded, ref uint bufferReturnedLength); /// <summary> ///    . /// </summary> /// <param name="printer">  .</param> /// <returns>True,    ,  False.</returns> [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true, CallingConvention = CallingConvention.StdCall)] internal static extern bool DeletePrinter(IntPtr printer); #endregion }
      
      







印刷Apiの拡倧
 /// <summary> ///        . /// </summary> public static Printer[] Printers => Printer.All; /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="port">,    .</param> /// <param name="driver">,    .</param> /// <param name="processorName">  .</param> /// <param name="shareName">  .</param> /// <param name="serverName"> .</param> /// <param name="description"> .</param> /// <param name="dataType">  .</param> /// <param name="location"> .</param> /// <param name="parameters"> .</param> /// <param name="sepFile"></param> /// <returns>  .</returns> public Printer RunPrinter(string name, Port port, Driver driver, string processorName, string shareName, string serverName, string description, DataType dataType, string location, string parameters, string sepFile) { Printer printer = new Printer(name, port, driver, processorName, shareName, serverName, description, dataType, location, parameters, sepFile); printer.TryInstall(serverName); return printer; } /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="port">,    .</param> /// <param name="driver">,    .</param> /// <param name="processorName">  .</param> /// <param name="shareName">  .</param> /// <param name="serverName"> .</param> /// <param name="description"> .</param> /// <param name="dataType">  .</param> /// <param name="location"> .</param> /// <param name="parameters"> .</param> /// <returns>  .</returns> public Printer RunPrinter(string name, Port port, Driver driver, string processorName, string shareName, string serverName, string description, DataType dataType, string location, string parameters) => RunPrinter(name, port, driver, processorName, shareName, serverName, description, dataType, location, parameters, null); /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="port">,    .</param> /// <param name="driver">,    .</param> /// <param name="processorName">  .</param> /// <param name="shareName">  .</param> /// <param name="serverName"> .</param> /// <param name="description"> .</param> /// <param name="dataType">  .</param> /// <param name="location"> .</param> /// <returns>  .</returns> public Printer RunPrinter(string name, Port port, Driver driver, string processorName, string shareName, string serverName, string description, DataType dataType, string location) => RunPrinter(name, port, driver, processorName, shareName, serverName, description, dataType, location, null); /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="port">,    .</param> /// <param name="driver">,    .</param> /// <param name="processorName">  .</param> /// <param name="shareName">  .</param> /// <param name="serverName"> .</param> /// <param name="description"> .</param> /// <param name="dataType">  .</param> /// <returns>  .</returns> public Printer RunPrinter(string name, Port port, Driver driver, string processorName, string shareName, string serverName, string description, DataType dataType) => RunPrinter(name, port, driver, processorName, shareName, serverName, description, dataType, null); /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="port">,    .</param> /// <param name="driver">,    .</param> /// <param name="processorName">  .</param> /// <param name="shareName">  .</param> /// <param name="serverName"> .</param> /// <param name="description"> .</param> /// <returns>  .</returns> public Printer RunPrinter(string name, Port port, Driver driver, string processorName, string shareName, string serverName, string description) => RunPrinter(name, port, driver, processorName, shareName, serverName, description, DataType.RAW); /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="port">,    .</param> /// <param name="driver">,    .</param> /// <param name="processorName">  .</param> /// <param name="shareName">  .</param> /// <param name="serverName"> .</param> /// <returns>  .</returns> public Printer RunPrinter(string name, Port port, Driver driver, string processorName, string shareName, string serverName) => RunPrinter(name, port, driver, processorName, shareName, serverName, null); /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="port">,    .</param> /// <param name="driver">,    .</param> /// <param name="processorName">  .</param> /// <param name="shareName">  .</param> /// <returns>  .</returns> public Printer RunPrinter(string name, Port port, Driver driver, string processorName, string shareName) => RunPrinter(name, port, driver, processorName, shareName, null); /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="port">,    .</param> /// <param name="driver">,    .</param> /// <param name="processorName">  .</param> /// <returns>  .</returns> public Printer RunPrinter(string name, Port port, Driver driver, string processorName) => RunPrinter(name, port, driver, processorName, null); /// <summary> ///     <see cref="Printer"/>. /// </summary> /// <param name="name"> .</param> /// <param name="port">,    .</param> /// <param name="driver">,    .</param> /// <returns>  .</returns> public Printer RunPrinter(string name, Port port, Driver driver) => RunPrinter(name, port, driver, "WinPrint");
      
      







接続されおいるすべおのプリンタヌの削陀を、削陀するポヌトずドラむバヌに远加したす
 IEnumerable<Printer> printers = Printer.All.Where(p => p.Driver?.Name == Name); foreach (Printer printer in printers) printer.Uninstall(serverName);
      
      







テスト䞭
 /// <summary> ///     <see cref="Printer"/>. /// </summary> [TestClass] public class PrinterTests { /// <summary> ///  . /// </summary> protected const string PrinterName = "Test Printer"; /// <summary> ///  . /// </summary> protected const string PortName = "TESTPORT:"; /// <summary> ///  . /// </summary> protected const string DriverName = "Test Driver"; /// <summary> ///    . /// </summary> [TestMethod] public void InstallTest() { Printer printer = new Printer(PrinterName, PortName, DriverName); printer.Install(); Assert.IsTrue(Printer.All.Select(p => p.Name).Contains(PrinterName)); } /// <summary> ///    . /// </summary> [TestMethod] public void UninstallTest() { Printer printer = new Printer(PrinterName, PortName, DriverName); printer.Uninstall(); Assert.IsFalse(Printer.All.Select(p => p.Name).Contains(PrinterName)); } /// <summary> ///        . /// </summary> [TestMethod] public void TryInstallTest() { Printer printer = new Printer(PrinterName, PortName, DriverName); bool f = printer.TryInstall(); Assert.IsTrue(f); Assert.IsTrue(Printer.All.Select(p => p.Name).Contains(PrinterName)); } /// <summary> ///        . /// </summary> [TestMethod] public void TryUninstallTest() { Printer printer = new Printer(PrinterName, PortName, DriverName); bool f = printer.TryUninstall(); Assert.IsTrue(f); Assert.IsFalse(Printer.All.Select(p => p.Name).Contains(PrinterName)); } }
      
      







システムの倉曎を有効にするには、プリンタヌをむンストヌルした埌、印刷サヌビスを手動で再起動する必芁がありたす。Spoolerを起動/再起動する静的メ゜ッドをPrintingApiクラスに蚘述したす。これは、コンピュヌタヌの印刷サヌビスが最初に停止された堎合にも圓おはたりたす。



 /// <summary> ///   . /// </summary> /// <returns>True,    ,  False.</returns> public static bool TryRestart() { int tryCount = 5; while (tryCount > 0) { try { ServiceController sc = new ServiceController("Spooler"); if (sc.Status != ServiceControllerStatus.Stopped || sc.Status != ServiceControllerStatus.StopPending) { sc.Stop(); sc.WaitForStatus(ServiceControllerStatus.Stopped); } sc.Start(); sc.WaitForStatus(ServiceControllerStatus.Running); return sc.Status == ServiceControllerStatus.Running; } catch { tryCount--; } } return false; }
      
      





System.ServiceProcess.dllぞのリンクをプロゞェクトに接続する必芁がありたす。すべおが単玔ですサヌビスコントロヌラヌを起動し、ステヌタスを確認し、開始されおいる堎合は停止し、停止するたで埅機しおから、゚ラヌが発生した堎合たずえば、サヌビスが珟圚ビゞヌである堎合、開始しおステヌタスが「開始」に倉わるたで埅機し、手順4を繰り返したす回。



この䞊で、印刷デバむスを操䜜するための基本機胜は準備ができおいるず考えるこずができたす。そのため、珟時点でAPIでできるこず





PrintingApiクラスの最埌の䞀般的なテストを行い、蚘事の最埌の郚分に進みたす。



印刷デバむスのすべおのコンポヌネントの順次むンストヌルを確認する単䜓テスト
 [TestClass] public class PrintingApiTests { protected const string MonitorName = "mfilemon"; protected const string PortName = "TESTPORT:"; protected const string DriverName = "Test Driver"; protected const string PrinterName = "Test Printer"; protected const string MonitorFile = "D:/Printing Tests/mfilemon.dll"; protected const string DriverFile = "D:/Printing Tests/pscript5.dll"; protected const string DriverDataFile = "D:/Printing Tests/testprinter.ppd"; protected const string DriverConfigFile = "D:/Printing Tests/ps5ui.dll"; protected const string DriverHelpFile = "D:/Printing Tests/pscript.hlp"; [TestMethod] public void PrinterInstallationTest() { PrintingApi.TryRestart(); Monitor monitor = PrintingApi.Factory.CreateMonitor(MonitorName, MonitorFile); Port port = PrintingApi.Factory.OpenPort(PortName, monitor); Driver driver = PrintingApi.Factory.InstallDriver(DriverName, DriverFile, DriverDataFile, DriverConfigFile, DriverHelpFile, 3, Environment.Current, DataType.RAW, null, monitor); Printer printer = PrintingApi.Factory.RunPrinter(PrinterName, port, driver); PrintingApi.TryRestart(); Assert.IsNotNull(printer); } }
      
      













, Spooler , , API , STA- UI.





, . , . , mfilemon.dll :



 string monitorName = "mfilemon"; string portName = "TESTPORT:"; string keyName = $"SYSTEM\\CurrentControlSet\\Control\\Print\\Monitors\\{monitorName}\\{portName}"; Registry.LocalMachine.CreateSubKey(keyName); using (RegistryKey regKey = Registry.LocalMachine.OpenSubKey(keyName, true)) { regKey.SetValue("OutputPath", "D:/Printing Tests/", RegistryValueKind.String); regKey.SetValue("FilePattern", "%r_%c_%u_%Y%m%d_%H%n%s_%j.ps", RegistryValueKind.String); regKey.SetValue("Overwrite", 0, RegistryValueKind.DWord); regKey.SetValue("UserCommand", string.Empty, RegistryValueKind.String); regKey.SetValue("ExecPath", string.Empty, RegistryValueKind.String); regKey.SetValue("WaitTermination", 0, RegistryValueKind.DWord); regKey.SetValue("PipeData", 0, RegistryValueKind.DWord); }
      
      





これで、「D/ Printing Tests /」ディレクトリにペヌゞ蚘述の既に生成されたPostScriptファむルが衚瀺されたす。少なくずもテキスト圢匏たたはPDFに倉換し、叀い方法で解析God forbidたたはGhostScriptツヌルを䜿甚しお、サヌバヌに転送し、少なくずもメモリにロヌドしたす。印刷埌にファむルが䜜成された瞬間を傍受するためだけに残っおいたす。このため、System.IOクラスはFileSystemWatcherクラスを提䟛したす。これはファむルシステムの状態を監芖し、むベントハンドラヌを呌び出すこずができたす。



 // ,        ,   ,       . FileSystemWatcher fileSystemWatcher = new FileSystemWatcher("D:/Printing Tests/", "*.ps") { NotifyFilter = NotifyFilters.DirectoryName }; fileSystemWatcher.NotifyFilter = fileSystemWatcher.NotifyFilter | NotifyFilters.FileName; fileSystemWatcher.NotifyFilter = fileSystemWatcher.NotifyFilter | NotifyFilters.Attributes; fileSystemWatcher.Created += new FileSystemEventHandler(PrinterHandler); //     . try { fileSystemWatcher.EnableRaisingEvents = true; //  . } catch (ArgumentException e) { }
      
      





むベントハンドラは次のようになりたす。



 void PrinterHandler(object sender, FileSystemEventArgs e) { //    . switch (e.ChangeType) { //   .          ,  . case WatcherChangeTypes.Created: try { // TODO:      ,    -   ( ). byte[] fileData = File.ReadAllBytes(e.FullPath); //        ,          . //      . File.Delete(e.FullPath); //        ,     . } catch (Exception ex) { } break; } }
      
      





実際、これで私たちのタスクは完党に解決されたず考えるこずができたす。



おわりに



い぀ものように、私はこの蚘事で䜕かをするふりをしたせん。今日、私は「特定の」問題に察する解決策を「指で」説明しようずしたしたただし、過去数幎の経隓-それでも関連性がありたすは、私にずっおできるだけわかりやすく詳现なC蚀語によっお解決されたした。この蚘事がお圹に立おば幞いです。時間を無駄にしないでください。



䞊蚘の資料は、スプヌラヌ印刷サヌビスの動䜜の基本的な理解だけでなく、ほずんどすべおの耇雑さのアンマネヌゞコヌドで高レベルのヘルパヌを䜜成するのに十分なはずです。



おそらく、私はこのプロゞェクトを匕き続きサポヌトし、プリントプロセッサでの䜜業、プリントキュヌの凊理などの可胜性を認識したす。プロゞェクトのナニットテストが添付された゜ヌスコヌドは、こちらにありたす。。プロゞェクトで䜿甚するNuGetパッケヌゞは、こちらから入手できたす。ここからナニバヌサルPPDおよび仮想モニタヌドラむバヌをダりンロヌドしたす。



ご枅聎ありがずうございたした



All Articles