Marshalling as a pointer to an array of shorts?

Merrion

Well-known member
Joined
Sep 29, 2001
Messages
265
Location
Dublin, Ireland
User Rank
*Experts*
How do I pass a variable length array of short values to an API call? I have tried
<MarshalAs(UnmanagedTypes.LPArray)>pFields() As Short
but it generates a loadlibrary exception...

Any ideas?

Thanks in advance,
Duncan
 
FindFirstPrinterChangeNotification - the element pFields in NOTIFY_OPTIONS is a pointer to a variable length linear array of 16 bit integers corresponding to i.e. JOB_NOTIFY_FIELD_STATUS...
 
Well, after reviewing the documentation on MSDN, it appears its looking for a pointer, not the actual array. With that said, change the structure to read "pFields As IntPtr" and use the Marshal.AllocHGlobal method I suggested to you a few threads back.
 
OK - problem with FindNextPrinterChangeNotification:-

I have declared the PrinterNotifyInfo structure that it wants in as a class thus:
Code:
Imports System.Runtime.InteropServices


<StructLayout(LayoutKind.Explicit)> _
Public Class PrinterNotifyOptions
    <FieldOffset(0)> Public dwVersion As Integer
    <FieldOffset(4)> Public dwFlags As Integer
    <FieldOffset(8)> Public Count As Integer
    \\ --JOB_NOTIFY_OPTIONS_TYPE
    <FieldOffset(12)> Public wType As Int16
    <FieldOffset(14)> Public wReserved0 As Int16
    <FieldOffset(16)> Public dwReserved1 As Int32
    <FieldOffset(20)> Public dwReserved2 As Int32
    <FieldOffset(24)> Public FieldCount As Int32
    <FieldOffset(28)> Public pFields As IntPtr

#Region "Public Enumerated Types"
    Public Enum Printer_Notification_Types
        PRINTER_NOTIFY_TYPE = &H0
        JOB_NOTIFY_TYPE = &H1
    End Enum

    Public Enum Printer_Notify_Field_Indexes
        PRINTER_NOTIFY_FIELD_SERVER_NAME = &H0
        PRINTER_NOTIFY_FIELD_PRINTER_NAME = &H1
        PRINTER_NOTIFY_FIELD_SHARE_NAME = &H2
        PRINTER_NOTIFY_FIELD_PORT_NAME = &H3
        PRINTER_NOTIFY_FIELD_DRIVER_NAME = &H4
        PRINTER_NOTIFY_FIELD_COMMENT = &H5
        PRINTER_NOTIFY_FIELD_LOCATION = &H6
        PRINTER_NOTIFY_FIELD_DEVMODE = &H7
        PRINTER_NOTIFY_FIELD_SEPFILE = &H8
        PRINTER_NOTIFY_FIELD_PRINT_PROCESSOR = &H9
        PRINTER_NOTIFY_FIELD_PARAMETERS = &HA
        PRINTER_NOTIFY_FIELD_DATATYPE = &HB
        PRINTER_NOTIFY_FIELD_SECURITY_DESCRIPTOR = &HC
        PRINTER_NOTIFY_FIELD_ATTRIBUTES = &HD
        PRINTER_NOTIFY_FIELD_PRIORITY = &HE
        PRINTER_NOTIFY_FIELD_DEFAULT_PRIORITY = &HF
        PRINTER_NOTIFY_FIELD_START_TIME = &H10
        PRINTER_NOTIFY_FIELD_UNTIL_TIME = &H11
        PRINTER_NOTIFY_FIELD_STATUS = &H12
        PRINTER_NOTIFY_FIELD_STATUS_STRING = &H13
        PRINTER_NOTIFY_FIELD_CJOBS = &H14
        PRINTER_NOTIFY_FIELD_AVERAGE_PPM = &H15
        PRINTER_NOTIFY_FIELD_TOTAL_PAGES = &H16
        PRINTER_NOTIFY_FIELD_PAGES_PRINTED = &H17
        PRINTER_NOTIFY_FIELD_TOTAL_BYTES = &H18
        PRINTER_NOTIFY_FIELD_BYTES_PRINTED = &H19
        PRINTER_NOTIFY_FIELD_OBJECT_GUID = &H1A
    End Enum

    Public Enum Job_Notify_Field_Indexes
        JOB_NOTIFY_FIELD_PRINTER_NAME = &H0
        JOB_NOTIFY_FIELD_MACHINE_NAME = &H1
        JOB_NOTIFY_FIELD_PORT_NAME = &H2
        JOB_NOTIFY_FIELD_USER_NAME = &H3
        JOB_NOTIFY_FIELD_NOTIFY_NAME = &H4
        JOB_NOTIFY_FIELD_DATATYPE = &H5
        JOB_NOTIFY_FIELD_PRINT_PROCESSOR = &H6
        JOB_NOTIFY_FIELD_PARAMETERS = &H7
        JOB_NOTIFY_FIELD_DRIVER_NAME = &H8
        JOB_NOTIFY_FIELD_DEVMODE = &H9
        JOB_NOTIFY_FIELD_STATUS = &HA
        JOB_NOTIFY_FIELD_STATUS_STRING = &HB
        JOB_NOTIFY_FIELD_SECURITY_DESCRIPTOR = &HC
        JOB_NOTIFY_FIELD_DOCUMENT = &HD
        JOB_NOTIFY_FIELD_PRIORITY = &HE
        JOB_NOTIFY_FIELD_POSITION = &HF
        JOB_NOTIFY_FIELD_SUBMITTED = &H10
        JOB_NOTIFY_FIELD_START_TIME = &H11
        JOB_NOTIFY_FIELD_UNTIL_TIME = &H12
        JOB_NOTIFY_FIELD_TIME = &H13
        JOB_NOTIFY_FIELD_TOTAL_PAGES = &H14
        JOB_NOTIFY_FIELD_PAGES_PRINTED = &H15
        JOB_NOTIFY_FIELD_TOTAL_BYTES = &H16
        JOB_NOTIFY_FIELD_BYTES_PRINTED = &H17
    End Enum

