Discussion:
P/Invoked OpenPrinter fails when opening network printer
(too old to reply)
Marek
2005-06-29 21:41:04 UTC
Permalink
I have local printer connected to PC_1 (lpt/usb). It’s shared (no pwd, ACL
for printing is set to Everyone). I want to print data from PC_2, via
\\PC_1\<printerName>.

OpenPrinter and StartDocPrinter fail with GetLastError == 997
(ERROR_IO_PENDING - Overlapped I/O operation is in progress). I’m able to
recreate this problem on following configurations :

PC_1 = NT 4.0
PC_2 = W2k3

PC_1 = WXP
PC_2 = W2k3

Everything works fine when printing on local printer or via print server
(that is direct to printer, not through PC_1).

I’m using C# and .NET 1.1. I didn’t try to recreate this from C++ yet.

Any suggestions? Thank you for any given answer...

Here is my code (simplified):

public class PrintDirect
{
[DllImport("winspool.drv", CharSet = CharSet.Unicode, ExactSpelling = false,
CallingConvention = CallingConvention.StdCall)]
public static extern int OpenPrinter(string pPrinterName, out IntPtr
phPrinter, IntPtr pDefault);

[DllImport("winspool.drv", CharSet = CharSet.Unicode, ExactSpelling = false,
CallingConvention = CallingConvention.StdCall)]
public static extern int StartDocPrinter(IntPtr hPrinter, int Level, ref
DOCINFO pDocInfo);

[DllImport("winspool.drv", CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int StartPagePrinter(IntPtr hPrinter);

[DllImport("winspool.drv", CharSet = CharSet.Ansi, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int WritePrinter(IntPtr hPrinter, IntPtr pBuf, int buf,
ref int pcWritten);

[DllImport("winspool.drv", CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int EndPagePrinter(IntPtr hPrinter);

[DllImport("winspool.drv", CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int EndDocPrinter(IntPtr hPrinter);
[DllImport("winspool.drv", CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int ClosePrinter(IntPtr hPrinter);
}

[StructLayout(LayoutKind.Sequential)]
public struct DOCINFO
{
[MarshalAs(UnmanagedType.LPWStr)] public string pDocName;
[MarshalAs(UnmanagedType.LPWStr)] public string pOutputFile;
[MarshalAs(UnmanagedType.LPWStr)] public string pDataType;
}

System.IntPtr lhPrinter = new System.IntPtr();
DOCINFO di = new DOCINFO();
int pcWritten = 0;
byte[] textBytes;



di.pDocName = "Etk";
di.pOutputFile = null;
di.pDataType = null;

PrintDirect.OpenPrinter(printerName, out lhPrinter, new System.IntPtr(0));
PrintDirect.StartDocPrinter(lhPrinter, 1, ref di);
PrintDirect.StartPagePrinter(lhPrinter);
IntPtr buf = Marshal.AllocCoTaskMem(textBytes.Length);
Marshal.Copy(textBytes, 0, buf, textBytes.Length);
PrintDirect.WritePrinter(lhPrinter, buf, textBytes.Length, ref pcWritten);
PrintDirect.EndPagePrinter(lhPrinter);
PrintDirect.EndDocPrinter(lhPrinter);
PrintDirect.ClosePrinter(lhPrinter);
Marshal.FreeCoTaskMem(buf);


Willy Denoyette [MVP]
2005-06-29 22:35:07 UTC
Permalink
Don't call SetLastError, the error code is probably wrong or inconsistent
when doing this, use GetLastWin32Error instead.
You also have to indicate that you need the win32 error code returned from
the API, so you have to place the SetLastError=true attribute in your
DllImport declarartion.

Willy.
I have local printer connected to PC_1 (lpt/usb). It’s shared (no pwd,
ACL
for printing is set to Everyone). I want to print data from PC_2, via
\\PC_1\<printerName>.
OpenPrinter and StartDocPrinter fail with GetLastError == 997
(ERROR_IO_PENDING - Overlapped I/O operation is in progress). I’m able
to
PC_1 = NT 4.0
PC_2 = W2k3
PC_1 = WXP
PC_2 = W2k3
Everything works fine when printing on local printer or via print server
(that is direct to printer, not through PC_1).
I’m using C# and .NET 1.1. I didn’t try to recreate this from C++ yet.
Any suggestions? Thank you for any given answer...
public class PrintDirect
{
[DllImport("winspool.drv", CharSet = CharSet.Unicode, ExactSpelling = false,
CallingConvention = CallingConvention.StdCall)]
public static extern int OpenPrinter(string pPrinterName, out IntPtr
phPrinter, IntPtr pDefault);
[DllImport("winspool.drv", CharSet = CharSet.Unicode, ExactSpelling = false,
CallingConvention = CallingConvention.StdCall)]
public static extern int StartDocPrinter(IntPtr hPrinter, int Level, ref
DOCINFO pDocInfo);
[DllImport("winspool.drv", CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int StartPagePrinter(IntPtr hPrinter);
[DllImport("winspool.drv", CharSet = CharSet.Ansi, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int WritePrinter(IntPtr hPrinter, IntPtr pBuf, int buf,
ref int pcWritten);
[DllImport("winspool.drv", CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int EndPagePrinter(IntPtr hPrinter);
[DllImport("winspool.drv", CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int EndDocPrinter(IntPtr hPrinter);
[DllImport("winspool.drv", CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int ClosePrinter(IntPtr hPrinter);
}
[StructLayout(LayoutKind.Sequential)]
public struct DOCINFO
{
[MarshalAs(UnmanagedType.LPWStr)] public string pDocName;
[MarshalAs(UnmanagedType.LPWStr)] public string pOutputFile;
[MarshalAs(UnmanagedType.LPWStr)] public string pDataType;
}
System.IntPtr lhPrinter = new System.IntPtr();
DOCINFO di = new DOCINFO();
int pcWritten = 0;
byte[] textBytes;


di.pDocName = "Etk";
di.pOutputFile = null;
di.pDataType = null;
PrintDirect.OpenPrinter(printerName, out lhPrinter, new System.IntPtr(0));
PrintDirect.StartDocPrinter(lhPrinter, 1, ref di);
PrintDirect.StartPagePrinter(lhPrinter);
IntPtr buf = Marshal.AllocCoTaskMem(textBytes.Length);
Marshal.Copy(textBytes, 0, buf, textBytes.Length);
PrintDirect.WritePrinter(lhPrinter, buf, textBytes.Length, ref pcWritten);
PrintDirect.EndPagePrinter(lhPrinter);
PrintDirect.EndDocPrinter(lhPrinter);
PrintDirect.ClosePrinter(lhPrinter);
Marshal.FreeCoTaskMem(buf);


Marek
2005-06-30 09:09:02 UTC
Permalink
Thanks for reply.

I'm calling Marshal.GetLastWin32Error(), to obtaint error code. I didn't
have SetLastError = true attribute in my declaration, so I added it.

After adding SetLastError = true, OpenPrinter and ClosePrinter return 1
(OK), but all other funcs returns 0 and GetLastWin32Error returns 997. I
forgot to mention that my program is windows service running under account
with Administrative privileges. Any other suggestions? Thank you in advance!

Here is output from my program:

OpenPrinter : 1
StartDocPrinter : 0
StartDocPrinter_GetLast : 997
StartPagePrinter : 0
StartPagePrinter_GetLast : 997
WritePrinter : 0
WritePrinter_GetLast : 997
EndPagePrinter : 0
EndPagePrinter_GetLast : 997
EndDocPrinter : 0
EndDocPrinter_GetLast : 997
ClosePrinter : 1
Post by Willy Denoyette [MVP]
Don't call SetLastError, the error code is probably wrong or inconsistent
when doing this, use GetLastWin32Error instead.
You also have to indicate that you need the win32 error code returned from
the API, so you have to place the SetLastError=true attribute in your
DllImport declarartion.
Willy.
I have local printer connected to PC_1 (lpt/usb). It’s shared (no pwd,
ACL
for printing is set to Everyone). I want to print data from PC_2, via
\\PC_1\<printerName>.
OpenPrinter and StartDocPrinter fail with GetLastError == 997
(ERROR_IO_PENDING - Overlapped I/O operation is in progress). I’m able
to
PC_1 = NT 4.0
PC_2 = W2k3
PC_1 = WXP
PC_2 = W2k3
Everything works fine when printing on local printer or via print server
(that is direct to printer, not through PC_1).
I’m using C# and .NET 1.1. I didn’t try to recreate this from C++ yet.
Any suggestions? Thank you for any given answer...
public class PrintDirect
{
[DllImport("winspool.drv", CharSet = CharSet.Unicode, ExactSpelling = false,
CallingConvention = CallingConvention.StdCall)]
public static extern int OpenPrinter(string pPrinterName, out IntPtr
phPrinter, IntPtr pDefault);
[DllImport("winspool.drv", CharSet = CharSet.Unicode, ExactSpelling = false,
CallingConvention = CallingConvention.StdCall)]
public static extern int StartDocPrinter(IntPtr hPrinter, int Level, ref
DOCINFO pDocInfo);
[DllImport("winspool.drv", CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int StartPagePrinter(IntPtr hPrinter);
[DllImport("winspool.drv", CharSet = CharSet.Ansi, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int WritePrinter(IntPtr hPrinter, IntPtr pBuf, int buf,
ref int pcWritten);
[DllImport("winspool.drv", CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int EndPagePrinter(IntPtr hPrinter);
[DllImport("winspool.drv", CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int EndDocPrinter(IntPtr hPrinter);
[DllImport("winspool.drv", CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int ClosePrinter(IntPtr hPrinter);
}
[StructLayout(LayoutKind.Sequential)]
public struct DOCINFO
{
[MarshalAs(UnmanagedType.LPWStr)] public string pDocName;
[MarshalAs(UnmanagedType.LPWStr)] public string pOutputFile;
[MarshalAs(UnmanagedType.LPWStr)] public string pDataType;
}
System.IntPtr lhPrinter = new System.IntPtr();
DOCINFO di = new DOCINFO();
int pcWritten = 0;
byte[] textBytes;
…
di.pDocName = "Etk";
di.pOutputFile = null;
di.pDataType = null;
PrintDirect.OpenPrinter(printerName, out lhPrinter, new System.IntPtr(0));
PrintDirect.StartDocPrinter(lhPrinter, 1, ref di);
PrintDirect.StartPagePrinter(lhPrinter);
IntPtr buf = Marshal.AllocCoTaskMem(textBytes.Length);
Marshal.Copy(textBytes, 0, buf, textBytes.Length);
PrintDirect.WritePrinter(lhPrinter, buf, textBytes.Length, ref pcWritten);
PrintDirect.EndPagePrinter(lhPrinter);
PrintDirect.EndDocPrinter(lhPrinter);
PrintDirect.ClosePrinter(lhPrinter);
Marshal.FreeCoTaskMem(buf);
…
Marek
2005-06-30 19:47:08 UTC
Permalink
I think I've got it. It was a security issue. I mapped network printer to
newly created local port lpt2 on PC_2:

net use lpt2 \\PC_1\<printerName> /user:<userName>

Then I created local printer on PC_2 on lpt2 and everything works fine.
However not in WNT 4.0 scenario. There must be some problem with passing
credentials from W2k3 to NT 4.0, as I still got error 997 (on OpenPrinter)...
net use didn't help. Hmm....
Post by Marek
Thanks for reply.
I'm calling Marshal.GetLastWin32Error(), to obtaint error code. I didn't
have SetLastError = true attribute in my declaration, so I added it.
After adding SetLastError = true, OpenPrinter and ClosePrinter return 1
(OK), but all other funcs returns 0 and GetLastWin32Error returns 997. I
forgot to mention that my program is windows service running under account
with Administrative privileges. Any other suggestions? Thank you in advance!
OpenPrinter : 1
StartDocPrinter : 0
StartDocPrinter_GetLast : 997
StartPagePrinter : 0
StartPagePrinter_GetLast : 997
WritePrinter : 0
WritePrinter_GetLast : 997
EndPagePrinter : 0
EndPagePrinter_GetLast : 997
EndDocPrinter : 0
EndDocPrinter_GetLast : 997
ClosePrinter : 1
Post by Willy Denoyette [MVP]
Don't call SetLastError, the error code is probably wrong or inconsistent
when doing this, use GetLastWin32Error instead.
You also have to indicate that you need the win32 error code returned from
the API, so you have to place the SetLastError=true attribute in your
DllImport declarartion.
Willy.
I have local printer connected to PC_1 (lpt/usb). It’s shared (no pwd,
ACL
for printing is set to Everyone). I want to print data from PC_2, via
\\PC_1\<printerName>.
OpenPrinter and StartDocPrinter fail with GetLastError == 997
(ERROR_IO_PENDING - Overlapped I/O operation is in progress). I’m able
to
PC_1 = NT 4.0
PC_2 = W2k3
PC_1 = WXP
PC_2 = W2k3
Everything works fine when printing on local printer or via print server
(that is direct to printer, not through PC_1).
I’m using C# and .NET 1.1. I didn’t try to recreate this from C++ yet.
Any suggestions? Thank you for any given answer...
public class PrintDirect
{
[DllImport("winspool.drv", CharSet = CharSet.Unicode, ExactSpelling = false,
CallingConvention = CallingConvention.StdCall)]
public static extern int OpenPrinter(string pPrinterName, out IntPtr
phPrinter, IntPtr pDefault);
[DllImport("winspool.drv", CharSet = CharSet.Unicode, ExactSpelling = false,
CallingConvention = CallingConvention.StdCall)]
public static extern int StartDocPrinter(IntPtr hPrinter, int Level, ref
DOCINFO pDocInfo);
[DllImport("winspool.drv", CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int StartPagePrinter(IntPtr hPrinter);
[DllImport("winspool.drv", CharSet = CharSet.Ansi, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int WritePrinter(IntPtr hPrinter, IntPtr pBuf, int buf,
ref int pcWritten);
[DllImport("winspool.drv", CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int EndPagePrinter(IntPtr hPrinter);
[DllImport("winspool.drv", CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int EndDocPrinter(IntPtr hPrinter);
[DllImport("winspool.drv", CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int ClosePrinter(IntPtr hPrinter);
}
[StructLayout(LayoutKind.Sequential)]
public struct DOCINFO
{
[MarshalAs(UnmanagedType.LPWStr)] public string pDocName;
[MarshalAs(UnmanagedType.LPWStr)] public string pOutputFile;
[MarshalAs(UnmanagedType.LPWStr)] public string pDataType;
}
System.IntPtr lhPrinter = new System.IntPtr();
DOCINFO di = new DOCINFO();
int pcWritten = 0;
byte[] textBytes;
…
di.pDocName = "Etk";
di.pOutputFile = null;
di.pDataType = null;
PrintDirect.OpenPrinter(printerName, out lhPrinter, new System.IntPtr(0));
PrintDirect.StartDocPrinter(lhPrinter, 1, ref di);
PrintDirect.StartPagePrinter(lhPrinter);
IntPtr buf = Marshal.AllocCoTaskMem(textBytes.Length);
Marshal.Copy(textBytes, 0, buf, textBytes.Length);
PrintDirect.WritePrinter(lhPrinter, buf, textBytes.Length, ref pcWritten);
PrintDirect.EndPagePrinter(lhPrinter);
PrintDirect.EndDocPrinter(lhPrinter);
PrintDirect.ClosePrinter(lhPrinter);
Marshal.FreeCoTaskMem(buf);
…
Loading...