Jump to content
Xtreme .Net Talk

Recommended Posts

  • *Experts*
Posted

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

Printer Monitor for .NET? - see Merrion Computing Ltd for details
  • *Experts*
Posted
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...
Printer Monitor for .NET? - see Merrion Computing Ltd for details
  • *Experts*
Posted

OK - problem with FindNextPrinterChangeNotification:-

 

I have declared the PrinterNotifyInfo structure that it wants in as a class thus:

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:-

 


   <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

Printer Monitor for .NET? - see Merrion Computing Ltd for details
  • *Gurus*
Posted

Well, now that I'm 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 can't 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. This'll 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, I'm sure you have a better method Divil. So feel free to make me look bad. ;)[/edit]

  • *Experts*
Posted

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

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 doesn't put the address in the IntPtr that I have passed it so I can't use Marshal.PtrToStructure on it.

 

There seem to be two possibilities: (1) The FindNextPrinterChangeNotification function doesn't realise that I am passing it an IntPtr to put this address in or (2) the FindNextPrinterChangeNotification call doesn't realise that pPrinterNotifyOptions is set so thinks I don't 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 don't 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:

Dim WithEvents sp As New Spooler(Printer.DeviceName)

Perhaps in version 1.3?

Printer Monitor for .NET? - see Merrion Computing Ltd for details
Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...