Inno Setup GetExceptionMessage returns empty message - exception

in Inno Setup script GetExceptionMessage returns empty message (it contains only colon ":" sign). The last version of Inno Setup (5.4.2) is used.
try
Log('Create IISNamespace');
// Create IIS namespace object
if Length(virtualDirectoryName) > 0 then
begin
IIS := CreateOleObject('IISNamespace');
Log('Get IIsWebService');
WebSite := IIS.GetObject('IIsWebService', IISServerName + '/w3svc');
Log('Get IIsWebServer');
WebServer := WebSite.GetObject('IIsWebServer', IISServerNumber);
Log('Get IIsWebVirtualDir');
WebRoot := WebServer.GetObject('IIsWebVirtualDir', 'Root');
Log('Delete IIsWebVirtualDir');
WebRoot.Delete('IIsWebVirtualDir', virtualDirectoryName);
WebRoot.SetInfo();
end;
except
MsgBox(ExpandConstant('{cm:IISException,'+ GetExceptionMessage +'}'),
mbInformation, mb_Ok);
Log('Uninstall IIS 6 exception: ' + GetExceptionMessage);
end;
The exception occurs during deleting IIsWebVirtualDir.
Is there any way to get exception type or real exception message?
Thanks, Denis.

I just wrote the following example to see if either GetExceptionMessage or ShowExceptionMessage are broken. I used both Inno setup 5.4.2 Unicode and Ansi versions.
[Setup]
AppName=Test
AppVersion=1.5
DefaultDirName={pf}\test
[Code]
function InitializeSetup(): Boolean;
var
I: Integer;
begin
try
I := I div 0; // Raise an exception
except
MsgBox(GetExceptionMessage,
mbError, MB_OK);
ShowExceptionMessage;
end;
result := false;
end;
I also ran CodeAutomation.iss that ships and it worked as expected. Which is contrary to the comment made by Alex K. that it may be broken.
Now that I know that the routines should work, I took your code and made the following setup test Script and ran it and it raised an exception on not finding the ISSNamespace as I don't have it installed.
[Setup]
AppName=Test
AppVersion=1.5
DefaultDirName={pf}\test
[CustomMessages]
IISException =ISS Exception " %1 " occured.
[Code]
const
IISServerName = 'localhost';
IISServerNumber = '1';
IISURL = 'http://127.0.0.1';
function InitializeSetup(): Boolean;
var
IIS, WebSite, WebServer, WebRoot, VDir: Variant;
virtualDirectoryName : String;
begin
virtualDirectoryName := 'test';
try
Log('Create IISNamespace');
// Create IIS namespace object
if Length(virtualDirectoryName) > 0 then
begin
IIS := CreateOleObject('IISNamespace');
Log('Get IIsWebService');
WebSite := IIS.GetObject('IIsWebService', IISServerName + '/w3svc');
Log('Get IIsWebServer');
WebServer := WebSite.GetObject('IIsWebServer', IISServerNumber);
Log('Get IIsWebVirtualDir');
WebRoot := WebServer.GetObject('IIsWebVirtualDir', 'Root');
Log('Delete IIsWebVirtualDir');
WebRoot.Delete('IIsWebVirtualDir', virtualDirectoryName);
WebRoot.SetInfo();
end;
except
MsgBox(ExpandConstant('{cm:IISException,'+ GetExceptionMessage +'}'),
mbInformation, mb_Ok);
Log('Uninstall IIS 6 exception: ' + GetExceptionMessage);
end;
end;
But I made a fatal flaw during the construction of this script that could be your problem.
Check your [CustomMesssages] section make sure you have %1 in the message. Otherwise nothing is returned.

Related

Detect office 365 (access) AND Visual C 64x using registry

