Groups | Blog | Home
all groups > dotnet interop > april 2004 >

dotnet interop : SetPrinter Call


Frank Jones
4/23/2004 4:51:02 PM
We are trying to pause a printer from C# or VB code using the Win32 printer API's in the winspool.drv. We are having varying degrees of success. With the following VB code, the OpenPrinter call works, but we get an access denied error message upon calling SetPrinter. I have auditing turned on the printer and get no failure audits, so it is hard to imagine that this error message is correct

Dim strPrinterName As Strin
strPrinterName = "Translator Image Printer

Dim lngReturn As Lon
Dim hPrinter As Lon
Dim printDefaults As PRINTER_DEFAULT

printDefaults.DesiredAccess = PRINTER_ALL_ACCES

lngReturn = OpenPrinterA(strPrinterName, hPrinter, printDefaults
If lngReturn <> 1 Or Err.LastDllError <> 0 The
MsgBox "Could not open printer!
En
End I

lngReturn = SetPrinterA(hPrinter, 0, 0, PrinterControlCodes.PrinterControlPause
If lngReturn <> 1 Or Err.LastDllError <> 0 The
Dim LangOptions As Lon
LangOptions = &H
Dim buffer As Strin
buffer = Space(256
lngReturn = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0&, Err.LastDllError, LangOptions, buffer, Len(buffer), 0&
MsgBox "Could not set printer: " & buffe
End I

lngReturn = ClosePrinter(hPrinter
If lngReturn <> 1 The
MsgBox "Could not close printer!
End I

In the C# world, we cannot even get the OpenPrinter call to work. It always returns with 0 and the Marshal.GetLastWin32Error() returns 87. The following C# code is where we are having issues

string printerName = "Translator Image Printer"
PrinterDefaults defaults = new PrinterDefaults()
defaults.DesiredAccess = PrinterAccessRights.PRINTER_ALL_ACCESS

int printerHandle = 0
int returnValue = OpenPrinterA(printerName, printerHandle, defaults)
if (returnValue == 1
Assert.AreEqual(0, Marshal.GetLastWin32Error(), String.Format("Marshal error #{0}: Could not open printer {1}", Marshal.GetLastWin32Error(), printerName))
els
Assert.Fail(String.Format("Last error: {0}", Marshal.GetLastWin32Error()))

returnValue = SetPrinterA(printerHandle, 0, 0, PrinterControlCommands.PRINTER_CONTROL_PAUSE); //(both Level and Buffer are empty to send commands
if (returnValue == 1
Assert.AreEqual(0, Marshal.GetLastWin32Error(), String.Format("Marshal error #{0}: Could not set printer {1}", Marshal.GetLastWin32Error(), printerName))

returnValue = ClosePrinter(printerHandle)
if (returnValue == 1
Assert.AreEqual(0, Marshal.GetLastWin32Error(), String.Format("Marshal error #{0}: Could not close printer {1}", Marshal.GetLastWin32Error(), printerName))

Mainly, we are interested in getting the C# code to work, and used the VB code to troubleshoot the OpenPrinter/SetPrinter issues. Any ideas on what to checkout would be greatly appreciated..

Thanks
v-yiy NO[at]SPAM online.microsoft.com (
4/26/2004 6:17:06 AM
Hi frank,

You may try the following C# snippet, it could open the "Microsoft Office
Document Image Writer" on my system. For the "Access Denied" issue, I'm not
clear about the reason, but if the problem also occurred on VB6, I think
it's probably not caused by interop. would you meet this problem if you run
this problem as administrator and then open a local printer ?

Thanks.

<code>
private void button1_Click(object sender, System.EventArgs e)
{
string printerName = "Microsoft Office Document Image Writer";
PrinterDefaults defaults = new PrinterDefaults();
defaults.DesiredAccess = PrinterAccess.PrinterAllAccess;

IntPtr printerHandle;
int returnValue = OpenPrinter(printerName, out printerHandle, ref
defaults);
if ( 1 == returnValue)
{
Debug.WriteLine(printerHandle.ToInt32().ToString());
ClosePrinter(printerHandle);
}
else
{
Debug.WriteLine(Marshal.GetLastWin32Error());
}
}


public enum PrinterAccess
{
//from winspool.h
ServerAdmin = 0x01,
ServerEnum = 0x02,
PrinterAdmin = 0x04,
PrinterUse = 0x08,
JobAdmin = 0x10,
JobRead = 0x20,
StandardRightsRequired = 0x000f0000, // from winnt.h
PrinterAllAccess = (StandardRightsRequired | PrinterAdmin | PrinterUse)
}

[StructLayout(LayoutKind.Sequential)]
public struct PrinterDefaults
{
public IntPtr pDataType;// In this scenario, these two fields are not
used
public IntPtr pDevMode;
public PrinterAccess DesiredAccess;
}

[DllImport("winspool.drv")]
private static extern int OpenPrinter(string printerName,out IntPtr
phPrinter, ref PrinterDefaults printerDefaults);

[DllImport("winspool.drv")]
public static extern int ClosePrinter(IntPtr phPrinter);
</code>

Best regards,

Ying-Shen Yu [MSFT]
Microsoft Community Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, please remove the word "online"
before sending mail.
Frank Jones
4/26/2004 2:16:02 PM
Hi Ying, this code snippet works great. In general, what is the best way to translate the Win32 API's into C# declares? I see so many examples on the internet showing incorrect declares. How can I tell, for example, to use IntPtr in the ClosePrinter call instead of a general int? How do I know when it's by reference or by an out parameter? Do you have a document describing Win32 API call from C# in depth that will cover these issues

Thanks
Fran

----- "Ying-Shen Yu[MSFT]" wrote: ----

Hi frank

You may try the following C# snippet, it could open the "Microsoft Office
Document Image Writer" on my system. For the "Access Denied" issue, I'm not
clear about the reason, but if the problem also occurred on VB6, I think
it's probably not caused by interop. would you meet this problem if you run
this problem as administrator and then open a local printer

Thanks

<code
private void button1_Click(object sender, System.EventArgs e

string printerName = "Microsoft Office Document Image Writer"
PrinterDefaults defaults = new PrinterDefaults()
defaults.DesiredAccess = PrinterAccess.PrinterAllAccess

IntPtr printerHandle
int returnValue = OpenPrinter(printerName, out printerHandle, ref
defaults)
if ( 1 == returnValue

Debug.WriteLine(printerHandle.ToInt32().ToString())
ClosePrinter(printerHandle)

else

Debug.WriteLine(Marshal.GetLastWin32Error())




public enum PrinterAcces

//from winspool.
ServerAdmin = 0x01
ServerEnum = 0x02
PrinterAdmin = 0x04
PrinterUse = 0x08
JobAdmin = 0x10
JobRead = 0x20
StandardRightsRequired = 0x000f0000, // from winnt.
PrinterAllAccess = (StandardRightsRequired | PrinterAdmin | PrinterUse


[StructLayout(LayoutKind.Sequential)
public struct PrinterDefault

public IntPtr pDataType;// In this scenario, these two fields are not
use
public IntPtr pDevMode
public PrinterAccess DesiredAccess


[DllImport("winspool.drv")
private static extern int OpenPrinter(string printerName,out IntPtr
phPrinter, ref PrinterDefaults printerDefaults)

[DllImport("winspool.drv")
public static extern int ClosePrinter(IntPtr phPrinter)
</code

Best regards,

Ying-Shen Yu [MSFT
Microsoft Community Suppor
Get Secure! - www.microsoft.com/securit

This posting is provided "AS IS" with no warranties and confers no rights
This mail should not be replied directly, please remove the word "online"
before sending mail

v-yiy NO[at]SPAM online.microsoft.com (
4/27/2004 2:09:10 AM
Hi Frank,

I agree with you, to define a correct P/invoke definition for real
scenario is not an easy job. Many issues may affect the final P/Invoke
definition, such as memory allocation, data marshalling, and the default
behavior of CLR marshaler etc.

Here is an article which gives an in-depth overview on the .NET interop.
"An Overview of Managed/Unmanaged Code Interoperability"
http://msdn.microsoft.com/netframework/default.aspx?pull=/library/en-us/dndo
tnet/html/manunmancode.asp

For more in-depth information on P/Invoke as well as COM Interop. I
recommend you read the book <.NET and COM: The Complete Interoperability
Guide> by Adam Nathan.
http://www.amazon.com/exec/obidos/ASIN/067232170X/102-9869026-1349709

And you may reach him at his blog:
http://blogs.msdn.com/adam_nathan

Thanks, wish you good luck!

Best regards,

Ying-Shen Yu [MSFT]
Microsoft Community Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, please remove the word "online"
before sending mail.
AddThis Social Bookmark Button