Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

DEVMODE storage allocation

llynisa
Beginner
2,418 Views
I have been translating the sample code in C++ for the subroutine GetPrinterDevice that is listed in Microsoft Knowledge Base Article 166129 ?HOWTO: Print Directly to a Non-Default Printer in MFC? and it works correctly (on one system at least).

However, whereas the original C++ code is able to allocate using a single command the memory required for the DEVMODE structure plus the private driver-data, I have been unable in CVF to do so, so have been forced to take two bites at the cherry. Does anyone know of a way of doing it in one? I append my CVF code, from which I have removed the tests for success of the operations.
! Allocate a global handle for DEVMODE structure dm.
! When dm.dmDriverExtra is available, resize memory. 
!
nLen = sizeof(dm)
hDm = GlobalAlloc(GHND, nLen)            ! See C++ code line below.
p_dm = GlobalLock(hDm)
call CopyMemory(p_dm, p2.pDevMode, nLen)
!
!  Now dm.dmDriverExtra is available, so memory can be freed and reallocated 
! with the correct size.
!
nLen = sizeof(dm) + dm.dmDriverExtra
p_dm = GlobalFree(p_dm)
hDm = GlobalAlloc(GHND, nLen)
p_dm = GlobalLock(hDm)
call CopyMemory(p_dm, p2.pDevMode, nLen)
LastError = GlobalUnlock(hDm)


The C++ code that is used where commented above is:

HGLOBAL  hDevMode = GlobalAlloc(GHND, sizeof(*p2->pDevMode) +
  p2->pDevMode->dmDriverExtra);


Regards

Alan
0 Kudos
7 Replies
Jugoslav_Dujic
Valued Contributor II
2,418 Views
Alan,
DocumentProperties (ain't the name intuitive? ;-) ) API returns size of DEVMODE+extra stuff structure for given printer if fMode argument is zero (i.e. it works in similar manner as GetPrinter -- first call returns number of bytes, then you allocate it and give it a regular buffer).

Oh, I found the Q166129. You can mimic that code using Cray (aka Integer) pointers, which are quite similar to C pointers (and you'll hardly avoid them when dealing with such ugly low-level printer stuff):
TYPE(T_PRINTER_INFO_2):: PI2; POINTER(pPI2, PI2)
TYPE(T_DEVMODE):: DM; POINTER(pDM, DM)

...
GetPrinter(hPrinter, 2, NULL, 0, LOC(dwBytesNeeded))
hPI2 = GlobalAlloc(GHND, dwBytesNeeded)
pPI2 = GlobalLock(hPI2)
GetPrinter(hPrinter, 2, pPI2, dwBytesNeeded, LOC(dwBytesReturned))

pDM = PI2%pDevMode
dmDriverExtra = DM%dmDriverExtra
...
Side note: I prefer ALLOCATEing a INTEGER(1) buffer array than using GlobalAlloc/GlobalLock, and then "equivalence" it to a DEVMODE or whatever using Cray pointer. Simpler & more flexible.

HTH
Jugoslav
0 Kudos
llynisa
Beginner
2,418 Views
Jugoslav,

Many thanks for your help - as usual there are several ways of skinning the cat and I could only think of the hard way. Now I can get onto my next problem.

Alan
0 Kudos
llynisa
Beginner
2,418 Views
And my next problem is that my program is now working reasonably well, but one user has a problem with network printers that have long filenames. The printer name is stored in the dmDeviceName element of the DEVMODE structure, and this is declared as a character(32) string in dfwinty. However, the printer names are longer than 32 characters ? indeed the first 32 characters of all of their names are the same.

There is no trouble with standard print dialog boxes, but it does not work with my customised version ? it will only print on the default printer for these long file names. Does anyone know of a fix?

Regards

Alan
0 Kudos
kdkeefer
Beginner
2,418 Views
Alan,
Just to get the Society for the Prevention of Cruelty to Animals (US version, may be Royal Humane Society in Britain) off your back "more the one way to skin a 'cat'" refers to a catfish, not the furry ones (except in eastern Asia) :)
Keith
Owned by 3 furry cats.
0 Kudos
Jugoslav_Dujic
Valued Contributor II
2,418 Views
Alan,
Attached is an actual source of mine, which is tested rather thoroughly -- it's also a custom print dialog. Unfortunately, it's not rich with comments and not compilable as-is (API calls are interspersed with dialog handling). I don't think it has 32-char limit problem, since it uses EnumPrinters and DocumentProperties APIs, which use pointers-to-strings, not character*32. Contents of IDC_COMBO_PRINTER are used as storage for printer names as obtained from EnumPrinters. I know it's too complicated for your needs, but I think you'll be able to extract the interesting parts.

[nDMBuffer is INTEGER(1) array sized enough to hold the biggest DEVMODE+extrastuff of all printers installed (iMaxBufSize). It is not deallocated anymore, and few variables are global/SAVEd in order to retain the dialog settings for eventual invocations. (bWasHere, bPrinterSet)]

(Attachment in the followup)

Jugoslav
0 Kudos
Jugoslav_Dujic
Valued Contributor II
2,418 Views
...here it is. I attached also a screenshot so that you get the idea how it looks like -- I hope control ID names are descriptive enough.

P.S. I'll be back September 1...
0 Kudos
llynisa
Beginner
2,418 Views
Jugoslav,

Welcome back, and many thanks for the code. I have been sidetracked by priority work & holidays, but will be implementing it soon.

Regards

Alan

0 Kudos
Reply