#End Region

    Public Sub New()


        \\ As it stands, version is always 2
        dwVersion = 2
        \\ We must have at least one notification - status makes sense to test with...
        NotifyJobStatus = True
        FieldCount = 1
        Dim pfld1 As Short = Job_Notify_Field_Indexes.JOB_NOTIFY_FIELD_STATUS

        \\ Use pointer to array per your suggestion...
        pFields = Marshal.AllocHGlobal(2)
        Marshal.WriteInt16(pFields, 0, pfld1)

    End Sub

End Class

And when I pass it to FindFirstPrinterChangeNotification it goes OK but when a print job occurs and the wait object triggers I have to call FindNextPrinterChangeNotification to get the info that has changed which I have declared thus:-

Code:
    <DllImport("winspool.drv", EntryPoint:="FindNextPrinterChangeNotification", _
    SetLastError:=True, CharSet:=CharSet.Ansi, _
    ExactSpelling:=True, _
    CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function FindNextPrinterChangeNotification _
                            (<InAttribute()> ByVal hChangeObject As IntPtr, _
                             <OutAttribute()> ByRef pdwChange As IntPtr, _
                             <InAttribute()> ByVal pPrinterNotifyOptions As PrinterNotifyOptions, _
                             <OutAttribute()> ByRef lppPrinterNotifyInfo As IntPtr _
                                 ) As Boolean

    End Function

Now when this is called the variable pdwChange is filled with the correct value to indicate what has changed but lppPrinterNotifyInfo is never non-zero.

Any thoughts at all?

Thanks in advance,
Duncan
 
Well, now that Im looking at the correct declare in MSDN, I might have a solution for you. lppPrinterNotifyInfo is looking for a pointer to a structure, correct? Correct. Now, after thinking this through, one cant expect the Win32 API to be able to access a managed structure using a pointer, so what you have to do is marshal that structure to unmanaged memory using Marshal.StructureToPtr(). You can use the Marshal.SizeOf method to get the size of the managed structure, and then allocate the neccessary memory using AllocHGlobal before you call StructureToPtr. Thisll give you a pointer which you can then pass to FindNextPrinterChangeNotification, hopefully. Then just call Marshal.PtrToStructure to get the managed structure back.

God I hope this works...
[edit]And yeah, Im sure you have a better method Divil. So feel free to make me look bad. ;)[/edit]
 
In the VB5 version I pass it an uninitialised long and it puts an address in this long which is an address of the structure that it has allocated e.g.:
Code:
Dim lpPrintInfoBuffer As Long 

        If FindNextPrinterChangeNotificationByLong(mEventHandle, pdwChange, PrintOptions, lpPrintInfoBuffer) <> 0 Then
           Call CopyMemoryPRINTER_NOTIFY_INFO(mData, lpPrintInfoBuffer, Len(mData))
...

Which is pretty much what you are saying. However doing the same thing in .Net it doesnt put the address in the IntPtr that I have passed it so I cant use Marshal.PtrToStructure on it.

There seem to be two possibilities: (1) The FindNextPrinterChangeNotification function doesnt realise that I am passing it an IntPtr to put this address in or (2) the FindNextPrinterChangeNotification call doesnt realise that pPrinterNotifyOptions is set so thinks I dont want any lppPrinterNotifyInfo back.

I am getting the last win 32 error as per your earlier help and it is saying "The operation executed successfully" so I really dont think option 2 is occuring...

You and your damn printer APIs... ;)
I know - if only MS would put me out of my missery by adding this stuff to the framework..life could be so much simpler if I could do:
Code:
Dim WithEvents sp As New Spooler(Printer.DeviceName)
Perhaps in version 1.3?
 
Have you considered using WMI to do all this? The framework contains classes under System.Management to aid in using WMI for exactly this type of thing (printer management).
 
[Resolved] Marshalling as a pointer to an array of shorts?

Attached is the source for the first cut of the printer watch component - thanks for your help in getting it this far...
 

Attachments

Back
Top