Generate PDF using QuickReport from a Windows Service in Delphi - delphi

I'm writing a windows service using Delphi XE3. The service is going to read from a database, generate a pdf using quickreport 5.05.1.
I plan to generate the pdf using TQRPDFDocumentFilter.
Everything works fine in a normal VCL application, but when I implement it in a windows service the service hangs (without any exceptions) when I do a QuickRep.Prepare.
I have read that it is possible to use QuickReport in a windows service, but I do not know how. Any suggestions?
Where is the code:
procedure foo
var
pdfFilter: TQRPDFDocumentFilter;
begin
with TForm2.Create(Self) do
begin
ClientDataSet1.Open;
QuickRep1.Prepare;
pdfFilter := TQRPDFDocumentFilter.Create(GetApplicationFolder() + 'test.pdf');
try
QuickRep1.QRPrinter.ExportToFilter(pdfFilter);
finally
pdfFilter.Free;
ClientDataSet1.Close;
end;
end;
end;
Edit:
I have also tried turning off "show progress" on the QuickReport as suggested in another thread.
Writing some code to catch an exception reveals that it indeed throws one. The message is "There is no default printer currently selected".
So this leads me to believe that the local system user that the service is running under does not have any printers installed and that this is the problem.

I have resolved a similar problem (printing to a shared network printer from a Java server running as a Windows service) with these steps:
log on as the user who will run the service
install the printer
IIRC with Delphi applications, the printer name is not case sensitive (with Java it is).

Related

How to solve exception error when consuming Microsoft Sql Server Reporting Services (SSRS) 2005 from Delphi XE7

