Print
Introduction
Some time ago for customers to develop a set of printer software, in C # to call the printer did some research.
---------------------------------------------
Problem
The. Net Framework 1.1 provides us with a PrinterSettings class that provides information about how documents are printed, including printers that print documents. Where the static properties InstalledPrinters allows us to get the names of all the printers installed on the computer.
Unfortunately, this property is only able to provide the name of the installed printer. There is nothing you can do to get information about the printer, such as the type of printer. The problem arises because the customer is unable to provide the printer's SDK, so the filtering of the printer (which, for commercial purposes, the customer requires the software to output only when using their printer) can only be achieved through printer-driven identification.
----------------------------------------------
Solution one uses WMI to get printer information
WMI, the full name of Windows Management instrumentation. is a scalable system management architecture that employs a unified, standards-based, extensible object-oriented interface. WMI provides you with a standard way to interact with system management information and the underlying WMI API. WMI is used primarily by system management application developers and administrators to access and operating system management information.
The System.Management class in the. Net Framework provides support for WMI, where ManagementObjectSearcher is used to retrieve ManagementObject or A collection of ManagementClass objects.
/**////<summary>
Code 1:WMI Search Sample
<summary>
<param name= "Strdrivername" > Driver name </param>
<returns> return to the list of found printers </returns>
<remarks>strdrivername supports "%" and "_" wildcard queries, similar to queries in SQL statements <remarks>
Public StringCollection getprintswithdrivername (string strdrivername)
{
StringCollection scprinters = new StringCollection ();
String strcheck = "";
if (strdrivername!= "" && strdrivername!= "*")
Strcheck = "where drivername like \" + Strdrivername + "\";
String searchquery = "Select Name from Win32_Printer" + Strcheck;
ManagementObjectSearcher searchprinters =
New ManagementObjectSearcher (SearchQuery);
Managementobjectcollection printercollection = Searchprinters.get ();
foreach (ManagementObject printer in printercollection)
{
String printname = printer. properties["Name"]. Value.tostring ();
Scprinters.add (Printname);
}
Searchprinters.dispose ();
Printercollection.dispose ();
return scprinters;
}
The problem seems to be basically solved, and the running program does get the correct list of printers. But it took a while for the user to find out that sometimes the printer was not getting it right, and it seems that dotnet has a problem calling WMI stability ...
WMI itself is still quite powerful, with a VBS that basically covers the most basic operations of Windows. The MSDN documentation is available in detail.
Http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/wmi_start_page.asp
-------------------------------------------
Solution two use Win32API to get the printer
Turn around, and back to Win32API come up, helpless ah ... No wonder C + + still so popular ah ...
. NET provides us with DllImport to operate unmanaged DLLs (see C # so strong AH ~ ~ ~ ~ Secretly laugh).
The main use of the EnumPrinters function in Winspool.drv, the code is as follows:
[DllImport ("winspool.drv", SetLastError = true, CharSet = CharSet.Auto)]
[Return:marshalas (Unmanagedtype.bool)]
private static extern bool EnumPrinters ([MarshalAs (UNMANAGEDTYPE.U4)] Printer_enum flags,
[MarshalAs (UNMANAGEDTYPE.LPSTR)] string sname,
UINT Ilevel,
IntPtr Pprinterdesc,
UINT Isize,
[MarshalAs (UNMANAGEDTYPE.U4)] ref UINT ineeded,
[MarshalAs (UNMANAGEDTYPE.U4)] ref UINT ireturned
);
Description: The Marshal property provides marshaling of data to managed and unmanaged code.
The EnumPrinters WIN32 API is defined as follows:
BOOL EnumPrinters (
DWORD Flags,//Printer object types
LPTSTR name,//Name of printer object
DWORD level,//information level
Lpbyte Pprinterenum,//printer information buffer
DWORD cbbuf,//size of printer information buffer
Lpdword pcbneeded,//bytes received or required
Lpdword pcreturned//Number of printers enumerated
);
Problem again, enumprinters through level to get printer_info, and can get printer driver is printer_info_2, and C # without printer_info_2 structure, I began to faint again ...
Search for half a day of data, the Internet is basically the definition of printer_info_1, and printer_info_2 different and printer_info_1, which also includes DEVMODE structure, unmanaged structure of the structure, I began to drift ~ ~ ~ ~
Finally it is found that instead of defining structures in C # to correspond to unmanaged structures, it is better to replace them directly with classes. So two classes are defined
Printer_info_2 and DEVMODE (note: Because the DEVMODE structure is used in printer_info_2 to receive printer-driven information, only this class is defined and no other classes are implemented specifically).
In Printer_info_2, for all DWORD type data, all correspond to the Int32 type, and all LPTStr, Lpdevmode, and Psecurity_descriptor correspond to the IntPtr pointer type.
To get the data in unmanaged, use a function to get the printer information
.
Printer_info_2 pi = new Printer_info_2 ();
Transferring data from unmanaged memory to managed memory
for (int i = 0; i < numprinters; i++)
{
Marshal.PtrToStructure (Prinfo, pi); Prinfo is the printer obtained from the enumprinters above
String driver = Marshal.ptrtostringauto (pi.pdrivername);
if (PrinterDriver = = "" | | Driver. ToLower (). IndexOf (PrinterDriver)!=-1)
{
Do the related processing
}
Prinfo = new IntPtr (Prinfo.toint32 () + marshal.sizeof (typeof (Printer_info_2))); Get start of next printer information segment
}
.
The problem is basically solved. However, the call to unmanaged functions in C #, and the data encapsulation between each other, is a difficult place, and it needs to be sorted out.
Article Source: Http://spaces.msn.com/sharkoo/Blog/cns!D8E832CE4545AF!158.entry
Add: In 2.0, the fixed keyword can be used to define a fixed-size array cache, rather than to define a numeric size as in 1.x. However, this approach can only be used for structs (struct) and not for classes (class) definitions.