|
Hello,
We would like to print some simple drawing output using GDI. We have used the PrintDlgEx function to obtain a device context handle to a printer, but are unsure of how to proceed. We have not been able to find much example code and are a little stuck.
Basically, we have the DC handle. Presumably we then call Rectangle(x,x,x,x) etc to do the painting. What must be done then to initiate the actual printing?
Any help would be appreciated.
Thanks,
Steve
|
|
|
|
|
Check this[^] out, it's a good starting point.
> The problem with computers is that they do what you tell them to do and not what you want them to do. <
> Life: great graphics, but the gameplay sux. <
|
|
|
|
|
That is not quite what we were looking for because we are using pure Win32, no MFC. However it did lead me to find this so for that you have my thanks. I spent ages looking on the MSDN site for something like that.
Steve
|
|
|
|
|
char devstring[256]; // array for WIN.INI data
HANDLE printer;
LPDEVMODE devMode = NULL;
DWORD structSize, returnCode;
GetProfileString("Devices", printerName, "", devstring, sizeof(devstring));
char *driver = strtok (devstring, (const char *) ",");
char *port = strtok((char *) NULL, (const char *) ",");
if (!driver || !port) {
MessageBox(win->hwndFrame, "Printer with given name doesn't exist", "Printing problem.", MB_ICONEXCLAMATION | MB_OK);
return;
}
BOOL fOk = OpenPrinter((LPSTR)printerName, &printer, NULL);
if (!fOk) {
MessageBox(win->hwndFrame, _TR("Could not open Printer"), _TR("Printing problem."), MB_ICONEXCLAMATION | MB_OK);
return;
}
HDC hdcPrint = NULL;
structSize = DocumentProperties(NULL,
printer, /* Handle to our printer. */
(LPSTR) printerName, /* Name of the printer. */
NULL, /* Asking for size, so */
NULL, /* these are not used. */
0); /* Zero returns buffer size. */
devMode = (LPDEVMODE)malloc(structSize);
if (!devMode) goto Exit;
// Get the default DevMode for the printer and modify it for your needs.
returnCode = DocumentProperties(NULL,
printer,
(LPSTR) printerName,
devMode, /* The address of the buffer to fill. */
NULL, /* Not using the input buffer. */
DM_OUT_BUFFER); /* Have the output buffer filled. */
if (IDOK != returnCode) {
// If failure, inform the user, cleanup and return failure.
MessageBox(win->hwndFrame, "Could not obtain Printer properties", "Printing problem.", MB_ICONEXCLAMATION | MB_OK);
goto Exit;
}
..........
if (bitmapDx >bitmapDy) {
devMode->dmOrientation = DMORIENT_LANDSCAPE;
} else {
devMode->dmOrientation = DMORIENT_PORTRAIT;
}
DocumentProperties(NULL,
printer,
(LPSTR) printerName,
devMode, /* Reuse our buffer for output. */
devMode, /* Pass the driver our changes. */
DM_IN_BUFFER | /* Commands to Merge our changes and */
DM_OUT_BUFFER); /* write the result. */
ClosePrinter(printer);
hdcPrint = CreateDC(driver, printerName, port, devMode);
if (!hdcPrint) {
MessageBox(win->hwndFrame, "Couldn't initialize printer", "Printing problem.", MB_ICONEXCLAMATION | MB_OK);
goto Exit;
}
PRINTPAGERANGE pr;
pr.nFromPage =1;
pr.nToPage =win->dm->pageCount();
if (CheckPrinterStretchDibSupport(win->hwndFrame, hdcPrint))
PrintToDevice(win->dm, hdcPrint, devMode, 1, &pr , pt);
Exit:
free(devMode);
DeleteDC(hdcPrint);
}
|
|
|
|
|
static bool CheckPrinterStretchDibSupport(HWND hwndForMsgBox, HDC hdc)
{
// most printers can support stretchdibits,
// whereas a lot of printers do not support bitblt
// quit if printer doesn't support StretchDIBits
int rasterCaps = GetDeviceCaps(hdc, RASTERCAPS);
int supportsStretchDib = rasterCaps & RC_STRETCHDIB;
if (supportsStretchDib)
return true;
MessageBox(hwndForMsgBox, "This printer doesn't support StretchDIBits function", "Printing problem.", MB_ICONEXCLAMATION | MB_OK);
return false;
}
static void PrintToDevice(DisplayModel *dm, HDC hdc, LPDEVMODE devMode, int nPageRanges, LPPRINTPAGERANGE pr, int printRange = 0) {
................
DOCINFO di = {0};
di.cbSize = sizeof (DOCINFO);
di.lpszDocName = filename;
if (StartDoc(hdc, &di) <= 0)
return;
.................
SetMapMode(hdc, MM_TEXT);
int printAreaWidth = GetDeviceCaps(hdc, HORZRES);
int printAreaHeight = GetDeviceCaps(hdc, VERTRES);
int topMargin = GetDeviceCaps(hdc, PHYSICALOFFSETY);
int leftMargin = GetDeviceCaps(hdc, PHYSICALOFFSETX);
.........
// use pixel sizes for printer with non square pixels
float fLogPixelsx= (float)GetDeviceCaps(hdc, LOGPIXELSX);
float fLogPixelsy= (float)GetDeviceCaps(hdc, LOGPIXELSY);
bool bPrintPortrait=fLogPixelsx*printAreaWidth<flogpixelsy*printareaheight;>
BOOL isSameFile = IsSameFile(dm);
int realWidth = printAreaWidth;
int realHeight = printAreaHeight;
// print all the pages the user requested unless
// bContinue flags there is a problem.
for (int i=0; i < nPageRanges; i++) {
assert(pr->nFromPage <= pr->nToPage);
for (DWORD pageNo = pr->nFromPage; pageNo <= pr->nToPage; pageNo++) {
............
StartPage(hdc);
..............
bmp->stretchDIBits(hdc, leftMargin, topMargin, realWidth, realHeight);
delete bmp;
if (EndPage(hdc) <= 0) {
AbortDoc(hdc);
return;
}
}
pr++;
}
Error:
EndDoc(hdc);
}
|
|
|
|
|
also you can do like this:
PRINTDLGEX pd;
LPPRINTPAGERANGE ppr=NULL;
.......
ZeroMemory(&pd, sizeof(PRINTDLGEX));
pd.lStructSize = sizeof(PRINTDLGEX);
pd.hwndOwner = hwndFrame;
pd.hDevMode = NULL;
pd.hDevNames = NULL;
pd.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE | PD_NOSELECTION;
pd.nCopies = 1;
/* by default print all pages */
pd.nPageRanges =1;
pd.nMaxPageRanges = MAXPAGERANGES;
ppr = (LPPRINTPAGERANGE)malloc(MAXPAGERANGES*sizeof(PRINTPAGERANGE));
pd.lpPageRanges = ppr;
ppr->nFromPage = 1;
ppr->nToPage = dm->pageCount();
pd.nMinPage = 1;
pd.nMaxPage = dm->pageCount();
pd.nStartPage = START_PAGE_GENERAL;
if (PrintDlgEx(&pd) == S_OK) {
if (pd.dwResultAction==PD_RESULT_PRINT) {
if (CheckPrinterStretchDibSupport(hwndFrame, pd.hDC)){
if (pd.Flags & PD_CURRENTPAGE) {
pd.nPageRanges=1;
pd.lpPageRanges->nFromPage=currentPageNo();
pd.lpPageRanges->nToPage =currentPageNo();
} else if (!(pd.Flags & PD_PAGENUMS)) {
pd.nPageRanges=1;
pd.lpPageRanges->nFromPage=1;
pd.lpPageRanges->nToPage =pageCount();
}
PrintToDevice(dm, pd.hDC, (LPDEVMODE)pd.hDevMode, pd.nPageRanges, pd.lpPageRanges);
}
}
}
else {
if (CommDlgExtendedError()) {
/* if PrintDlg was cancelled then
CommDlgExtendedError is zero, otherwise it returns the
error code, which we could look at here if we wanted.
for now just warn the user that printing has stopped
becasue of an error */
MessageBox(win->hwndFrame, "Cannot initialise printer", "Printing problem.", MB_ICONEXCLAMATION | MB_OK);
}
}
free(ppr);
if (pd.hDC != NULL) DeleteDC(pd.hDC);
if (pd.hDevNames != NULL) GlobalFree(pd.hDevNames);
if (pd.hDevMode != NULL) GlobalFree(pd.hDevMode);
}
|
|
|
|
|
You will need to put all GDI calls between StartDoc /EndDoc and StartPage /EndPage APIs.
The Doc indicates a print job and the Page indicates a new page.
So basically you will have one pair of StartDoc /EndDoc and several pairs of StartPage /EndPage (One for each page).
«_Superman_»
|
|
|
|
|
|
I'm trying to compile the SysInternals Native app[^] for XP x64 (and other Windows x64 ), so I can create an app which can run during boot-time (similar to chkdsk), but am not having much luck. As SysInternals have stopped supplying native.xip, you can get it from
http://www.dowers.net:8080/ftp/Programs/InsideWin2000/Sysinternals-Website/NATIVE.ZIP[^]
I've installed the Windows Server 2003 DDK, and have started a Windows Server 2003 Free x64 Build environment (using the shortcut). I've then copied all the Native sources and makefile to ddk\inc, as instructed to do so at the bottom of the linked article. However, when I run build.exe, I get two identical errors:
C:\WINDDK\3790~1.183\inc>build
BUILD: Adding /Y to COPYCMD so xcopy ops won't hang.
BUILD: Using 4 child processes
BUILD: Object root set to: ==> objfre_wnet_AMD64
BUILD: Compile and Link for AMD64
BUILD: Computing Include file dependencies:
BUILD: Examining c:\winddk\3790~1.183\inc directory for files to compile.
c:\winddk\3790~1.183\inc - 1 source files (82 lines)
BUILD: Saving C:\WINDDK\3790~1.183\build.dat...
BUILD: Compiling (NoSync) c:\winddk\3790~1.183\inc directory
1>errors in directory c:\winddk\3790~1.183\inc
1>c:\winddk\3790~1.183\bin\makefile.new(1106) : error U1050: Setting TARGETPATH=
C:\WINDDK\3790~1.183\lib in .\sources is not valid - please use obj.
BUILD: nmake.exe /nologo BUILDMSG=Stop. -i NTTEST= UMTEST= NOLINK=1 NOPASS0=1 PA
SS1_NOLIB=1 AMD64=1 failed - rc = 2
BUILD: Compiling c:\winddk\3790~1.183\inc directory
100>c:\winddk\3790~1.183\bin\makefile.new(1106) : error U1050: Setting TARGETPAT
H= C:\WINDDK\3790~1.183\lib in .\sources is not valid - please use obj.
BUILD: nmake.exe failed - rc = 2
BUILD: Compile errors: not linking c:\winddk\3790~1.183\inc directory
BUILD: Done
0 files compiled - 2 Errors
What exactly does the error mean ?
1>c:\winddk\3790~1.183\bin\makefile.new(1106) : error U1050: Setting TARGETPATH=
C:\WINDDK\3790~1.183\lib in .\sources is not valid - please use obj.
How can I fix it ?
Is there any good information on how to correctly setup a build environment for building native apps for both x86 and x64 ?
|
|
|
|
|
You might have much better luck posting your question on a site that's devoted to driver development. They know all about this kind of stuff.
Try this site:
http://www.osronline.com/[^]
Good luck!
|
|
|
|
|
I think you should install the latest version of the DDK (WDK).
The one you are using is very old and probably does not support x64.
The new version, the last time I looked was something like 6001.18002.
«_Superman_»
|
|
|
|
|
Hi.
I'm new in c/c++... and I'm a little confused...
I made a dll in c/c++ (using some example I saw on-line), and now I want to load it in a new project, but it doesn't work.
I paste the dll file in the project debug folder, and I'm using
HINSTANCE myDll = LoadLibrary((LPCWSTR)"TestingDll.dll");
to access to it, but myDll is always empty...Can anyone tell me what possible I'm doing wrong?
Thanks
|
|
|
|
|
All the various dlls that TestingDll.dll is dependent on wuould not be present.
Check out the dependencies of TestingDll.dll using depends.exe and paste all those dlls also in the same folder.
|
|
|
|
|
Thanks for your atention...
At the beginning I thought that was the problem and decided to do something very basic for testings, but I still can not access to it.
For my testings I made:
//MyDll.cpp
#include "MyDll.h"
namespace Functions{
Person MyFunctions::first() {
struct Person myPerson;
myPerson.name = "asd";
myPerson.age = 123;
return myPerson;
}
}
//MyDll.h
namespace Functions{
struct Person {
char *name;
int age;
};
class MyFunctions {
public:
static __declspec(dllexport) Person first();
};
}
Then the DLL file I paste in the new project folder (only this one, because for my point of view I don't need nothing more, because it is very simple and doesn't use/depend nothing more ), right?
In the new project I made:
#include "stdafx.h"
#include "windows.h"
using namespace System;
int main(array<System::String ^> ^args){
HINSTANCE myDll = LoadLibrary((LPCWSTR)"TestingDll.dll");
if(myDll) {
Console::WriteLine("DLL loaded \n");
}
else {
Console::WriteLine("DLL failed to load \n");
}
return 0;
}
And the result always is -> "DLL failed to load".
It doesn't returns any error, but doesn't do what I want .
I apologize, but due to my inexperience I did not understand the problem that could cause this ( for sure is something that I'm doing wrong, or forget).
Can you help me?
|
|
|
|
|
From LoadLibrary documentation [^].
Return Value
If the function succeeds, the return value is a handle to the module.
If the function fails, the return value is NULL. To get extended error information, call GetLastError.
BTW possibly you should put the DLL inside the project folder.
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
Thanks for your atention...
I already have the DLL inside the new project folder, but it still not work and I couldn't understand what could be the cause of this, because it doesn't return any error...
|
|
|
|
|
As stated by the documentation I linked in my previous post, if the LoadLibrary return HANDLE is NULL then you have to call GetLastError in order to get some understanding of what's happening.
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
Perhaps your quote on Creation could be applied to the other Lord who has created so many dialects of C with so many obscure confusions in syntax.
Regards
Ron
|
|
|
|
|
Maybe. Anyway, strictly speaking, the obstacles that are hurting the OP are functions of an application programming interface (Win32 API ): he isn't dealing with a C language dialect.
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
Again, CByteArray members GetData & GetSize (togheter with std::string constructor) do the trick, for instance:
CByteArray arr;
arr.Add(0xff);
arr.Add(0x00);
arr.Add(0x10);
arr.Add(0x41);
std::string str((char*) arr.GetData(), arr.GetSize());
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
Are you using Visual Studio 2005 or 2008?
You may notice that the Visual Studio puts your exe in a folder called "debug" at the same level as your project folder.
The "debug" folder that's inside your project folder holds only the obj files, and the exe does not run from there.
You have to make sure that you put the DLL into the same folder where the exe file is created.
Solution Folder<br />
|<br />
|---Project Folder<br />
| |<br />
| |-Debug<br />
|<br />
|---Debug <= Put dll here<br />
|
|
|
|
|
I'm using Visual Studio 2008.
I had been careful to paste the DLL in the folder with the .exe file... But it still doesn't work...
It is the first time I tried to do a DLL, it is possible I forgot something, or maybe I'm doing something wrong...
|
|
|
|
|
Does your DllMain() function return TRUE?
A Dll will only load if its DllMain() function returns TRUE.
|
|
|
|
|
I think my DLL code is correct, because I used the DLL in a c# project and it loaded and worked just fine.
My problem is to load in a c++ project.
I read that if we want to use a DLL without de lib file, we must paste de DLL file in the debug project folder (and I did it, because I want it to work without the code files).
Then I used
HINSTANCE myDll = LoadLibrary((LPCWSTR)"Testing.dll");
if(myDll)
Console::WriteLine("DLL loaded \n");
else
Console::WriteLine("DLL failed to load \n");
it always "DLL failed to load ", it doesn't return any error.
Did I forgot something, or am I doing something wrong? (I'm starting with c++, so possible I'm making some mistake).
Thanks.
|
|
|
|
|
Change your code so that it reads as follows:
HINSTANCE myDll = LoadLibrary((LPCWSTR)"Testing.dll");
DWORD Error = GetLastError();
if (myDll)
Console::Writeline("Dll Loaded");
else
Console::Writeline("Dll Not Loaded");
Put a breakpoint at the line that says "Not Loaded."
When the program breaks, inspect the value of the variable Error.
That will be the Windows error code for what went wrong. Post the Error code here, and maybe we can help you figure it out.
|
|
|
|
|