I have a MS Access app which I am planning to sell to people however it uses ODBC (MYSQL) to connect to a backend MySQL DB plus obviously needs ms access (runtime at least).
I created an Inno Setup installer to check for installed components however I have come across some issues:
ODBC 64x fails unless you also have ODBC 32x installed
ODBC (either) cant install unless the respective bit Visual C++ 2015-2019 is installed
My registry path for Visual C+ detects the install but not the Bit version!
Ms Access 365 (2019?) isn't detected using my current registry detection methods.
Code used:
function GetHKLM: Integer;
begin
if IsWin64 then
Result := HKLM64
else
Result := HKLM32;
Result := HKLM;
end;
function IsOfficeInstalled: Boolean;
begin
Result := RegKeyExists(GetHKLM, 'Software\Microsoft\Office');
end;
function NormalAccessPath: String;
var
Names: TArrayOfString;
I: Integer;
S: String;
begin
if not IsOfficeInstalled then
Result:=''
else
begin
if RegGetSubkeyNames(GetHKLM, 'Software\Microsoft\Office', Names) then
begin
for I := 0 to GetArrayLength(Names)-1 do
begin
S := 'Software\Microsoft\Office\' + Names[I]+ '\' + 'Access';
if RegKeyExists(GetHKLM, S) then
Result:=S;
S := '';
end
end
end;
end;
function IsNormalAccessInstalled: Boolean;
var
Path: String;
begin
Path:= NormalAccessPath;
if Path <> '' then
Result := True
else
Result := False
end;
function IsMySQLODBC51Installed: Boolean;
begin
// the result was inverted in the original code; the original function returned
// True if the ODBC driver was not installed, False otherwise, and according to
// the function name it should be vice-versa
Result := RegKeyExists(GetHKLM, 'Software\ODBC\ODBCINST.INI\MySQL ODBC 8.0 Unicode Driver');
end;
function IsRuntimeAccessInstalled: Boolean;
begin
Result := RegKeyExists(GetHKLM, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\AccessRuntimeRetail - en-us');
end;
function IsVCInstalled: Boolean;
begin
Result := RegKeyExists(GetHKLM, 'Software\Microsoft\VisualStudio\14.0\VC');
end;
function AddAsTrusted: Boolean;
var
Path: String;
ResultCode: Integer;
begin
Path:= NormalAccessPath;
MsgBox('Adding Trusted Location', mbInformation, MB_OK);
//Exec('C:\Me\freelance\Inno setup script\fixes.bat', '', '', SW_SHOW, ewWaitUntilTerminated, ResultCode)
if Path <> '' then
begin
//if not RegKeyExists(GetHKLM, Path + '\Security') then
// RegWriteStringValue(GetHKLM, Path + '\Security','MedidropUseless', 'MedidropUseless')
if not RegKeyExists(GetHKLM, Path + '\Security\Trusted Locations') then
RegWriteStringValue(GetHKLM, Path + '\Security\Trusted Locations\Location1','Path', 'C:\MediDrop')
end;
Result := True;
end;
So for 2 & 3:
I need to detect visualC's VERSION.
I tested the installer at a new location today and they already had visual C++ 2015 86x so my installed failed for ODBC 64x because visualC 64x was missing. Obviously:
'Software\Microsoft\VisualStudio\14.0\VC'
is not appropriate..
For 4:
As can be seen I am checking Software\Microsoft\Office however this computer did have the 15.0 and 16.0 subfolders (terminology?) but did NOT have ACCESS in them so my installer thought it was not installed.
However.. it was, so I need to find a way of finding this 365 version of access!
Finally, at the end of the install I add a path for trusted location:
function AddAsTrusted: Boolean;
var
Path: String;
ResultCode: Integer;
begin
Path:= NormalAccessPath;
MsgBox('Adding Trusted Location', mbInformation, MB_OK);
//Exec('C:\Me\freelance\Inno setup script\fixes.bat', '', '', SW_SHOW, ewWaitUntilTerminated, ResultCode)
if Path <> '' then
begin
if not RegKeyExists(GetHKLM, Path + '\Security\Trusted Locations') then
RegWriteStringValue(GetHKLM, Path + '\Security\Trusted Locations\Location1','Path', 'C:\[MyAppName]')
end;
Result := True;
end;
Once again due to the 365 issue... this did not work. I created the path correctly in 16.0 but since access wasnt there, I still needed to Enable Content when I opened the app the first time, something I don't want to do.
Does anyone know where I can start to figure the above issues out??

Initialize TSQLConnection Driver non-GUI App

I'm trying to create TSQLConnection at run-time on non-GUI application.
Uses Data.DB, Data.SqlExpr, Data.DBXMSSQL;
...
procedure TFoo.InitializeDB;
begin
if NOT Assigned(SQLCon) then exit;
SQLCon.Params.Clear;
SQLCon.ConnectionName := 'ReportsCon';
SQLCon.DriverName := 'MSSQL';
SQLCon.LoadParamsFromIniFile('C:\ConfigTest\DBTest.ini');
try
SQLCon.Connected := True;
except
on E: Exception Do
LastErr := E.Message;
end;
end;
I got this error
DBX Error: Driver could not be properly initialized. Client library may be missing, not installed properly, of the wrong version, or the driver may be missing from the system path.
For test purpose i created a new GUI project i dropped TButton on the form with the below OnClick event
Uses Data.DB, Data.SqlExpr, Data.DBXMSSQL;
...
procedure TForm12.btn1Click(Sender: TObject);
var
SQLConnection: TSQLConnection;
begin
SQLConnection := TSQLConnection.Create(nil);
try
SQLConnection.ConnectionName := 'ReportsCon';
SQLConnection.DriverName := 'MSSQL';
SQLConnection.LoadParamsFromIniFile('C:\ConfigTest\DBTest.ini');
try
SQLConnection.Connected := True;
except
on E: Exception Do
ShowMessage(E.Message);
end;
finally
SQLConnection.Free;
end;
end;
The code run as expected with no error.
Both EXE and dbxmss.dll are on the same folder
C:\Users\$Name\Documents\Embarcadero\Studio\Projects\Win32\Debug
What am I missing here ?

Delphi 2010 : UniDAC vs Indy-MultiThread safety handleing method

I am doing develop Indy based application.
Server has several Indy TCP Server components.
So It works under multi-threads and handles mysql db.
I have faced one problem.
That is about the exceptions of MySQL DB in threads.
When serveral threads attack to same db table, then It says me like follows
UniQuery_Mgr: Duplicate field name 'id'
UniQuery_Mgr: Field 'grp_id' not found //of course grp_id field is really existed.
Assertion failure (C:\Program Files (x86)\unidac539src\Source\CRVio.pas, line 255)
Commands out of sync; You can't run this command now
ReceiveHeader: Net packets out of order: received[0], expected[1]
UniQuery_Mgr: Cannot perform this operation on a closed dataset
How to do I ? UniQuery_Mgr is TUniQuery component.
and my query handling code is normally like this
Code 1
sql := 'SELECT * FROM data_writed;';//for example
UniQuery_Mgr.SQL.Clear;
UniQuery_Mgr.SQL.Add(sql);
UniQuery_Mgr.ExecSQL;
Code 2
try
sql := 'SELECT * FROM gamegrp_mgr;';
UniQuery_Mgr.SQL.Clear;
UniQuery_Mgr.SQL.Add(sql);
UniQuery_Mgr.ExecSQL;
if UniQuery_Mgr.RecordCount > 0 then
begin
MAX_GAME_GROUP_COUNT := UniQuery_Mgr.RecordCount + 1;
UniQuery_Mgr.First;
i := 1;
while not UniQuery_Mgr.Eof do
begin
Game_Group_ID[i] := UniQuery_Mgr.FieldByName('grp_id').AsInteger;
Game_Game_ID[i] := UniQuery_Mgr.FieldByName('game_id').AsInteger;
UniQuery_Mgr.Next;
Inc(i);
end;
end;
except
on E : Exception do
begin
EGAMEMSG := Format('GAME group read error: <%s> # %s',[ E.ToString, DateTimeToStr(now)]);
Exit;
end;
end;
Code 3
try
sql := 'UPDATE data_writed SET write_gamegrp = ' + QuotedStr('0') + ';';
UniQuery_Mgr.SQL.Clear;
UniQuery_Mgr.SQL.Add(sql);
UniQuery_Mgr.ExecSQL;
except
on E : Exception do
begin
EGAMEMSG := Format('data updating error: <%s> # %s',[ E.ToString, DateTimeToStr(now)]);
Exit;
end;
end;
My handling DB components is bad ? Other thread-safe method is existed???

Getting MySQL process output

I want to play with MySQL process and get what ever it write to console so I write this code in FreePascal:
I want to control MySQl and read & write whatever.
Process := TProcess.Create(nil);
with Process do
begin
Executable := 'C:\Program Files (x86)\MySQL\MySQL Server 5.5\bin\mysql.exe';
with Parameters do
begin
Options := [poUsePipes];
Add('-u');
Add('root');
Add('-p');
end;
Execute;
sleep(1000);
WriteLn(Process.Output.NumBytesAvailable); // will be 0 but it write "Enter password"
WriteLn(Process.Stderr.NumBytesAvailable); // will be 0 but it write "Enter password"
end;
TProcess is a component that control executing other programs,I even test Delphi codes but all result are the same.
But the problem is that this will freeze because there is no output but console window write :
Enter password:
How can I get this in my application and all others?
As I said I want to work with MySQL executable and read from and write in it, So I dont want to use its library or any other DB component.
EDIT:
Here is a Delphi version of my test from here with the same result :
function GetDosOutput(CommandLine: string; Work: string = 'C:\'): string;
var
SA: TSecurityAttributes;
SI: TStartupInfo;
PI: TProcessInformation;
StdOutPipeRead, StdOutPipeWrite: THandle;
WasOK: Boolean;
Buffer: array[0..255] of AnsiChar;
BytesRead: Cardinal;
WorkDir: string;
Handle: Boolean;
begin
Result := '';
with SA do begin
nLength := SizeOf(SA);
bInheritHandle := True;
lpSecurityDescriptor := nil;
end;
CreatePipe(StdOutPipeRead, StdOutPipeWrite, #SA, 0);
try
with SI do
begin
FillChar(SI, SizeOf(SI), 0);
cb := SizeOf(SI);
dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
wShowWindow := SW_HIDE;
hStdInput := GetStdHandle(STD_INPUT_HANDLE); // don't redirect stdin
hStdOutput := StdOutPipeWrite;
hStdError := StdOutPipeWrite;
end;
WorkDir := Work;
Handle := CreateProcess(nil, PChar('cmd.exe /C ' + CommandLine),
nil, nil, True, 0, nil,
PChar(WorkDir), SI, PI);
CloseHandle(StdOutPipeWrite);
if Handle then
try
repeat
WasOK := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil);
if BytesRead > 0 then
begin
Buffer[BytesRead] := #0;
Result := Result + Buffer;
end;
until not WasOK or (BytesRead = 0);
WaitForSingleObject(PI.hProcess, INFINITE);
finally
CloseHandle(PI.hThread);
CloseHandle(PI.hProcess);
end;
finally
CloseHandle(StdOutPipeRead);
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
memo1.text:=GetDosOutput('"C:\Program Files (x86)\MySQL\MySQL Server 5.5\bin\mysql.exe" -u root -p');
end;
It will freeze in WasOK line .
Also I tested many other codes for this subject and neither worked.

Application closing when Activating the Connection on FireDAC

I developed an application that uses FireDAC to connect to a MySQL Database.
But when I try to open it on a workstation, at the moment that I set the Connected := True; on the TFDConnection, the application closes itself without showing an exception. It is surrounded with a try...except, but still doesn't show no error message at all. Here's the code I'm using to set the connection:
procedure TfrmServidor.confConnection;
begin
with conMySQL do begin
DriverName := LeXML.Strings[5];
Params.Add('Server=' + LeXML.Strings[3]);
Params.Add('Port=' + LeXML.Strings[4]);
Params.Add('Database=' + LeXML.Strings[0]);
Params.Add('User_Name=' + LeXML.Strings[1]);
Params.Add('Password=' + LeXML.Strings[2]);
ShowMessage(Params.Text);
end;
try
conMySQL.Connected := True;
except
on e : Exception do
ShowMessage(e.Message);
end;
end;
Where LeXML is a function that reads a XML file with the properties and returns the values on a TStringList.
What is it that i'm doing wrong?
The ShowMessage with the Params Text returns the following:
[Window Title]
Servidor
[Content]
DriverID=MySQL
Server=10.1.1.16
Port=3306
Database=treinamentos
User_Name=treinamentos
Password=masterkey
[OK]
Can anyone help?