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.pdm = GlobalLock(hDm)call CopyMemory(pdm, p2.pDevMode, nLen)!! Now dm.dmDriverExtra is available, so memory can be freed and reallocated!
With the correct size.!nLen = sizeof(dm) + dm.dmDriverExtrapdm = GlobalFree(pdm)hDm = GlobalAlloc(GHND, nLen)pdm = GlobalLock(hDm)call CopyMemory(pdm, 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);RegardsAlan. 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. 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?RegardsAlan. 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 IDCCOMBOPRINTER 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.
Nietod - I took out the freelibrary right after fp (that's what I get for copying sample code), but when I put inMessageBox(NULL,dmp-dmDev iceName,', MBAPPLMODAL MBICONEXCLAMATION MBOK);all I get is a blank. It still works with the PrinterData string kludge, otherwise not - and when I try to access DEVMODE member structures with dmp.dmDeviceName, I get 'must be a structure or union' error. I can't figure out how to declare a DEVMODE structure (devmode dm) and then access the memory with GlobalAlloc and GlobalLock functions (which Help seems to say you have to do). I was confused because I didn't realize you had working and non-working code intermixed. I also couldn;t see where you were using the DEVMODE structure.
(That was the bug. But I didn't know that.)However, unless the documentation says that the DEVMODE needs to be allcoated in global memory (I only have 32 bit documentation.) You don't need to use GlobalAlloc and GlobalLock and all that stuff. Just declare the DEVMODE structure locally and pass a pointer to it, likeDEVMODE DM;bytes = fp( NULL, hlib, &DM, (LPSTR) DeviceName,(LPSTR) PortName, (LPDEVMODE) NULL, (LPSTR) NULL, DMOUTBUFFER). Nietod -Unfortunately, that's what the docs do say -Identifies a movable global memory object that contains a DEVMODE structure. Before the PrintDlg function is called, the members in this structure may contain data used to initialize the dialog box controls. When the PrintDlg function returns, the members in this structure specify the state of each of the dialog box controls.I have already tired dmp as the variable (got a GPF in the driver) and then tried it with localalloc; didn't work.When I try to do the DEVMODE dm, I can't allocate global memory for dm (as I did local mem in simple old DOS C).struct DEVMODE dm;dm=calloc(1,sizeof(DEVMODE ));dm.dmOrientation=DMORIENT LANDSCAPE;Simple, but Not! NullTerminator -there goes my learning curve - I don't have a clue about MFC or C.
I said that was a possible improvement if the DEVMODE does not have to be globally allocated. You said you must have the DEVMODE structure globally allocated. So don't declare it locally, likeDECMODE DM;Don't do that. Allocate it with GlobalAlloc if it has to be in global memory.However the problem is that you are passing a handle to this global memory when you need to pass a pointer. You dobytes = fp( NULL, hlib, (LPDEVMODE) hGlobalMemory, (LPSTR) DeviceName,(LPSTR) PortName, (LPDEVMODE) NULL, (LPSTR) NULL, OUTBUFFER);That is wrong. The 3rd parameter shoudl be a pointer to the locked global memory, likebytes = fp( NULL, hlib, dmp, (LPSTR) DeviceName,(LPSTR) PortName, (LPDEVMODE) NULL, (LPSTR) NULL, OUTBUFFER).
Reading your code is a nightmare. You should switch to C and windows.32.
Download; FAQ; Ask a Question; Compatibility. Specifications Warranty Contact Us. Driver; Manual. Please Select your operating system first: Select, Vista 64. Download msi ms-7104 ver 3 manual.
It will make my life easier.:-)The problem appears to be the amount of memory you are allocating. With your 'string kludge' your are calling the function to ask it how much memory to allocate. See first you specify NULL in the 3rd parameter, which tells it the returnt he number of bytes it wants, likebytes = fp( NULL, hlib, (LPDEVMODE) NULL, (LPSTR) DeviceName,(LPSTR) PortName, (LPDEVMODE) NULL, (LPSTR) NULL, 0);Then you allocate the number of bytes it wants.PrinterData = malloc(bytes);finally you specfy the memory of the size it suggested.bytes = fp( NULL, hlib, (LPDEVMODE) PrinterData, (LPSTR) DeviceName,(LPSTR) PortName, (LPDEVMODE) NULL, (LPSTR) NULL, DMOUTBUFFER);You need to do that with the globally allocated memory as well. You need to get the size to be allocated before you allocate the memory. Does this make sense? Post that code.
That code is closer that what you had before. Do you have any documentation on this function you are calling (EXTDEVMODE). I don't because I only have 32 bit docs. If you have some 16 bit docs can you post it or if it is too long e-mail it to me at nietod@theshop.net.By the way you won't find win32 that big a change. In general, things get better, not worse, and there won't be too much to learn.If you can switch to C, that is a BIG change, but one that I recommend highly.
But when you make the change you can start using it like C and slowly add in C features as you learn them.