Delphi, OLE and problems with Microsoft Scheduler - delphi

I have console Delphi application which works with Excell though OLE.
The examle of code is pretty simple
procedure SaveBaseRecordsToFile(BaseName: string; PaymentRecords: TPaymentRecords);
var
i: integer;
Excel: Variant;
begin
try
Excel:=CreateOleObject('Excel.Application');
Excel.DisplayAlerts:=False;
except
on E: Exception do begin
LogWriter.WriteLog(E.ClassName + ': ' + E.Message);
exit;
end;
end;
try
Excel.Workbooks.Add;
//Excel.Worksheets.Add;
Excel.Worksheets[1].Cells[2, 1].Value := 'Account number';
Excel.Worksheets[1].Cells[2, 2].Value := 'Sum';
for i := 0 to Length(PaymentRecords) - 1 do begin
Excel.Worksheets[1].Cells[i + 3, 1].Value := PaymentRecords[i].NUMBER;
Excel.Worksheets[1].Cells[i + 3, 2].Value := PaymentRecords[i].SUMMA;
end;
Excel.ActiveSheet.Name := 'SHEET1';
Excel.Application.Workbooks[1].SaveAs(ExtractFilePath(ParamStr(0)) + BaseName + '.xls', 56);
Excel.Workbooks.Close;
Excel.Quit;
finally
Excel := Unassigned;
end;
end;
When I run this application in interactive mode (by myself) it wors perfect.
But when I try to run it through standart Microsoft Scheduler I see in log of my applications such records:
21:41:40.523: EOleSysError: Отказано в доступе, ProgID: "Excel.Application" (Access denied from Russian)
If I set in schedule task option "Run with highest privileges" I see in log of my applications such records:
20:12:04.475: EOleException: Метод SaveAs из класса Workbook завершен неверно (SaveAs method of Workbook class finished incorrectly from Russian)
Is there any way to run application with OLE call through Microsort Scheduler?
Or maybe I can work with Excel without OLE (it's pretty simple operations as you could see in my examle)? How can I do it?

The fundamental issue is that Excel needs to run in an interactive desktop. Running through the task scheduler, as you have configured it, runs it in a non-interactive desktop. That's not a supported mode of operation for Excel: http://support.microsoft.com/kb/257757
Your only real hope of success is to create the Excel file without using COM automation of Excel. There are many libraries to help you do that.

Related

Reading Exif data usind CCR.Exif causing access violations

I have a programme, called ViewPhotos, that gives me problems when reading Exif data. I am using CCR.Exif (by Chris Rollistone). CCR.Exif does not reside in the project directory.
To figure out what is happening I created a small programme called TestExif, which consists of a form and a button that invokes the procedure shown below. I also copied the exact same procedure to ViewPhotos. TestExif is using the same unit CCR.Exif as ViewPhotos.
procedure TForm1.Button1Click(Sender: TObject);
var
ExifData: TExifData;
ADate: TDateTime;
OriginalDate: TDateTime;
Mes: string;
begin
ExifData := TExifData.Create;
try
ExifData.LoadFromGraphic('C:\000\APhotos\ADigital\2017\BlueMountains\PC090131.JPG');
ADate := ExifData.DateTime;
Mes := 'Date' + ' = ' + DateToStr(ADate) + #13;
OriginalDate := ExifData.DateTimeOriginal;
Mes := Mes + 'OriginalDate' + ' = ' + DateToStr(OriginalDate);
finally
ExifData.Free;
end;
ShowMessage(Mes);
end;
Now, I do the following:
Build ViewPhotos.
Run the Test-Procedure in ViewPhotos. This
generates an access violation.
Close ViewPhotos and open TestExif.
Run TestExif. This generates an access violation.
Build TestExif.
Run TestExif and get the expected result.
Close TestExif and open ViewPhotos.
Run ViewPhotos and get the proper result.
How can I find the cause of my problem and rectify it? What are the steps I should take?
The access violations are:
For CCR.Exif to compile correctly, the Syntax option for Complete boolean evaluation must be left false (which is the default setting).

TMemIniFile.Create hanging when called in ServiceStart

In a service running under system account the code below hangs in the TMemIniFile.Create without errors.
If we replace it with TIniFile, it works fine.
It's a Delphi Tokyo 10.2.3 Win32 app running under Windows Server 2012R2. There's no concurrent access to the INI file.
This is the first time (first client) we see this, it has been running fine on many machines.
I have no idea what to look for further. Any ideas?
It 'works' now because we switched to TIniFile, but I'd like to find the cause. From other posts I read here, TINIfile seems to be more finicky than TMemINIfile, my situation is the reverse.
There are no special characters in the INI file and it is created with an ASCII editor.
// This is set in the ServiceCreate:
FIniFileNaam := ChangeFileExt(ParamStr(0),'.INI');
// This is called from the ServiceStart:
procedure TTimetellServiceBase.LeesINI;
var lIniFile : TMemIniFile;
begin
LogMessage(FIniFileNaam, EVENTLOG_INFORMATION_TYPE, cCatInfo, cReadINI); // Logs to event log, we see this
FStartDir := ExtractFilePath(ParamStr(0));
if assigned(FLaunchThreadLijst) then FreeAndNil(FLaunchThreadLijst);
FLaunchThreadLijst := TStringList.Create;
try
if FileExists(FIniFileNaam) then
begin
// Lees waarden uit INI file
lIniFile := TMemIniFile.Create(FIniFileNaam); // This is the call that hangs. The service is unresponsive now.
try
FLaunchThreadLijst.CommaText := lIniFile.ReadString(INISECTIE_SERVICETASKS,'RunIniFiles','');
FMaxTaskDuration := lIniFile.ReadInteger(INISECTIE_SERVICETASKS,'MaxTaskDuration',FMaxTaskDuration);
finally
FreeAndNil(lIniFile);
end;
end;
finally
if (FLaunchThreadLijst.Count = 0) and FileExists(FStartDir + FExeName) then
FLaunchThreadLijst.Add(SDEFAULTTHREADNAME);
LogMessage(Format('FLaunchThreadLijst.CommaText: %s (%d items)',[FLaunchThreadLijst.CommaText,FLaunchThreadLijst.Count]), EVENTLOG_INFORMATION_TYPE, cCatInfo, cLaunchList);
end;
end;
FWIW, INI file contents:
[TASKMANAGER]
RunIniFiles=TTTasks.ini
MaxTaskDuration=2
RestartIniFiles=
KillIniFiles=

Delphi - printing XML document by InternetExplorer Ole Object

I want to print XML document in Delphi, using OleObject. My code:
var
ie : OleVariant;
begin
ie := CreateOleObject('InternetExplorer.Application');
ie.Navigate('doc.xml');
ShowWindow(frmGlowna.ie.HWND, SW_SHOWMAXIMIZED);
ie.Visible := True;
while ie.QueryStatusWB( OLECMDID_PRINT) <> OLECMDF_SUPPORTED + OLECMDF_ENABLED do
Application.ProcessMessages;
ie.ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_PROMPTUSER,OleVariant(VarAsType($02, varSmallint)), vOut);
ie.Quit;
ie := Unassigned;
end;
Line:
ie.ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_PROMPTUSER,OleVariant(VarAsType($02, varSmallint)), vOut);
Execute printing command and wait for finish.
Everything is OK, as long as the program does not run again or run the same program twice at the same time.
I get different errors:
Catastrophic failure
or
The object invoked has disconnected from its clients
Please help.

