.NET Forum / Languages / VB.NET / March 2008
thrown exception in Marshal.PtrToStructure
|
|
Thread rating:  |
Stephanie Doherty - 26 Mar 2008 13:28 GMT Hello World,
I am trying to read an intptr() returned from a call to EnumPrinters into a structure and keep getting an exception. The relevant code looks like:
Public Structure pInfo <MarshalAs(UnmanagedType.LPStr)> Dim flags As String <MarshalAs(UnmanagedType.LPStr)> Dim pDescription As String <MarshalAs(UnmanagedType.LPStr)> Dim pName As String <MarshalAs(UnmanagedType.LPStr)> Dim pComment As String End Structure
<DllImport("winspool.drv", EntryPoint:="EnumPrinters", _ SetLastError:=True, CharSet:=CharSet.Unicode)> Public Shared Function _ EnumPrinters(ByVal flags As Int32, ByVal pName As String, ByVal Level _ As Int32, ByVal pPrinterEnum As IntPtr, ByVal cbBuf As Int32, ByRef _ pcbNeeded As Int32, ByRef pcReturned As Int32) As Int32 End Function
selectedItem = "\\" & CmB_Servers.SelectedItem server = selectedItem.ToString() EnumPrinters(flag, server, PRINTER_LEVEL_1, outC, 0, pcbNeeded, pcReturned) outC = Marshal.AllocHGlobal(pcbNeeded + 1) If EnumPrinters(flag, server, PRINTER_LEVEL_1, outC, pcbNeeded, pcbNeeded, pcReturned) > 0 Then
Dim manyPr As pInfo Dim currentP As IntPtr = outC Dim i As Integer
For i = 1 To pcReturned
manyPr = Marshal.PtrToStructure(currentP, manyPr.GetType()) CmB_Printers.Items.Add(manyPr.pName) currentP = IntPtr.op_Explicit(currentP.ToInt32 + Marshal.SizeOf(manyPr.GetType)) Next Else MsgBox("unable to get printers") End If Marshal.FreeHGlobal(outC)
---- The exception thrown is: Object reference not set to an instance of an object I assume that is referring to the manyPr variable, but am not sure what I should be doing about it.
Help!
Thanks, Stephanie
Bill McCarthy - 26 Mar 2008 13:57 GMT First, turn on Option Strict, then try this :
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _ Public Structure pInfo <MarshalAs(UnmanagedType.LPTStr)> Dim flags As String <MarshalAs(UnmanagedType.LPTStr)> Dim pDescription As String <MarshalAs(UnmanagedType.LPTStr)> Dim pName As String <MarshalAs(UnmanagedType.LPTStr)> Dim pComment As String End Structure
<DllImport("winspool.drv", EntryPoint:="EnumPrintersW", _ SetLastError:=True, CharSet:=CharSet.Unicode)> Public Function _ EnumPrinters(ByVal flags As Int32, ByVal pName As String, ByVal Level _ As Int32, ByVal pPrinterEnum As IntPtr, ByVal cbBuf As Int32, ByRef _ pcbNeeded As Int32, ByRef pcReturned As Int32) As Int32 End Function
For i = 1 To pcReturned
manyPr = CType(Marshal.PtrToStructure(currentP, GetType(pInfo)), pInfo) CmB_Printers.Items.Add(manyPr.pName) currentP = IntPtr.op_Explicit(currentP.ToInt32 + Marshal.SizeOf(GetType(pInfo))) Next
> Hello World, > [quoted text clipped - 50 lines] > Thanks, > Stephanie Stephanie Doherty - 26 Mar 2008 18:18 GMT Thank you for your suggestion,Bill. Unfortunately this throws an exception (Error: PInvoke item (field,method) must be Static.) in the first call to EnumPrinter.
The definitions for the variables in that call are: Public Const PRINTER_ENUM_SHARED As Int32 = 20 Public Const PRINTER_ENUM_NAME As Int32 = 8 Public Const PRINTER_LEVEL_1 As Int32 = 1 Dim pcbNeeded As Int32 = 0 Dim pcReturned As Int32 = 0 Dim flag As Int32 = PRINTER_ENUM_NAME Or PRINTER_ENUM_SHARED
What did I miss? Stephanie
> First, turn on Option Strict, then try this : > [quoted text clipped - 76 lines] > > Thanks, > > Stephanie Bill McCarthy - 26 Mar 2008 18:34 GMT Mark the API declaration for EnumPrinters as Shared, or place it in a Module
> Thank you for your suggestion,Bill. Unfortunately this throws an exception > (Error: PInvoke item (field,method) must be Static.) in the first call to [quoted text clipped - 95 lines] >> > Thanks, >> > Stephanie Stephanie Doherty - 26 Mar 2008 19:38 GMT Ok. Setting the EnumPrinters function as Shared fixed that exception. However, once past that, I am still getting the original exception (Object reference not set to an instance of an object) for the line:
manyPr = Marshal.PtrToStructure(currentP, manyPr.GetType())
> Mark the API declaration for EnumPrinters as Shared, or place it in a Module > [quoted text clipped - 97 lines] > >> > Thanks, > >> > Stephanie Bill McCarthy - 26 Mar 2008 19:41 GMT go back and read the code in my first reply
> Ok. Setting the EnumPrinters function as Shared fixed that exception. > However, once past that, I am still getting the original exception (Object [quoted text clipped - 115 lines] >> >> > Thanks, >> >> > Stephanie Stephanie Doherty - 26 Mar 2008 19:56 GMT I believe I already did. Unless I missed something, my changes should have consisted of adding the line: StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _
changing the declaration for EnumPrinters to: <DllImport("winspool.drv", EntryPoint:="EnumPrintersW", _
and the code for the line that causes the exception to: manyPr = CType(Marshal.PtrToStructure(currentP, GetType(pInfo)), pInfo)
plus the substitution a couple of lines later to: currentP = IntPtr.op_Explicit(currentP.ToInt32 + Marshal.SizeOf((GetType(pInfo))))
but I'm still getting the exception.
> go back and read the code in my first reply > [quoted text clipped - 117 lines] > >> >> > Thanks, > >> >> > Stephanie Bill McCarthy - 26 Mar 2008 20:03 GMT and change the strings to UnmanagedType.LPTStr
>I believe I already did. Unless I missed something, my changes should have > consisted of adding the line: [quoted text clipped - 147 lines] >> >> >> > Thanks, >> >> >> > Stephanie Stephanie Doherty - 26 Mar 2008 20:09 GMT Did that too.
> and change the strings to UnmanagedType.LPTStr > [quoted text clipped - 149 lines] > >> >> >> > Thanks, > >> >> >> > Stephanie Bill McCarthy - 26 Mar 2008 20:13 GMT post your complete code.
> Did that too. > [quoted text clipped - 166 lines] >> >> >> >> > Thanks, >> >> >> >> > Stephanie Stephanie Doherty - 26 Mar 2008 20:23 GMT Here goes:
Option Strict On Imports System Imports System.IO Imports System.Text Imports System.Runtime.InteropServices Imports System.ComponentModel Imports System.Management
Public Class Form1 Inherits System.Windows.Forms.Form Public Const PRINTER_ENUM_SHARED As Int32 = 20 Public Const PRINTER_ENUM_NAME As Int32 = 8 Public Const PRINTER_LEVEL_1 As Int32 = 1 <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _ Public Structure pInfo <MarshalAs(UnmanagedType.LPStr)> Dim flags As String <MarshalAs(UnmanagedType.LPStr)> Dim pDescription As String <MarshalAs(UnmanagedType.LPStr)> Dim pName As String
<DllImport("winspool.drv", EntryPoint:="EnumPrintersW", _ SetLastError:=True, CharSet:=CharSet.Unicode)> Public Shared Function _ EnumPrinters(ByVal flags As Int32, ByVal pName As String, ByVal Level _ As Int32, ByVal pPrinterEnum As IntPtr, ByVal cbBuf As Int32, ByRef _ pcbNeeded As Int32, ByRef pcReturned As Int32) As Int32 End Function Public Sub getServerPrinters() Dim pcbNeeded As Int32 = 0 Dim pcReturned As Int32 = 0 Dim outC As IntPtr = IntPtr.Zero Dim flag As Int32 = PRINTER_ENUM_NAME Or PRINTER_ENUM_SHARED Dim selectedItem As Object Dim server As String Dim status As Int32
selectedItem = "\\" + CmB_Servers.SelectedItem.ToString server = selectedItem.ToString() EnumPrinters(flag, server, PRINTER_LEVEL_1, outC, 0, pcbNeeded, pcReturned) outC = Marshal.AllocHGlobal(pcbNeeded + 1) If EnumPrinters(flag, server, PRINTER_LEVEL_1, outC, pcbNeeded, pcbNeeded, pcReturned) > 0 Then
Dim manyPr As pInfo Dim currentP As IntPtr = outC Dim i As Integer
For i = 1 To pcReturned
manyPr = CType(Marshal.PtrToStructure(currentP, GetType(pInfo)), pInfo) CmB_Printers.Items.Add(manyPr.pName) currentP = IntPtr.op_Explicit(currentP.ToInt32 + Marshal.SizeOf((GetType(pInfo)))) Next Else MsgBox("unable to get printers") End If Marshal.FreeHGlobal(outC)
End Sub ... End Class
> post your complete code. > [quoted text clipped - 168 lines] > >> >> >> >> > Thanks, > >> >> >> >> > Stephanie Bill McCarthy - 26 Mar 2008 20:36 GMT You have the structure declared wrong. Note it should be LPTStr, not LPStr on each of the four fields. See my first reply again.
> Here goes: > [quoted text clipped - 253 lines] >> >> >> >> >> > Thanks, >> >> >> >> >> > Stephanie Stephanie Doherty - 26 Mar 2008 20:43 GMT I'm afraid that doesn't do it either.
> You have the structure declared wrong. Note it should be LPTStr, not LPStr > on each of the four fields. See my first reply again. [quoted text clipped - 256 lines] > >> >> >> >> >> > Thanks, > >> >> >> >> >> > Stephanie Bill McCarthy - 26 Mar 2008 21:02 GMT try this :
Option Strict On Imports System Imports System.IO Imports System.Text Imports System.Runtime.InteropServices Imports System.ComponentModel Imports System.Management
Public Class Form1 Inherits System.Windows.Forms.Form
Public Const PRINTER_ENUM_SHARED As Int32 = 20 Public Const PRINTER_ENUM_NAME As Int32 = 8 Public Const PRINTER_LEVEL_1 As Int32 = 1
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _ Public Structure pInfo Dim flags As Int32 <MarshalAs(UnmanagedType.LPTStr)> Dim pDescription As String <MarshalAs(UnmanagedType.LPTStr)> Dim pName As String <MarshalAs(UnmanagedType.LPTStr)> Dim pComment As String End Structure
<DllImport("winspool.drv", EntryPoint:="EnumPrintersW", _ SetLastError:=True, CharSet:=CharSet.Unicode)> Public Shared Function _ EnumPrinters(ByVal flags As Int32, ByVal pName As String, ByVal Level _ As Int32, ByVal pPrinterEnum As IntPtr, ByVal cbBuf As Int32, ByRef _ pcbNeeded As Int32, ByRef pcReturned As Int32) As Int32 End Function
Public Sub getServerPrinters() Dim pcbNeeded As Int32 = 0 Dim pcReturned As Int32 = 0 Dim outC As IntPtr = IntPtr.Zero Dim flag As Int32 = PRINTER_ENUM_NAME Or PRINTER_ENUM_SHARED Dim server As String
server = "\\" & My.Computer.Name ' add code here for server name EnumPrinters(flag, server, PRINTER_LEVEL_1, outC, 0, pcbNeeded, pcReturned)
outC = Marshal.AllocHGlobal(pcbNeeded)
If EnumPrinters(flag, server, PRINTER_LEVEL_1, outC, pcbNeeded, pcbNeeded, pcReturned) > 0 Then
Dim manyPr As pInfo Dim currentP As IntPtr = outC Dim i As Integer
For i = 1 To pcReturned
manyPr = CType(Marshal.PtrToStructure(currentP, GetType(pInfo)), pInfo) Debug.Print(manyPr.pName) currentP = IntPtr.op_Explicit(currentP.ToInt32 + Marshal.SizeOf((GetType(pInfo)))) Next Else MsgBox("unable to get printers") End If Marshal.FreeHGlobal(outC)
End Sub
Stephanie Doherty - 27 Mar 2008 12:32 GMT That worked perfectly! I was then able to make the substitutions for my system and it's all good. Thank you so much, Bill.
Stpehanie
> try this : > [quoted text clipped - 62 lines] > > End Sub Bill McCarthy - 27 Mar 2008 14:47 GMT Glad I could help :)
> That worked perfectly! I was then able to make the substitutions for my > system and it's all good. Thank you so much, Bill. [quoted text clipped - 68 lines] >> >> End Sub
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|