SetHdevmode and printer configuration

E

Eric Eggermann

Hello,
I need to implement a custom print dialog, and I'm trying to show a printers
configuration box, like when you click Properties on the windows forms
PrintDialog. I've gotten as far as showing the dialog. Now what do I do with
the devmode pointer? I've tried using SetHdevmode on the printer setting,
and it's default page setting, but I'm getting a System.EngineExecution
error.

Here's the declarations,
[DllImport("winspool.drv", EntryPoint="DocumentProperties",
SetLastError=true,
CallingConvention=CallingConvention.StdCall)]
private static extern int DocumentProperties(IntPtr hwnd, int hPrinter,
string pDeviceName, IntPtr pDevModeOutput, IntPtr pDevModeInput, int fMode);

[DllImport("winspool.drv", EntryPoint="OpenPrinter", SetLastError=true,
CallingConvention=CallingConvention.StdCall)]
private static extern int OpenPrinter(string pPrinterName, ref int
phPrinter, PRINTER_DEFAULTS pDefault);

[DllImport("winspool.drv", EntryPoint="ClosePrinter", SetLastError=true,
CallingConvention=CallingConvention.StdCall)]
private static extern int ClosePrinter(int hPrinter);

Here's the code to show the dialog:

string printerName = cboPrinter.PrinterName; // user selected printer
PRINTER_DEFAULTS pd = new PRINTER_DEFAULTS();
int handle = 0;
int ret = OpenPrinter(printerName, ref handle, pd);

IntPtr devOut = cboPrinter.Printer.GetHdevmode();
IntPtr devIn = cboPrinter.Printer.GetHdevmode();

int propSetRet = DocumentProperties(this.Handle, handle, printerName,
devOut, devIn, DM_IN_PROMPT | DM_OUT_BUFFER);
int closeRet = ClosePrinter(handle);

cboPrinter.Printer.DefaultPageSettings.SetHdevmode(devOut); //<-- Error here
cboPrinter.Printer.SetHdevmode(devOut);

All the API calls return 1 so that part seems to be working. So how do I
make use of the changes the user made in the printer's dialog? And is there
any way I can use the IntPtr to devOut and get a structure that I can look
at the values? I don't think I really need that for my program, but it might
help me debug.

TIA,
Eric Eggermann
 
M

Mattias Sjögren

Eric,
IntPtr devOut = cboPrinter.Printer.GetHdevmode();
IntPtr devIn = cboPrinter.Printer.GetHdevmode();

GetHdevmode returns a memory object *handle*. You should use
GlobalLock to get a pointer to the DEVMODE.

I also believe you have to set CharSet=CharSet.Auto in your DllImport
attributes to get this to work.

And is there
any way I can use the IntPtr to devOut and get a structure that I can look
at the values?

Yes, you can dereference the pointer with Marshal.PtrToStructure().



Mattias
 
E

Eric Eggermann

Mattias Sjögren said:
Eric,


GetHdevmode returns a memory object *handle*. You should use
GlobalLock to get a pointer to the DEVMODE.

I also believe you have to set CharSet=CharSet.Auto in your DllImport
attributes to get this to work.

Thanks Matthias,
I'm going to try that right now. But, what is the difference between the
handle and the address to the memory? What is in the handle?

And I'm sort of guessing here, but do you mean that, I should use
GetHdevmode to get handles to two devmode structures for the printer, then
use GlobalLock on them, then on success pass the returns from that to the
DocumentProperties call? Anyway, that's what I'm going to do for starters.

Thanks again,
Eric
 
M

Mattias Sjögren

Eric,
I'm going to try that right now. But, what is the difference between the
handle and the address to the memory? What is in the handle?

The address is just that, an address to a place in the process'
virtual memory.

The handle represents a "memory object", which is created when you
allocate movable memory with the Global or Local memory APIs. Here are
some quotes from the docs about this that may help

"GMEM_MOVEABLE
Allocates movable memory. Memory blocks are never moved in physical
memory, but they can be moved within the default heap.
The return value is a handle to the memory object. To translate the
handle into a pointer, use the GlobalLock function."

"When you allocate fixed memory, GlobalAlloc and LocalAlloc return a
pointer that the calling process can immediately use to access the
memory. When you allocate moveable memory, the return value is a
handle. To get a pointer to a movable memory object, use the
GlobalLock and LocalLock functions."

And I'm sort of guessing here, but do you mean that, I should use
GetHdevmode to get handles to two devmode structures for the printer, then
use GlobalLock on them, then on success pass the returns from that to the
DocumentProperties call? Anyway, that's what I'm going to do for starters.

Exactly. Also make sure you free (GlobalFree) devIn and devOut when
you're done, since each call to GetHdevnode returns newly allocated
memory.



Mattias
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top