Word automation does only work for administrator, or with a delay after creating word.application

We have a program made in Borland Delphi that uses Word automation to create documents.
On an installation (terminal server) we are only able to get the Word automation to work when running as local administrator.
When runnnig as anoter user we get an error message "Opdracht mislukt -2146824090" (its dutch version of Office), wich I guess is translated to "Operation failed" or "Command failed".
The user has read/write access to the folder where the program try to put the new document.
Office 2010
64bits Windows server 2008 R2 standard
The applicaion is 32bit windows application.
If I add a delay (500ms) after the word.application is created, everything works as normall.
WordApp := CreateOleObject('Word.Application');
sleep(500);
Doc := WordApp.documents.Open(sFile,EmptyParam,true);
Anybody knows why the CreateOleObject command now returns before the Word application can be used?
If you want to track out that, you could use a tool like ProcessMonitor to trace the Word automation executions till the point which you can use the app.
Seems some kind of rights check is taking place - but half a second seems too much time just for this.
You could try to open the Document a few times, or is Word totally borked after it gave the error?
WordApp := CreateOleObject('Word.Application');
while True do
begin
try
Doc := WordApp.documents.Open(sFile,EmptyParam,true);
Break;
except
on E: EOleSysError do
begin
// raise error if it's not the expected "Command failed" error
if E.ErrorCode <> -2146824090 then
raise;
end;
end;
end;
Edit:
Please see my answer here which provides a better solution and an explanation why this happens.
The administrator account working wihtout delay, seems not to have anything with rights to do, but that Word happens to start much faster with this account than the normal domain user accounts.
I can live with the delay workaround, but if anyone knows a better way please let me know.
I realize this thread is quite old, but I solved this issue by making sure to close the document before quitting (oleDocument.Close). By doing so there is no need for any type of delays, etc. See Delphi code snippet below.
Example:
oleWord := Unassigned;
oleDocument := Unassigned;
Screen.Cursor := crHourGlass;
try
oleWord := CreateOleObject('Word.Application');
oleWord.Visible := False;
oleWord.DisplayAlerts := False;
oleDocument := oleWord.Documents.Open(Worklist.Filename);
oleDocument.SaveAs(Worklist.Filename, wdFormatDOSTextLineBreaks);
oleDocument.Close;
oleWord.Quit(False);
finally
oleDocument := Unassigned;
oleWord := Unassigned;
Screen.Cursor := crDefault;
end;

