SteveYau
1/31/2007 8:05:00 AM
Hi There,
I tried a simple VB.Net console program that uses win32 api call on
WinSpool.drv to query a local or remote printer's sharing status. The API
calls I used are OpenPrinter, GetPrinter and ClosePrinter. The program runs
perfectly on x86 32-bit platform.
However, when I compile the same program on a x64 Windows Server 2003 R2
Ent. and run it (with only slight modification on printer name), it caused a
FatalExecutionEngineError. On VS2005 debug windows, it showed:
---
The error code is 0xC0000005. This error may be a bug in the CLR or in the
unsafe or non-verifiable portions of user code. Common sources of this bug
include user marshaling errors for COM-interop or PInvoke, which may corrupt
the stack.
---
And in Application eventlog, a ".NET RunTime" event 1023 ".NET Runtime
version 2.0.50727.63 - Fatal Execution Engine Error (000006427F880608)
(80131506)" was logged.
Here I attach this small program. Line 116, the second invocation of
GetPrinter, is the place where .Net engine failed.
Grateful if any experts here can give me some hints.
Thanks
Steve
----- Attached sample code ---
Imports System.Runtime.InteropServices
Module Module1
Const PRINTER_ATTRIBUTE_SHARED As Integer = &H8
Const ERROR_INSUFFICIENT_BUFFER As Integer = &H7A
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _
Structure PRINTER_INFO_2W
<MarshalAs(UnmanagedType.LPWStr)> Public pServerName As String
<MarshalAs(UnmanagedType.LPWStr)> Public pPrinterName As String
<MarshalAs(UnmanagedType.LPWStr)> Public pShareName As String
<MarshalAs(UnmanagedType.LPWStr)> Public pPortName As String
<MarshalAs(UnmanagedType.LPWStr)> Public pDriverName As String
<MarshalAs(UnmanagedType.LPWStr)> Public pComment As String
<MarshalAs(UnmanagedType.LPWStr)> Public pLocation As String
Public pDevMode As IntPtr
<MarshalAs(UnmanagedType.LPWStr)> Public pSepFile As String
<MarshalAs(UnmanagedType.LPWStr)> Public pPrintProcessor As String
<MarshalAs(UnmanagedType.LPWStr)> Public pDataType As String
<MarshalAs(UnmanagedType.LPWStr)> Public pParameter As String
Public pSecurityDescriptor As IntPtr
Public Attributes As Integer
Public Priority As Integer
Public DefaultPriority As Integer
Public StartTime As Integer
Public UntilTime As Integer
Public Status As Integer
Public cJobs As Integer
Public AveragePPM As Integer
End Structure
<DllImport("winspool.Drv", EntryPoint:="OpenPrinterW", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Function OpenPrinter(ByVal src As String, _
ByRef hPrinter As IntPtr, ByVal pd As Integer) As Boolean
End Function
<DllImport("winspool.Drv", EntryPoint:="ClosePrinter", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Function ClosePrinter(ByVal hPrinter As IntPtr) As Integer
End Function
<DllImport("winspool.Drv", EntryPoint:="GetPrinterW", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Function GetPrinter(ByVal hPrinter As IntPtr, ByVal Level As Integer, _
ByRef pPrinter As Byte, ByVal cbBuf As Integer, ByRef pcbNeeded As
Integer _
) As Integer
End Function
Sub Main()
Dim buf() As Byte
Dim BytesWritten, ByteLength, rc, DLLErrCode As Integer
Dim bufptr As IntPtr = IntPtr.Zero
Dim bResult As Boolean
Dim pPrinter_Info As PRINTER_INFO_2W
Dim PrintHandle As IntPtr = IntPtr.Zero
Console.WriteLine("Trying to OpenPrinter [\\CCZ166\CCL12]")
' check to see if the printer can be opened.
rc = OpenPrinter("\\CCZ166\CCL12", PrintHandle, 0)
If rc = 0 Then
Console.WriteLine("Cannot OpenPrinter [\\CCZ166\CCL12] Error = [" &
Err.LastDllError & "]")
Exit Sub
End If
Console.WriteLine("Printer [CCL12] Found. Checking Shared Status... ")
ReDim buf(1)
' check to get printer information, pass no buffer and ask for return
buffer size
rc = GetPrinter(PrintHandle, 2, buf(0), 0, BytesWritten)
If rc = 0 Then
DLLErrCode = Err.LastDllError
' Expected to get ERROR_INSUFFICIENT_BUFFER return code
If DLLErrCode <> ERROR_INSUFFICIENT_BUFFER Then
Console.WriteLine("Cannot GetPrinter [CCL12] DLL Error = [" &
DLLErrCode & "]")
ClosePrinter(PrintHandle)
Exit Sub
End If
End If
Console.WriteLine("First GetPrinter Called... BytesWritten = [" &
BytesWritten.ToString & "]")
With pPrinter_Info
.pServerName = ""
.pPrinterName = ""
.pShareName = ""
.pPortName = ""
.pDriverName = ""
.pComment = ""
.pLocation = ""
.pDevMode = IntPtr.Zero
.pSepFile = ""
.pPrintProcessor = ""
.pDataType = ""
.pParameter = ""
.pSecurityDescriptor = IntPtr.Zero
.Attributes = 0
.Priority = 0
.DefaultPriority = 0
.StartTime = 0
.UntilTime = 0
.Status = 0
.cJobs = 0
.AveragePPM = 0
End With
ByteLength = BytesWritten
ReDim buf(ByteLength - 1)
' Get Printer Info and store it in buf
Console.WriteLine("Second GetPrinter Calling... ")
rc = GetPrinter(PrintHandle, 2, buf(0), ByteLength, BytesWritten)
Console.WriteLine("Second GetPrinter Called... ")
If rc = 0 Then
' Unexpected GetPrinter Error
Console.WriteLine("Cannot GetPrinter [CCL12] DLL Error = " & _
Err.LastDllError)
ClosePrinter(PrintHandle)
Exit Sub
End If
' Allocate memory and parse the buffer
Try
bufptr = Marshal.AllocCoTaskMem(ByteLength)
Marshal.Copy(buf, 0, bufptr, ByteLength)
pPrinter_Info = CType(Marshal.PtrToStructure(bufptr,
GetType(PRINTER_INFO_2W)), _
PRINTER_INFO_2W)
Marshal.FreeCoTaskMem(bufptr)
Catch ex As Exception
Console.WriteLine("Unable to marshal PRINTER_INFO_2. ")
ClosePrinter(PrintHandle)
Exit Sub
End Try
' Check whether the printer is shared
bResult = (pPrinter_Info.Attributes And PRINTER_ATTRIBUTE_SHARED)
ClosePrinter(PrintHandle)
If bResult Then
Console.WriteLine("Printer [CCL12] found and shared. ")
Else
Console.WriteLine("Printer [CCL12] found but not shared.")
End If
End Sub
End Module