*Experts* Merrion Posted November 24, 2002 *Experts* Posted November 24, 2002 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 Quote Printer Monitor for .NET? - see Merrion Computing Ltd for details
*Gurus* Derek Stone Posted November 24, 2002 *Gurus* Posted November 24, 2002 Which Win32 API function are you trying to use this with? Quote Posting Guidelines
*Experts* Merrion Posted November 25, 2002 Author *Experts* Posted November 25, 2002 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... Quote Printer Monitor for .NET? - see Merrion Computing Ltd for details
*Gurus* Derek Stone Posted November 25, 2002 *Gurus* Posted November 25, 2002 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. Quote Posting Guidelines
*Experts* Merrion Posted November 25, 2002 Author *Experts* Posted November 25, 2002 I'm having so many problems with this, I figured I'd attach the code for me/us to refer to....pqw.zip Quote Printer Monitor for .NET? - see Merrion Computing Ltd for details
*Experts* Merrion Posted November 25, 2002 Author *Experts* Posted November 25, 2002 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 Quote Printer Monitor for .NET? - see Merrion Computing Ltd for details
*Gurus* Derek Stone Posted November 27, 2002 *Gurus* Posted November 27, 2002 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] Quote Posting Guidelines
*Gurus* Derek Stone Posted November 27, 2002 *Gurus* Posted November 27, 2002 You and your damn printer APIs... ;) Quote Posting Guidelines
*Experts* Merrion Posted November 27, 2002 Author *Experts* Posted November 27, 2002 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? Quote Printer Monitor for .NET? - see Merrion Computing Ltd for details
*Gurus* divil Posted November 27, 2002 *Gurus* Posted November 27, 2002 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). Quote MVP, Visual Developer - .NET Now you see why evil will always triumph - because good is dumb. My free .NET Windows Forms Controls and Articles
*Experts* Merrion Posted November 27, 2002 Author *Experts* Posted November 27, 2002 I may be misreading the documentation, but WMI_Printer doesn't seem to have any spooler type events? Quote Printer Monitor for .NET? - see Merrion Computing Ltd for details
*Experts* Merrion Posted November 28, 2002 Author *Experts* Posted November 28, 2002 OK - I have a partial solution as per this article...Derek Stone was right in the first instance... Quote Printer Monitor for .NET? - see Merrion Computing Ltd for details
*Experts* Merrion Posted November 30, 2002 Author *Experts* Posted November 30, 2002 [PLAIN][Resolved] Marshalling as a pointer to an array of shorts?[/PLAIN] Attached is the source for the first cut of the printer watch component - thanks for your help in getting it this far...pritwatchnetsrc.zip Quote Printer Monitor for .NET? - see Merrion Computing Ltd for details
Recommended Posts