Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Languages / VB.NET / March 2008

Tip: Looking for answers? Try searching our database.

thrown exception in Marshal.PtrToStructure

Thread view: 
Enable EMail Alerts  Start New Thread
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 Magazines

Get 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 ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.