|
thanks for reply Johan.
I have done what you suggested.
BOOL CReportGenerator::Print()
{
1: BOOL result = FALSE;
2: CPrintDialog printer( FALSE );
3:
4: if( printer.GetDefaults() )
5: {
6: HDC hdcPrinter = printer.GetPrinterDC();
7: CDC dc;
8: dc.Attach( hdcPrinter );
9: Print( &dc );
10: dc.EndDoc();
11: }
12: return result;
}
After stepping over the 6th line in debug mode, the value of hdcPrinter is "0x8e211160 unused=???" I think this is the problem.
Or maybe I am missing somethink very simple.
I would be thankful to you, if you could write me simple steps which I need to take in order to print very simple report.
"Success is the ability to go from one failure to another with no loss of enthusiasm." - W.Churchill
|
|
|
|
|
I think it is ok this far. An as a matter of a fact, it is easy to print - you should basically need no more than that stuff. Did you try the demo app, will it print? Have you tried stepping further down into the Print() on line 9?
|
|
|
|
|
Hi Johan, I have fixed everything finally and voted for you 5, wanted to vote more but could not
thanks for help.
PS.Instead of writing c:\\ I had written c:\ when setting the path of template file and had never paid att to it anymore that was the problem
"Success is the ability to go from one failure to another with no loss of enthusiasm." - W.Churchill
|
|
|
|
|
Giorgi Moniava wrote: I had written c:\ when setting the path
This is not an uncommon error
|
|
|
|
|
The task is to develop app for printing pictures. User selects pictures from file and I would like to automatically load these pictures into the doc with template created by ReportCreator. Is it possible to dynamically add pictures from file?
Tom
|
|
|
|
|
You can create fields at runtime and also access the field attributes, so this is indeed possible. The documentation has all the gory details.
|
|
|
|
|
Thank you for your truly excellent program.
The bitmap on a report shows up when rpt file is selected through a dialog, but when I specify the name directly it does not (everything else shows up).
rg.SetReportfile(pth+"\\Rep.rpt");
CarlH
|
|
|
|
|
Carl,
Given that the bitmap is a reference to a file rather than embedded data, this might not be so surprising - lots of stuff can go wrong. You might want to place the bitmap at the same location as the report file, and make sure that the reference in the rpt-file (it is a text file so you can read it in any editor) only contains the bmp-name - that is, not the path to it. You might also want to put a breakpoint in the image object, to see that it is trying to load from the location you expect.
It is less than satisfacory to have reports referencing external files - it makes them too brittle, but adding them into the report file was just not an option.
|
|
|
|
|
Hi Johan,
First, I'd like to thank you for this nice utility.
However, I've been experiencing the same problem with printing a bitmap. After digging in the code, I've found that the CDrawPicture::FromString method sets the filename from the title parameter of the report_picture: object. This only contain the filename without the path information, and thus only succeeds if the file is in the cwd of the application. Since I load my template file from a subdir, it was failing to display a bitmap file saved in that same directory. Moving the bitmap to the cwd fixed the problem.
I've noticed that the last param of the report_picture: object is not parsed at all and contain the whole file path. So adding
contents.GetAt( count++, filepath );
filepath.Replace( _T( "\\colon" ), _T( ":" ) );
in the CDrawPicture::FromString method (where filepath is a CString object), and setting the filename with it (result->SetFilename( filepath )) solved the problem for me.
Now, I'm not sure if you had a reason not to do it like that.
Thanks again!
Claude Vaillancourt
|
|
|
|
|
Claude,
This has indeed been the reason for much thinking on my part. It is documented that images will have to be placed in the same directory as the report files, if memory serves. The reason is that I didn't want relative paths (even lrss absolute!), due to the fragility of such. So, I would not want to generalize a solution leading to the impossibility to move the reports.
|
|
|
|
|
Hi,
I have report template with report header and report body. In report body I need place two fields which will present large text but in fact I don't how big these fields should be to hold and present whole text. The best solution will be to set these fields to a minimal size in report templete and let them to widen to fit whole text. How can I cope with this problem??
Thanks a lot
Shark
|
|
|
|
|
I would in fact rather try to make them as big as possible. It they are placed based on each other, that is, one field should be located just after the other, this might not be possible however. In this case, you'll have to create a printer CDC , create a font matching the font you'll use for printing, and then loop all the texts, calling GetTextExtent for each string.
|
|
|
|
|
Thanks,
I can try make them as big as possible but what when the text is longer than one page. In the template editor I can widen these field to fit whole page, but reported text is longer that one page.How can I make it to be continued on several pages?
Thanks a lot
shark
|
|
|
|
|
Oooo, that is not possible without some trickery. What I would do would be to create a single column grid. Then I would split the text into lines, putting each line in the grid (the the report will then print the grid on as many pages as necessary).
How to split the text then? Well, you could write a function that gets a printer CDC and then uses GetTextExtent to walk the text and split it into lines that will fit in a single cell (that is, line).
|
|
|
|
|
The article looks very promising, to begin with.
I've downloaded all files, unpacked it and started playing. Started 'ReportCreator.exe', created a very simple report with a couple of fields. Then, started 'ReportGeneratorDemo.exe', loaded the report, created and saved in the first step. The message box said that the report had being loaded and it is ready to print. Calling up the print preview - shows three empty pages ... Then I realized, that re-opening the report(s) with the 'ReportCreator.exe', also brings up a clean white sheet. Nothing to see from the stuff that was put on it in the first step. Opening the .prt file in an editor however shows the stuff that was created:
(
paper:793,1122;
report_label ,697917,0,656250,2,208333,1,093750,Label,$app_name,0,Times New Roman,120,0,0,0,0,0,0,1,3381756,2,1243436;;
)
I'm using XP, Sp2. Any known issues with that?
Regards,
|
|
|
|
|
The problem is the delimiters. If you look at the first part of the saved label:
report_label ,697917
the value is a location - and it should be 0.697917 etc., in fact, the line should read
report_label .697917,0.656250,2.208333,1.093750,Label,$app_name,0,Times New Roman,120,0,0,0,0,0,0,1,3381756,2,1243436;;
Have you perhaps incorporated the editor in an app that sets the locale, thus using the comma instead of the decimal point?
|
|
|
|
|
Now that you brought that up, I think I know what's the reason for the failure: the local for the double format. Since I've run your binaries and did not changed anything on the file that had being created, I'm sure that this is the reason. I've had the very same problem a while ago in our company where a report (created by a application written in cpp) that contained some double number could not be imported into Excel at a customer. I turned out that to be the problem I've described above, the delimiter in the doubles where wrong.
Regards
|
|
|
|
|
What is embarassing is that me, being Swedish, actually uses the decimal comma rather than the point
|
|
|
|
|
|
When clicking on an object (label or field) in the DiagramEditor the object may move slightly. I assume this is because the code catches the left button down and the small inadvertent mouse move before it sees the left button up.
Most similar apps do not have the same problem. It would be nice if the DiagramEditor could discern between single clicks and true click and drag events.
Anyone have a work around for this?
|
|
|
|
|
Your analysis is indeed true. This might - for example - be fixed by not starting to register mouse movement until a certain (small) time has elapsed, or perhaps by discarding movements under a given amount of pixels. It is slightly difficult, however, to find a good general solution - note that the underlying vector editor is a general class.
|
|
|
|
|
Hi Again,and have good time
dear johan
as i read your docs about R.G. you had used inch for internal measurments.but i notice this is only when you archive them.
the problem arises when CUnitConversion is not yet initialized and s_resolution is zero or something else other than load time.
you can reproduce this by adding
BOOL CReportCreatorApp::InitInstance()<br />
{<br />
......<br />
ParseCommandLine(cmdInfo);<br />
<br />
cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing;<br />
if (!ProcessShellCommand(cmdInfo))<br />
return FALSE;<br />
......<br />
}
and try to load a saved report.
this may be simplly solved by initializing CUnitConversion but i think this valuable code must be independent of Application and it is better CDiagramEntityContainer be aware of resulotion used for it's objects and have correction methods for resolution changs.
REGARDS Peiman
|
|
|
|
|
Thanks for the suggestion! Another idea that comes to mind is to let CUnitConversion self-initialize. I'm getting slightly desperate when it comes to updating the article, though
|
|
|
|
|
Hello there,
I see some questions on the forum regarding this subject, I have solved it for myself through the following function. If you call this function like this
int PreviousOrientation = SetDefaultPrinterOrientation(DMORIENT_LANDSCAPE);
It will switch printing to Landscape, and you can use the returned value to set it back to whatever it was set before the call, by passing that value and calling it again.
Hope someone can find this useful
Cheers
Alex
#include "winspool.h"
int SetDefaultPrinterOrientation(short dmOrientation)
{
HANDLE hPrinter = NULL;
DWORD dwNeeded = 0;
PRINTER_INFO_2 *pi2 = NULL;
DEVMODE *pDevMode = NULL;
PRINTER_DEFAULTS pd;
BOOL bFlag;
LONG lFlag;
LPTSTR pPrinterName = NULL;
DWORD size;
GetDefaultPrinter(NULL, &size);
TCHAR* buffer = new TCHAR[size];
if(GetDefaultPrinter(buffer, &size))
pPrinterName = buffer;
else
{
if(buffer != NULL)
delete buffer;
return 0;
}
// Open printer handle (on Windows NT, you need full-access because you
// will eventually use SetPrinter)...
ZeroMemory(&pd, sizeof(pd));
pd.DesiredAccess = PRINTER_ALL_ACCESS;
bFlag = OpenPrinter(pPrinterName, &hPrinter, &pd);
if (!bFlag || (hPrinter == NULL))
{
if(buffer != NULL)
delete buffer;
return 0;
}
// The first GetPrinter tells you how big the buffer should be in
// order to hold all of PRINTER_INFO_2. Note that this should fail with
// ERROR_INSUFFICIENT_BUFFER. If GetPrinter fails for any other reason
// or dwNeeded isn't set for some reason, then there is a problem...
SetLastError(0);
bFlag = GetPrinter(hPrinter, 2, 0, 0, &dwNeeded);
if ((!bFlag) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER) || (dwNeeded == 0))
{
ClosePrinter(hPrinter);
if(buffer != NULL)
delete buffer;
return 0;
}
// Allocate enough space for PRINTER_INFO_2...
pi2 = (PRINTER_INFO_2 *)GlobalAlloc(GPTR, dwNeeded);
if (pi2 == NULL)
{
ClosePrinter(hPrinter);
if(buffer != NULL)
delete buffer;
return 0;
}
// The second GetPrinter fills in all the current settings, so all you
// need to do is modify what you're interested in...
bFlag = GetPrinter(hPrinter, 2, (LPBYTE)pi2, dwNeeded, &dwNeeded);
if (!bFlag)
{
GlobalFree(pi2);
ClosePrinter(hPrinter);
if(buffer != NULL)
delete buffer;
return 0;
}
// If GetPrinter didn't fill in the DEVMODE, try to get it by calling DocumentProperties...
if (pi2->pDevMode == NULL)
{
dwNeeded = DocumentProperties(NULL, hPrinter,pPrinterName,NULL, NULL, 0);
if (dwNeeded <= 0)
{
GlobalFree(pi2);
ClosePrinter(hPrinter);
if(buffer != NULL)
delete buffer;
return 0;
}
pDevMode = (DEVMODE *)GlobalAlloc(GPTR, dwNeeded);
if (pDevMode == NULL)
{
GlobalFree(pi2);
ClosePrinter(hPrinter);
if(buffer != NULL)
delete buffer;
return 0;
}
lFlag = DocumentProperties(NULL, hPrinter,pPrinterName, pDevMode, NULL,DM_OUT_BUFFER);
if (lFlag != IDOK || pDevMode == NULL)
{
GlobalFree(pDevMode);
GlobalFree(pi2);
ClosePrinter(hPrinter);
if(buffer != NULL)
delete buffer;
return 0;
}
pi2->pDevMode = pDevMode;
}
// Driver is reporting that it doesn't support this change...
if (!(pi2->pDevMode->dmFields & DM_ORIENTATION))
{
GlobalFree(pi2);
ClosePrinter(hPrinter);
if (pDevMode)
GlobalFree(pDevMode);
if(buffer != NULL)
delete buffer;
return 0;
}
// Specify exactly what we are attempting to change...
pi2->pDevMode->dmFields = DM_ORIENTATION;
// Make note of the current Orientation setting
// If the functions works, return it to the calling program
// So that, the application can set it back to whatever
// it used to be before the call
int OriginalOrientation = pi2->pDevMode->dmOrientation;
// Now, change it to whatever was requested by the calling application
pi2->pDevMode->dmOrientation = dmOrientation;
// Do not attempt to set security descriptor...
pi2->pSecurityDescriptor = NULL;
// Make sure the driver-dependent part of devmode is updated...
lFlag = DocumentProperties(NULL, hPrinter, pPrinterName, pi2->pDevMode, pi2->pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER);
if (lFlag != IDOK)
{
GlobalFree(pi2);
ClosePrinter(hPrinter);
if (pDevMode)
GlobalFree(pDevMode);
if(buffer != NULL)
delete buffer;
return 0;
}
// Update printer information...
bFlag = SetPrinter(hPrinter, 2, (LPBYTE)pi2, 0);
if (!bFlag) // The driver doesn't support, or it is unable to make the change...
{
GlobalFree(pi2);
ClosePrinter(hPrinter);
if (pDevMode)
GlobalFree(pDevMode);
if(buffer != NULL)
delete buffer;
return 0;
}
// Tell other apps that there was a change...
SendMessageTimeout(HWND_BROADCAST, WM_DEVMODECHANGE, 0L,(LPARAM)(LPCSTR)pPrinterName, SMTO_NORMAL, 1000, NULL);
// Clean up...
if (pi2)
GlobalFree(pi2);
if (hPrinter)
ClosePrinter(hPrinter);
if (pDevMode)
GlobalFree(pDevMode);
if(buffer != NULL)
delete buffer;
return OriginalOrientation;
}
|
|
|
|
|
Thanks for this useful addition. Personally, I think the above should be made a mini-article of its own.
|
|
|
|
|