Message board for the users of flat assembler.
> Windows > PAGESETUPDLG
kasake36 22 May 2006, 12:57
Hello, this time i have a problem accessing strings located inside a structure.
First of all: i have a Richedit-Control inside my dialog, plus there is a "Print"-Button. If the user presses this button, i call the PageSetupDlg-Dialog (which should be used instead of the PrintDlg, as stated in the WIN32API.HLP). The PageSetupDlg returns a value different than zero, which means that the user pressed OK. So if this is the case, i then want to create a DeviceContext using the Data (Drivername, Devicename) the user has selected (This is returned by PageSetupDlg using the PAGESETUPDLG-structure).
But when trying to create the DeviceContext, i run into problems. I just can't figure out how to access the strings for Drivername and Devicename located at PAGESETUPDLG.hDevNames.
hDevNames is a handle to a global memory object that contains a DEVNAMES structure, and this DEVNAMES-structure itself contains word-variables which point to null-terminated strings.
I would be glad if anyone could help how i can access these strings.
|22 May 2006, 12:57||
farrier 22 May 2006, 22:22
Everything I have learned about printing RichEdit docs came from Chib777 and his utilities XXContorls. Here is a link to the MASM32 site where he annouced the most recent version:
and a link to his site:
Attached is a program segment in FASM that I use in some commercial apps, ugly, but it works. In this case I use RTF files in RichEdit controls. Usage:
PrintRTF proc pFileName:DWORD, bLandOrPor:DWORD, PrintViewPrompt:DWORD, NumCopies:DWORD
provide a pointer to a filename
binary for Landscape or Portrait layout
binary for Print or View, not currently used
DWORD for number of copies
Most of the work is done formatting the individual pages. Unfortunately, this routines automatically prints to the default printer, and bypasses the printer dialog and page setup dialog. It uses hardcoded pages margins.
Hope this can help!
Some Assembly Required
It's a good day to code!
U.S.Constitution; Bill of Rights; Amendment 1:
... the right of the people peaceably to assemble, ...
The code is dark, and full of errors!
|22 May 2006, 22:22||
kasake36 23 May 2006, 08:23
Yes, interesting, thank you. But i just found a tutorial about printing in windows. It uses the PrintSetupDlg and i think i'll give it a try, hehe.
Here's the link: http://www.catch22.net/tuts/printing.asp
|23 May 2006, 08:23||
kasake36 23 Jun 2006, 09:21
Hello! Some time has passed and i still haven't finished the "print-from-richedit-control" procedure. It's not yet possible to set the margins, but anyway it may be helpful for some (and it uses the PAGESETUPDLG instead of the PRINTDLG). The handle to the window is passed to the procedure, and the Richedit-Control in passed window has to have the synonym ID_RTF.
proc PrintCurRE,hwnd:DWORD push ebx ; ====================================================================== ; The following partial program will demonstrate how to print the ; content of a RichEdit-Control to paper. ; This is achieved through this steps: ; 1) The user choses the wanted printer-device, margins, etc ; (PrintSetupDlg) ; 2) Creation of a device context ; 3) Formatting the text in the RichEdit-Control for the created ; device context. ; 4) Setting up the print-job (StartDoc) ; 5) Print page per page ; ?) Cleaning up: deletion of the device context, unlocking of locked ; memory objects. ; ---------------------------------------------------------------------- ; Let the user chose the wanted printer-device and other configurations ; for the print-job (f.i. margins, paper-size). A deactivated option is ; the page-layout (portrait or landscape, default is portrait). ; This is done by calling the PageSetupDlg which comes with the ; CommonDialogs.dll (comdlg32.dll). ; As parameter for the PageSetupDlg a PAGESETUPDLG-structure is used, ; which configures which options in the PageSetupDlg are made available ; for the user. Also, this structure allows to set a handle to a dialog ; box template which should be used instead of the standard ; PageSetupDlg-dialog box. mov [pagup.lStructSize], \ ; Specify the size of the sizeof.PAGESETUPDLG ; structure. mov eax,[hwnd] ; Set the owner-dialog of mov [pagup.hwndOwner],eax ; the PageSetupDlg. ; Initialize recommended margins and minimum margins (set to 10 mm on ; each side): mov [pagup.rtMargin+RECT.left],1000 mov [pagup.rtMargin+RECT.top],1000 mov [pagup.rtMargin+RECT.right],1000 mov [pagup.rtMargin+RECT.bottom],1000 mov [pagup.rtMinMargin+RECT.left],1000 mov [pagup.rtMinMargin+RECT.top],1000 mov [pagup.rtMinMargin+RECT.right],1000 mov [pagup.rtMinMargin+RECT.bottom],1000 ; Setting behaviourial flags for the PageSetupDlg. Here, PSD_NOWARNING ; is used to oppress the system from displaying a warning message if ; there is no default printer. ; PSD_INHUNDREDTHSOFMILLIMETERS indicates that all sizes ; are to be set in hundredths of millimeters. PSD_MARGINS and ; PSD_MINMARGINS tells the PageSetupDlg to use the rtMargin and ; rtMinMargin members to setup the margins: mov [pagup.Flags],PSD_NOWARNING+\ PSD_INHUNDREDTHSOFMILLIMETERS+\ PSD_MARGINS+PSD_MINMARGINS+\ PSD_DISABLEMARGINS ; After the PAGESETUPDLG-structure has been initialized, the ; PrintSetupDlg is called, which will return 0 in case the user cancels ; the process. invoke PageSetupDlg,pagup ; Show the PageSetupDialogs. cmp eax,0 ; If user cancels, je printcurre_fin ; end procedure. ; ---------------------------------------------------------------------- ; After the user has chosen the wanted options, a device context has to ; be created, which outputs to a printer-device. A device context is a ; structure that defines a set of graphic objects and the graphic modes ; that affect output. These graphic objects could be a pen for line ; drawing, a brush for painting/filling, a bitmap, a palette of colours ; or a region for clipping, which is for this program the most important ; object, since the output is clipped page by page. ; To create a device context, the function CreateDC has to be called ; with the following parameters: ; LPCTSTR lpszDriver, // pointer to string specifying driver name ; LPCTSTR lpszDevice, // pointer to string specifying device name ; LPCTSTR lpszOutput, // do not use; set to NULL ; CONST DEVMODE *lpInitData // pointer to optional printer data ; Since the PageSetupDlg has saved options selected by the user back to ; the PAGESETUPDLG-structure, these parameters can get obtained easily. ; As a member of PAGESETUPDLG, hDevNames points to a DEVNAMES structure ; which in turn points to a null-terminated string that contains the ; filename of the device driver. ; Another member of PAGESETUPDLG is hDevMode, and as the name might let ; guess, this member points to a DEVMODE structure which points to a ; string containing the device name. ; ?????????????????????????????????????????????????????????????????????????????? ; Before these can be used, they have to get locked ; ?????????????????????????????????????????????????????????????????????????????? invoke GlobalLock,[pagup.hDevNames] ; Lock the DEVNAMES-struct and mov [hdena],eax ; save the returned handle. invoke GlobalLock,[pagup.hDevMode] ; Lock the DEVMODE-struct and mov [hdemo],eax ; save the returned handle. invoke CreateDC,[hdena],[hdemo], \ ; Create the device context, NULL,[hdemo] ; and, in case cmp eax,NULL ; it returns NULL, je fcrecdc ; output a error-message and end ; the process. mov [hDC],eax ; Otherwise save the handle to ; the device context. ; ---------------------------------------------------------------------- ; Is the device context created successfully, the next step is to set up ; the richedit-control. This is done by sending the EM_FORMATRANGE ; message to the richedit-control. This message uses the FORMATRANGE ; structure as parameter, which contains infos about the output device, ; and the area to render. So the first step is to initialize this ; structure: mov eax,[hDC] ; Setting the devices: hdc is the handle to the device context where the ; output is actually send to. hdcTarget contains the handle to the ; device context to format for. So the hdc and hdcTarget are usually the ; same handles, but would differ in case of print-previews (in this case ; hdc would have the handle of the window in which the output is viewed, ; whilst hdcTarget is the device context of the printer. mov [fora.hdc],eax ; Device for rendering mov [fora.hdcTarget],eax ; Target-device ; The rcPage-member of FORMATRANGE specifies the entire area of the ; rendering device, this is the size of the paper. Units are in TWIPS. mov [fora.rcPage+RECT.left],0 ; Sheet begins at mov [fora.rcPage+RECT.top],0 ; 0|0. stdcall huMMToTWIPS, \ ; Convert the width of the [pagup.ptPaperSize+POINT.x] ; sheet-size to TWIPS mov eax,[istwips] ; and save resulting mov [fora.rcPage+RECT.right],eax ; width. stdcall huMMToTWIPS, \ ; Convert the height of the [pagup.ptPaperSize+POINT.y] ; sheet-size to TWIPS mov eax,[istwips] ; and save the resulting mov [fora.rcPage+RECT.bottom],eax ; height. ; The rc-member of FORMATRANGE specifies the area to render to, units ; are in TWIPS. Here is the place where the margins get calculated ; and subtracted from the sheet-size (rc-member) to get the area to ; render to. ; ; ********************************************************************** ; *** The following calculations were done guided by ; *** http://www.catch22.net/tuts/printing.asp ; ; Since most printers cannot print to the edge of a piece of paper, ; there will always be a small border around the outside of this ; printable area which cannot be printed to. To get the printable area ; of a printing device, the procedure GetDeviceCaps is used. ; ; A sheet of paper: ; ; @@@@@@@@@@@@@@@@ ; @**************@ ; @*............*@ ; @*............*@ ; @*............*@ @ = Printer margin ; @*............*@ * = User's margin ; @*............*@ . = User's page area ; @*............*@ ; @*............*@ ; @*............*@ ; @*............*@ ; @**************@ ; @@@@@@@@@@@@@@@@ ; mov [fora.rc+RECT.left],0 mov [fora.rc+RECT.top],0 mov eax,dword[fora.rcPage+RECT.right] mov [fora.rc+RECT.right],eax mov eax,dword[fora.rcPage+RECT.bottom] mov [fora.rc+RECT.bottom],eax ; As last member the range of the text to format is set. Here, if cpMin ; is set to 0 and cpMax to -1, all the text is printed. mov [fora.chrg+CHARRANGE.cpMin],0 mov [fora.chrg+CHARRANGE.cpMax],-1 ; Before being able to send a message to the RichEdit-Control, the ; handler to this control must get obtained: invoke GetDlgItem,[hwnd],ID_RTF mov [hPRTE],eax ; ---------------------------------------------------------------------- ; To set up the print-job, the StartDoc procedure has to be called, ; which, as parameter, takes a DOCINFO-structure. mov [dofo.cbSize],sizeof.DOCINFO ; Specify the size. mov [dofo.lpszDocName],docnam ; Documentname ; Points to a null-terminated string that specifies the name of an ; output file. If this pointer is NULL, the output will be sent to the ; device identified by the device context handle that was passed to the ; StartDoc function: mov [dofo.lpszOutput],NULL ; The last two members are ignored in Version above Win95: mov [dofo.lpszDatatype],NULL mov [dofo.fwType],NULL ; After initializing the DOCINFO structure, the StartDoc procedure can ; be called, which returns a value above zero, if successfull. This ; value is the print job identifier for the document: invoke StartDoc,[hDC],dofo ; ---------------------------------------------------------------------- ; Now print page per page. This loop was copied from the example of ; "Using Built-In Printing Features from a Rich Edit Control" found in ; the WIN32API.HLP. ; As first step the textlength is requested. The example mentioned above ; uses the WM_GETTEXTLENGTH message for this task, but it seems that the ; result of this message is larger than the actual textlength, when the ; Richedit-Control uses diverse text-formatings like tables, ; text-styles, and so forth. For further infos the WM_GETTEXTLENGTH ; entry in the WIN32API.HLP provides some infos. ; So instead of using WM_GETTEXTLENGTH to find out the actual ; textlength, first all text in the Richedit-control is selected: mov dword[change.cpMin],0 mov dword[change.cpMax],-1 invoke SendMessage,[hPRTE],EM_EXSETSEL,0,change ; After selecting all the text, a request is send to get the cpMin and ; cpMax position of the selection: invoke SendMessage,[hPRTE],EM_EXGETSEL,0,change mov eax,[change.cpMax] ; Save the textlength. It will mov [txtlen],eax ; be used to calculate if the ; last printed char is too the ; last one in the richedit-ctrl. @@: invoke StartPage,[hDC] ; Start a page ; Print as much text as can fit on a page. The return value is the ; index of the first character on the next page. Using TRUE for the ; wParam parameter causes the text to be printed. ; While the EM_FORMATRANGE message (with FALSE as wparam!) causes the ; RichEdit Control to format it's content for the given device-context ; (in fora), the EM_DISPLAYBAND message is the cause the contents gets ; printed: invoke SendMessage,[hPRTE], \ ; Returns the index of the last EM_FORMATRANGE,FALSE,fora ; character that fits in the mov [laca],eax ; range + 1. invoke SendMessage,[hPRTE], \ ; Output the formatted contents EM_DISPLAYBAND,0,fora.rc ; to the device context (fora). ; End a page: invoke EndPage,[hDC] ; Is there more text to print? This can be found out by comparing the ; index of the last printed character with the textlen. mov eax,[laca] ; If the last character cmp eax,[txtlen] ; has been printed, je @f ; end the loop ; Before being sure that another page has to be printed, another check ; is run: this time laca+1 is compared with the txtlen, and, if they are ; equal, the loop will also get ended. ; This check seems odd, but if, f.i. the Richedit control would be ; empty, EM_FORMATRANGE would return 0 while the txtlen would be set ; to 1. Since 0 is not equal to 1, the program would generate another ; page and another and so forth. Too, i have achieved the same effect by ; trying to print the delivered "prasland.rtf" file in landscape format. ; Then, EM_FORMATRANGE would always return 1225 while the txtlen is set ; to 1226, which, again, would result in endless printing-loop. inc eax ; last character + 1 cmp eax,[txtlen] je @f ; Otherwise, set the cpMin member of the FORMATRANGE structure to the ; last formatted character (which is actually the last formated ; character + 1) as new start position for the next page. The cpMax ; member is set to -1 again: mov eax,[laca] mov [fora.chrg+CHARRANGE.cpMin],eax mov [fora.chrg+CHARRANGE.cpMax],-1 jmp @b ; Jump to the start of the loop @@: ; The printing process is nearly finished. ; When printing is complete, the EM_FORMATRANGE message must be sent ; to the control with wParam = 0 and lParam = NULL to free the ; information cache by the control: invoke SendMessage,[hPRTE],EM_FORMATRANGE,0,NULL ; End the document: invoke EndDoc,[hDC] ; ---------------------------------------------------------------------- ; After the printing has been done, the device context has to be ; deleted: invoke DeleteDC,[hDC] ; Plus all locked memory objects have to get unlocked: ulop: invoke GlobalUnlock,[hdena] ; Unlock DEVNAMES invoke GlobalUnlock,[hdemo] ; Unlock DEVMODE printcurre_fin: pop ebx ret fcrecdc: stdcall TInfoBox,[ebp+8],fdc jmp ulop endp ;=============================================================================== ;== Converts a digit given in hundredths of millimeters to it's equivalent in ;== TWIPS, where 25.4 mm = 1 inch = 1440 TWIPS. ;== The calculation is done by converting the millimeters to inches through ;== a division by 2540 (25.4 mm * 100 to get hundredths of millimeters). The ;== resulting inches then get multiplied by 1440 to get the TWIPS. ;== ;== The procedure receives the digit to convert as parameter and writes the ;== resulting TWIPS into the istwips dword variable. ;=============================================================================== proc huMMToTWIPS,humm:DWORD push ebx ; ---------------------------------------------------------------------- ; This part converts the millimeters to inches by a division through ; 254 instead of the 2540 stated in the main comment. By this, the ; result will be more precise, but it forces us to set the multiplicator ; to 144. mov edx,0 ; Clear remainder mov eax,[humm] ; Set humm as dividend mov ebx,254 ; Set divisor div ebx ; Calculate mov ebx,eax ; Save the resulting inches ; ---------------------------------------------------------------------- ; Multiply the inches by 144 to get the TWIPS: mov eax,144 ; Set multiplicator mul ebx mov [istwips],eax ; Save the resulting twips pop ebx ret endp
I'm no assembler-professional, i know!
|23 Jun 2006, 09:21||
Tomasz Grysztar 23 Jun 2006, 09:59
I think you'd get better precision by first doing MUL and then the DIV instead of the opposite order. Also since your function already returns the value in EAX, there's no need to store it in global variable.
It could look like:
proc huMMToTWIPS,humm:DWORD mov eax,[humm] mov ecx,1440 mul ecx ; EAX*1440 stored in EDX:EAX mov ecx,2540 div ecx ; EDX:EAX divided by 2540 -> result in EAX ; this not really necessary: ; mov [istwips],eax ret endp
|23 Jun 2006, 09:59||
kasake36 23 Jun 2006, 10:05
Thanks! Half the instructions i used, hehe
|23 Jun 2006, 10:05||
< Last Thread | Next Thread >
Copyright © 1999-2023, Tomasz Grysztar. Also on GitHub, YouTube, Twitter.
Website powered by rwasa.