Indy 10 FTP empty list

I have been receiving reports from some of my users that, when using idFTP.List() from some servers (MS FTP) then the listing is received as empty (no files) when in reality there are (non-hidden) files on the current directory. May this be a case of a missing parser? The funny think, when I use the program to get the list from MY server (MSFTP on W2003) everything seems OK but on some servers I've been hitting this problem.
Using latest Indy10 on D2010. Any idea?
IdFTPListParseWindowsNT is broken.
The function CheckListing returns false because of a bad parsing:
if sDir = ' <DI' then begin {do not localize}
sDir := Copy(SData, 27, 5);
end else begin
sDir := Copy(SData, 26,28); <---------------BAD PASRSING
Result := TextStartsWith(sDir,' <DI') or IsNumeric(TrimLeft(sDir));
if not Result then begin
Exit;
end;
end;
Commenting this part to make it work like in older versions
if sDir = ' <DI' then begin {do not localize}
sDir := Copy(SData, 27, 5);
end;
{ else begin
sDir := Copy(SData, 26,28); <---------------BAD PASRSING
Result := TextStartsWith(sDir,' <DI') or IsNumeric(TrimLeft(sDir));
if not Result then begin
Exit;
end;
end;}
Showuld solve your problem. Don't know why this change was introduced, though.
This is usually caused by something unexpected in the directory listing which makes the list parser fail. IIS might support both NT-style and Unix-style directory listings, so make sure that you're including both listing parsers in your application and picking between them using IdFTPLaistParse.pas::CheckListing. If that doesn't help it's probably a goofy date or a something in the filename; the best way to debug it is to add code to save the raw directory listing to a file so the end user can send you a copy.
Are you sure you can actually establish the data connection ? The directly listing command is usually the first occasion such a listing is requested and, if you're in the wrong mode, it's usually the point where the failure occurs (i.e. the data channel connection timesout).

Resources