I am trying to create a sample Delphi XE7 desktop app that will connect to SSRS 2005 web service but every time I try to call LoadReport web method, the following error is shown:
This is what I have done so far:
Create a desktop app.
Import WSDL for ReportExecution2005 and ReportService2005.
Create a button that call the web service based on the code shown
here. The web service locations as well as report are hardcoded for
simplicity purposes.
This is the code snippet from the link:
HTExec := tHttpRio.Create(nil);
rsExec := GetReportExecutionServiceSoap(False, ExecURL, HTExec);
// Load the selected report.
LRParams.Report := 'ReportName';
LoadParamsResponse := rsExec.LoadReport(LRParams); //here it fails
Note: I have already created a .NET win form app (VS2010 and VS2013) that consumes this web service without any issues, thus I know the web service and report to render are working OK. Sadly our requirements is for a Delphi solution, My educated guess is that the WSDL importer generated code is not correct and somebody out there may have come across with this issue before and know how to solve it.
I did a quick search for "http://schemas.microsoft.com/sqlserver/2005/06/30/reporting/reportingservices/LoadReport"
and found this.
If it applies to you as well, it may be the case you're calling the service on an incorrect URL, use the one with ReportExecution2005.asmxin it, not ReportService2005.asmx
(There's a lot more here)
To find out differences between the Delphi version and the working version, use a HTTP proxy (Fiddler2) to capture the SOAP HTTP traffic in both setups.
If you have no access to the working environment, use SoapUI to create SOAP requests.

Delphi - Write/read files in a shared environment

I have some problems on files which are placed in a LAN: there is a single Delphi program (server) which should write some files, which can be only read by multiple Deplhi programs (clients).
I use these simple instructions in the server for writing (DataList is a TStrings):
Stream:=TFileStream.Create(filePath,fmOpenWrite or fmShareDenyWrite);
try
DataList.SaveToStream(Stream);
finally
Stream.Free;
end;
The clients check every 5 seconds if the file above is modified (by just checking the FileAge), and if modifications are occurred, they load the DataList in the following way:
try
Stream:=TFileStream.Create(filePath,fmOpenRead or fmShareDenyNone);
DataList.LoadFromStream(Stream);
finally
Stream.Free;
end;
Normally everything works perfectly, but sometimes it happens that the server or the client raise an exception because "the file is in use by other process".
I don't understand which is the problem: I tried many alternatives, but this can happen also with just the server and only one istance of the client running..
Any ideas?
Thanks!
By design, network file systems can't be trusted. At least, NFS (in Linux) and SMB (in Windows) have no proven lock feature: concurrent access is not safe.
You need to use a Client-Server protocol to ensure that shared data is safe. You can use TCP/IP, HTTP or any other mean.
I recommend using a true service implementation, like DataSnap, RemObjects or our Open Source mORMot.

Why does GetActiveObject fail to detect running instance of Outlook?

I am facing an issue in my windows7 32bit Pc(on i3).I have Outlook 2010 and Delphi 7 on it.
I am using following code to detect Outlook is running or not.
ClassID := ProgIDToClassID(ClassName);
Result := (GetActiveObject(ClassID, nil, Unknown) = S_OK);
This fails, ie, result become false and yet in other PCs this working fine.
The error I'm getting is MK_E_Unavailable.
Update:
May be it just happening with me only.
procedure TForm1.Button1Click(Sender: TObject);
function IsObjectActive(ClassName: string): Boolean;
var
ClassID: TCLSID;
Unknown: IUnknown;
begin
try
ClassID := ProgIDToClassID(ClassName);
Result := (GetActiveObject(ClassID, nil, Unknown) =S_OK );
except
Result := False;
end;
end;
begin
if IsObjectActive('Outlook.Application') Then
ShowMessage('OutLook is there.')
else
ShowMessage('OutLook is not there.')
end;
Plz note OL is running and
When I am running the created exe, I am getting message "OutLook is there".
when I am running from Delphi IDE, I am getting Message 'OutLook is not there.'
This happens always, I am using Delphi 7 on Windows 7, running with Run as Admin. Kindly tell me why this happening and how can I fix this.
What's the issue of Delphi 7 on Windows 7.
Please suggest.
Here's the entry for GetActiveObject.
http://msdn.microsoft.com/en-us/library/a276e30c-6a7f-4cde-9639-21a9f5170b62%28VS.85%29
If you want to decode the error, you need to find out what the HResult means.
Wikipedia has a link to a ERR.EXE utility from MS that will translate the HResult code into an error description. For COM HResults see: http://matthewbass.com/2005/11/15/decoding-com-hresult-error-codes/.
note the download link in the article is broken, here's a working link: http://www.softlookup.com/display.asp?id=7113
Once you know what the error is, update the question.
If you want to know whether a process is running without using OLE, see: How to check if a process is running using Delphi?
Another option might to use FindWindowEx to check for Outlook 2010 specific windows.
You can use WinID (a spy++ clone) to see the windows used by Outlook 2010.
I was facing the same issue and I found the solution.
It's simple, If Outlook is already running, it MUST have the same rights as the process that is trying to use it.
In simple words, if you are running Outlook with admin rights, you must execute your app with admin rights.
Your problem must be that you are running Outlook without admin rights, and Delphi IDE with admin rights. So when you are launching your app from within IDE, the rights doesn't match, and you get the error. This is why when running your app outside the IDE it works as expected. Because outside IDE your app runs without admin rights.
Try to match the rights. This is something to take into account for the end user environment too.
Also, the UAC under Windows Vista and later is known to cause multiple issues with these type of things. If everything else fails, disable UAC (User Account Control, you will find it under your account options) and see what happens.
try to use rctrl_renwnd32
try this:
(FindWindow('rctrl_renwnd32', nil) <> 0)
http://users.skynet.be/am044448/Programmeren/VBA/vba_class_names.htm

Indy 10 Delphi FTP Client Demo Error

I am new to Delphi and wanted to try breaking down a demo to understand the it's structure.
I am trying to get the Indy 10 Delphi FTP Client demo to run on Delphi XE2.
Whenever I run the downloaded code, I enter the FTP URL, Username, Password etc and when the FTP connects this error appears:
raised exception class $C00000005 with message 'access violation at
0x0018f90e: write of address 0x0000000'
Which I assume it means it's pointing at a null?
The debugging tool simple points at this line..
ChangeFTPDir(Sites[cbFTPAddress.ItemIndex].RootDir);
What would be the best way of removing this error (try/catch) or is there a working sample of a Delphi FTP procedure that I could have a look at?
Thanks for your time in advance,
Sophie
The procedure is as below:
procedure TfrmMain.ChangeFTPDir(NewDir: String);
begin
FLastDirStack.Add(FTP.RetrieveCurrentDir);
FTP.ChangeDir(NewDir);
DisplayFTP;
end;
I assume that the site array does contain details as the ftp does connect to the name of the stored ftp site before the error appears...
Did you use IdAllFTPListParsers ? Try it.

QuickReport throws "There Is No Default Printer Currently Selected" Exception

I have created a Delphi Service which prints TQuickReports. Everything works fine if compiled and run as a Windows Application. But when converted to operate as a service trying to create a form containing a TQuickRep component throws the exception.
This service runs fine on many other boxes but not this one in particular. Here are some details:
Using QuickReport version 4.07
Box is a Windows Server 2008 operating system.
Using Delphi 2007
Printer.Printers.Count is returning a positive value. In fact I can list out all of the printers.
I have tried running the service both using Local System Account and Logged on as an Admin.
Is there a default printer set up in session 0? Remember that under Vista / Server 2008 / Windows 7, services run in a separate session. Whether or not the logged-in user has a default printer set is not relevant - it's a per-session setting and doesn't affect session 0.
Can you rewrite the code to gracefully handle that exception and pick a printer to use?
You can solve this problem by creating a new dword UserSelectedDefault with the value: 1 in
HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows\SessionDefaultDevices\Session_ID
Make sure you have a local printer selected.
You might give the user a way to select the printer for the service. The Windows service probably does not have a default printer set.
Set TQuickRep.PrinterSettings.PrinterIndex to set the printer number. Then, TQuickRep.Print to print the report.
A colleague ended up finding the solution. I should have added these are "network" printers and not Local printers (at the time I didn't think this was related to the problem). So the service needed to be installed with "NetworkService" as the user account under the logon tab. From the Windows Help:
To specify that the service uses the Network Service account, click This account, and
then type NT AUTHORITY\NetworkService
We had a simular problem here. Using TS servers, Citrix and Powerfuse 9.
Powerfuse had all printers capitalized, however they were shared in a mixed case.
This combination caused Delphi/QReport to crash
When all printers are from printserver to powerfuse in the same case (not important upper or lower or even mixed), the problem was gone
Actually it is a Delphi(5) problem. The comparison of the available printers and the default printer is case sensitive (Printers.pas):
if TPrinterDevice(Objects[I]).Device = Device then
begin
with TPrinterDevice(Objects[I]) do
SetPrinter(PChar(Device), PChar(Driver), PChar(Port), 0);
Exit;
end;
Changing the comparison to:
if lowercase(TPrinterDevice(Objects[I]).Device) = lowercase(Device)
solves the problem.
If using terminal services 2008, same user for multiple sessions, you should look into the:
HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows\SessionDefaultDevices\Session_ID
instead of
HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows\
I solved a similar problem: If a Delphi application (or service) uses QuickReport, it runs before the system loads the default printer (or printers).
When QuickReport executes TQRPrinter.Init, the printer.printers.count is zero,
shortly after the system loads, the printer.printers.count is the number of printers,
but tqrprinter.int has already executed, so TQRPrinter.FPrinterOK is false,
you then see this error when you try open a QuickReport.
The solution for me was wait until the printers were loaded before launching the application (in citrix and terminal server). I solved this in two ways, either by overwriting tqrprinter or delay the dpr.

Resources