How to restart Inno Setup installer based on result of procedure that executes a program/subinstaller - checkbox

I have an install procedure that is executed if the sub exe is not installed, and if so, I want the final "lauch my app" checkbox at the end to be replaced by a "restart computer" checkbox.
How can I do that?
I tried to use the NeedRestart() and also use a global boolean variable. But I can't seem to make it work.
Minimal reproductible example:
the file line :
[Files]
Source: "Dependencies\ndp48-x86-x64-allos-enu.exe"; \
DestDir: "{app}"; Flags: deleteafterinstall; \
AfterInstall: InstallNETFramework; Check: NETFrameworkIsNotInstalled
The installation procedure:
procedure InstallNETFramework;
var
ResultCode: Integer;
StatusText: string;
begin
StatusText := WizardForm.StatusLabel.Caption;
WizardForm.StatusLabel.Caption := 'Installing .NET Framework 4.8...';
WizardForm.ProgressGauge.Style := npbstMarquee;
try
if not ShellExec('open', ExpandConstant('{app}\ndp48-x86-x64-allos-enu.exe'), '/norestart', '', SW_SHOW, ewWaitUntilTerminated, ResultCode)
then
begin
MsgBox('.NET Framework 4.8 Installation did not succeed : ' + IntToStr(ResultCode) + '.', mbError, MB_OK);
end;
finally
WizardForm.StatusLabel.Caption := StatusText;
WizardForm.ProgressGauge.Style := npbstNormal;
end;
end;
The NeedToRestart event function:
[Code]
var NeedToRestart: boolean;
function NeedToRestart();
begin
//??
end;
If this installation procedure is executed, then at the end, instead of having a "launch {{app}}" I want "restart computer". If possible with the option now or later? It's fine if not.

As you correctly assumed:
introduce a global Boolean variable
set it when the .NET installer is successfully executed (you should check ResultCode to be really sure that it did)
and use the variable in the NeedRestart event function:
var
RestartNeeded: Boolean;
function NeedRestart(): Boolean;
begin
Result := RestartNeeded;
end;
procedure InstallNETFramework;
var
ResultCode: Integer;
begin
// ...
if Exec(ExpandConstant('{app}\ndp48-x86-x64-allos-enu.exe'),
'/norestart', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) and
(ResultCode = { whatever success exit code[s] the installer uses }) then
begin
Log('.NET Framework 4.8 installation succeeded, need restart');
RestartNeeded := True;
// Or if the installer has specific code to indicate success with restart:
// RestartNeeded := (ResultCode = RestartCode);
end
else
begin
MsgBox('.NET Framework 4.8 installation did not succeed: ' +
IntToStr(ResultCode) + '.', mbError, MB_OK);
end;
// ...
end;
.NET installer return codes seem to be documented here (but I didn't test it):
https://learn.microsoft.com/en-us/dotnet/framework/deployment/deployment-guide-for-developers#return-codes
Similar question: Inno Setup and VC Redistributable and handling exit code 3010 gracefully
As hinted by #PMF in your other question, as alternative approach might be to try the RestartIfNeededByRun directive along with running your subinstaller using [Run]. Though that limits error handling.
If you want to keep executing (and checking) the .NET installation in code, you can use MakePendingFileRenameOperationsChecksum function:
var
ResultCode: Integer;
Checksum: string;
// ...
Checksum := MakePendingFileRenameOperationsChecksum;
if Exec(ExpandConstant('{app}\ndp48-x86-x64-allos-enu.exe'),
'/norestart', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) and
(ResultCode = { whatever success exit code[s] the installer uses }) then
begin
Log('.NET Framework 4.8 installation succeeded, need restart');
if Checksum <> MakePendingFileRenameOperationsChecksum then
begin
Log('Need to restart detected');
RestartNeeded := True;
end;
end
// ...

Related

Drag & Drop Component Suite: Drop files and if path isn't exists get data from file

I use the Drag and Drop Component Suite for Delphi.
I try to create a drag & drop area which accepts files (ie, from Windows Explorer) and data (ie, from Outlook attachments). So, I use the demo (CombatTargetDemo) to learn how it works, and after this I create a wrapper class which creates a TDropComboTarget object:
constructor TDragAndDrop.Create( vpntOwner: TWinControl);
begin
fpntDragAndDrop := TDropComboTarget.Create(vpntOwner);
fpntDragAndDrop.Name := 'DropComboTarget_'+vpntOwner.Name;
fpntDragAndDrop.DragTypes := [dtCopy, dtLink];
fpntDragAndDrop.OnDrop := DropFiles;
fpntDragAndDrop.Target := vpntOwner;
fpntDragAndDrop.Formats := [mfFile, mfData];
end;
procedure TDragAndDrop.DropFiles(Sender: TObject; ShiftState: TShiftState; Point: TPoint; var Effect: Integer);
var
intCnt: Integer;
pntStream: TStream;
strFileName: String;
strDragAndDropFile: String;
begin
try
fstlDroppedFilePaths.Clear;
fstlDroppedFilePaths.Assign(fpntDragAndDrop.Files);
for intCnt := 0 to fpntDragAndDrop.Data.Count-1 do begin
strFileName := fpntDragAndDrop.Data.Names[intCnt];
if (strFileName = '') then begin
strFileName := IntToStr(intCnt)+'_'+FormatDateTime('yyyymmddhhnnss', Now())+'.dat';
end;
strDragAndDropFile := GetDragAndDropSavePath+strFileName;
pntStream := TFileStream.Create(strDragAndDropFile, fmCreate);
try
pntStream.CopyFrom(fpntDragAndDrop.Data[intCnt], fpntDragAndDrop.Data[intCnt].Size);
finally
pntStream.Free;
end;
if FileExists(strDragAndDropFile, false) then begin
fstlDroppedFilePaths.Add(strDragAndDropFile);
end;
end;
except
end;
end;
First of all, the code works.
If I drop a Windows Explorer file on the area:
fpntDragAndDrop.Files.Count is 1 (contains the path+name from file)
fpntDragAndDrop.Data.Count is 1 (contains the file as a stream)
If I drop a file from Outlook on the area:
fpntDragAndDrop.Files.Count is 0 (contains nothing)
fpntDragAndDrop.Data.Count is 1 (contains the file as a stream)
Now my problem:
If I drop very large files from Windows Explorer, the component does the following:
Read the file header and add an item to fpntDragAndDrop.Files
Create a TMemoryStream and try to load the data from the file into the stream
Step 1 is perfect, but on step 2 I get an exception because of insufficient memory.
My solution:
I want that the component does Step 1. If Step 1 gives a result, then the component should skip Step 2. After this, the variables in the DropFiles procedure should have the following values:
If I drop a Windows Explorer file on the area:
fpntDragAndDrop.Files.Count is 1 (contaims the path+name from the file)
fpntDragAndDrop.Data.Count is 0 (No memory stream is loaded)
If I drop a file from Outlook on the area:
fpntDragAndDrop.Files.Count is 0 (comtains nothing)
fpntDragAndDrop.Data.Count is 1 (contains the file as a stream)
Does somebody have an idea? Or maybe the component has a setting for that?
I'm not overly familiar with this suite, but just browsing through its source, I think you can use the OnAcceptFormat event to reject formats you don't want on a per-drop basis.
So, even though you have enabled drops of mfData doesn't mean you have to actually accept a dropped stream (TDataStreamDataFormat) if a file path (TFileDataFormat or TFileMapDataFormat) is available. So, query the fpntDragAndDrop.DataObject to see what formats it actually holds, such as by passing it to the HasValidFormats() method of the various formats in the fpntDragAndDrop.DataFormats property.
For example:
fpntDragAndDrop.OnAcceptFormat := AcceptStreams;
...
procedure TDragAndDrop.AcceptStreams(Sender: TObject;
const DataFormat: TCustomDataFormat; var Accept: boolean);
var
Fmt: TCustomDataFormat;
i: Integer;
begin
if DataFormat is TDataStreamDataFormat then
begin
// FYI, TFileDataFormat should be in DataFormats[0],
// and TFileMapDataFormat should be in DataFormats[5],
// if you want to avoid this loop...
for i := 0 to fpntDragAndDrop.DataFormats.Count-1 do
begin
Fmt := fpntDragAndDrop.DataFormats[i];
if (Fmt <> DataFormat) and ((Fmt is TFileDataFormat) or (Fmt is TFileMapDataFormat)) then
begin
if Fmt.HasValidFormats(fpntDragAndDrop.DataObject) then
begin
Accept := False;
Exit;
end;
end;
end;
end;
Accept := True; // should already be True by default...
end;

How can I check if the program was installed correctly using Exec() function in Inno Setup? [duplicate]

Using innosetup and want to show error/msgbox if one of the [RUN] process does not return process code 0. I'm using it for authorization process, if authorization is not successful, i want to notify the user.
I have following:
Filename: "{pf32}\Common Files\Authorization.exe"; Parameters: " "{code:GetAuthorizationFilePath}" /s"; WorkingDir: "{tmp}"; Flags: skipifdoesntexist hidewizard; StatusMsg: "Authorizing License";
Returns me:
Process exit code:0
0 of course is successful, but if its not 0 i want to notify the user.
Is there a way to do that?
Thanks and Regards,
Kev84
I think there's no way to accomplish this from the [Run] section. What you can do is:
use the Pascal Script for this task
or display the modal error message from your executed application Authorization.exe and terminate it only after the user confirms the error message (setup will then continue e.g. with the execution of the other files in the [Run] section)
Here is the code sample of the Pascal Script; you can check also the commented version of this code:
[Code]
function NextButtonClick(CurPageID: Integer): Boolean;
var
ResultCode: Integer;
begin
Result := True;
if CurPageID = wpWelcome then
begin
Result := False;
if Exec(ExpandConstant('{pf32}\Common Files\Authorization.exe'), '', '',
SW_SHOW, ewWaitUntilTerminated, ResultCode) then
begin
if ResultCode = 0 then
Result := True
else
MsgBox('The authorization failed!', mbCriticalError, MB_OK);
end;
end;
end;
I had the same requirements: to run an external program and display an error message if the return code is not 0. It was very important for me to run the program in the Run section as I needed to display a status message and the progress bar is nice to have.
I found that you can use AfterInstall in the Run section to trigger the execution of your program and check the result code (see this link for more info about AfterInstall.)
So, my idea was to run a dummy program like change and to use the procedure specified in AfterInstall to run the real program and catch its result code.
[Code]
procedure ExecuteRealProgram();
var
ResultCode: Integer;
begin
if Exec(ExpandConstant('{pf32}\Common Files\Authorization.exe'), '', '', SW_SHOW,
ewWaitUntilTerminated, ResultCode)
then begin
if not (ResultCode = 0) then
MsgBox('Error! ResultCode is ' + IntToStr(ResultCode), mbCriticalError, MB_OK);
end
else
MsgBox('Exec failed! Error: ' + SysErrorMessage(ResultCode), mbCriticalError, MB_OK);
end;
end;
[Run]
Filename: "change.exe"; WorkingDir: "{tmp}"; \
StatusMsg: "Running external program. Please wait."; AfterInstall: ExecuteRealProgram

Windows Services in Delphi with database connection

I would just like a tip about a situation.
I created a Windows service that does the task management of my application.
The service connect to the database (Firebird) and call a component that does the task management.
The process works fine, however, in Windows 10 the service does not start automatically after the computer is restarted. In other versions of Windows everything works perfectly. In testing, I have identified that if I comment on the method that calls the execution of the tasks, the service usually starts on Windows 10.
Procedure TDmTaskService.ServiceExecute(Sender: TService);
Begin
Inherited;
While Not Terminated Do
Begin
//Process;
Sleep(3000);
ServiceThread.ProcessRequests(False);
End;
End;
The problem is that nothing exception is generated in component or service.
By analyzing the Windows Event Monitor, I have identified that the error that occurred with my service is Timeout, in which case the service was unable to connect to the service manager within the time limit. No more exceptions are generated.
Would anyone have any about Windows Services made in Delphi that connect to database?
Example of my source code:
**Base class:**
unit UnTaskServiceDmBase;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs;
type
TDmTaskServicosBase = class(TService)
private
{ Private declarations }
public
function GetServiceController: TServiceController; override;
{ Public declarations }
end;
var
DmTaskServiceBase: TDmTaskServicosBase;
implementation
{$R *.DFM}
procedure ServiceController(CtrlCode: DWord); stdcall;
begin
DmJBServicosBase.Controller(CtrlCode);
end;
function TDmTaskServicosBase.GetServiceController: TServiceController;
begin
Result := ServiceController;
end;
end.
**Service Class:**
Unit UnTaskServiceDm;
Interface
Uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs,
UnJBTask,
UnJBReturnTypes,
UnJBUtilsFilesLog,
UnTaskServiceDmConfig,
UnTaskServiceDmConnection,
ExtCtrls,
IniFiles;
Type
TDmTaskService = Class(TDmTaskServicosBase)
Procedure ServiceExecute(Sender: TService);
Procedure ServiceCreate(Sender: TObject);
Procedure ServiceStop(Sender: TService; Var Stopped: Boolean);
Private
FTaskServiceConfig: TDmTaskServiceConfig;
FStatus: TResultStatus;
FDmConnection: TDmTaskServiceConnection;
FJBTask: TJBTask;
FLog: TJBUtilsFilesLog;
Procedure ExecuteTasksSchedule;
Procedure UpdateServiceInformation;
Procedure Process;
Procedure UpdateConnection;
Public
Function GetServiceController: TServiceController; Override;
End;
Implementation
{$R *.DFM}
Procedure ServiceController(CtrlCode: DWord); Stdcall;
Begin
DmTaskService.Controller(CtrlCode);
End;
Procedure TDmTaskService.UpdateConnection;
Begin
Try
FDmConnection.SqcCon.Connected := False;
FDmConnection.SqcCon.Connected := True;
FLog.Adicionar('Conexão com banco restabelecida.');
FLog.FinalizarLog;
Except
On E: Exception Do
Begin
FLog.Adicionar('Erro ao restabelecer conexão com o banco de dados.' +
sLineBreak + sLineBreak + E.Message);
FLog.FinalizarLog;
End;
End;
End;
Procedure TDmTaskService.UpdateServiceInformation;
Begin
Inherited;
Try
Try
FTaskServiceConfig.Load;
FLog.Adicionar('Dados registro serviço.');
FLog.Adicionar('Nome: ' + FTaskServiceConfig.ServiceName);
FLog.Adicionar('Descrição: ' + FTaskServiceConfig.ServiceDescription);
If (FTaskServiceConfig.ServiceName <> EmptyStr) And
(FTaskServiceConfig.ServiceDescription <> EmptyStr) Then
Begin
Name := FTaskServiceConfig.ServiceName ;
DisplayName := FTaskServiceConfig.ServiceDescription;
End;
FTaskServiceConfig.Close;
Except
On E: Exception Do
Begin
FLog.Adicionar('Erro adicionar dados registro serviço.');
FLog.Adicionar('Erro ocorrido: ' + sLineBreak + sLineBreak + E.Message);
End;
End;
Finally
FLog.Adicionar('Name: ' + Name);
FLog.Adicionar('DisplayName: ' + DisplayName);
FLog.FinalizarLog;
End;
End;
Procedure TDmTaskService.Process;
Begin
Try
If FDmConnection.SqcCon.Connected Then
Begin
ExecuteTasksSchedule;
End
Else
UpdateConnection;
Except
On E: Exception Do
Begin
FLog.Adicionar('Ocorreu um erro ao checar as tarefas.' + sLineBreak +
'Erro ocorrido: ' + sLineBreak + E.Message);
FLog.FinalizarLog;
UpdateConnection;
End;
End;
End;
Procedure TDmTaskService.ExecutarTarefasAgendadas;
Begin
If FJBTask.ExistTaskDelayed Then
Begin
Try
FJBTask.ExecuteTasks;
Except
On E: Exception Do
Begin
FLog.Adicionar('Ocorreu um erro ao executar as tarefas agendadas.' +
sLineBreak + 'Erro ocorrido: ' + sLineBreak + E.Message);
FLog.FinalizarLog;
UpdateConnection;
End;
End;
End;
End;
Function TDmTaskService.GetServiceController: TServiceController;
Begin
Result := ServiceController;
End;
Procedure TDmTaskService.ServiceCreate(Sender: TObject);
Begin
Inherited;
Try
FLog := TJBUtilsFilesLog.Create;
FLog.ArquivoLog := IncludeTrailingPathDelimiter(FLog.LogFolder) + 'TaksService.log';
FDmConnection := TDmTaskServiceConexao.Create(Self);
FDmConnection.Log := FLog;
FJBTask := TJBTarefa.Create(Self);
FJBTask.SQLConnection := FDmConnection.SqcConexao;
FTaskServiceConfig := TDmTaskServiceConfig.Create(Self);
FTaskServiceConfig.SQLConnection := FDmConnection.SqcConexao;
FStatus := FDmConnection.ConfigurouConexao;
If FStatus.ResultValue Then
Begin
UpdateServiceInformation;
End
Else
Begin
FLog.Adicionar(FStatus.MessageOut);
FLog.FinalizarLog;
End;
Except
On E: Exception Do
Begin
FLog.Adicionar('Não foi possível iniciar o serviço.' + sLineBreak +
'Erro ocorrido: ' + sLineBreak + sLineBreak + E.Message);
FLog.FinalizarLog;
Abort;
End;
End;
End;
Procedure TDmTaskService.ServiceExecute(Sender: TService);
Begin
Inherited;
While Not Terminated Do
Begin
Process;
Sleep(3000);
ServiceThread.ProcessRequests(False);
End;
End;
Procedure TDmTaskService.ServiceStop(Sender: TService; Var Stopped: Boolean);
Begin
Inherited;
If Assigned(FDmConnection) Then
Begin
FLog.Adicionar('Finalizando serviço.');
FLog.Adicionar('Fechando conexão.');
Try
FDmConnection.SqcConexao.Close;
Finally
FLog.FinalizarLog;
End;
End;
End;
End.
By analyzing the Windows Event Monitor, I have identified that the error that occurred with my service is Timeout, in which case the service was unable to connect to the service manager within the time limit. No more exceptions are generated.
Do not connect to your database, or do any other lengthy operations, in the TService.OnCreate event. Such logic belongs in the TService.OnStart event instead. Or better, create a worker thread for it, and then start that thread in the TService.OnStart event and terminate it in the TService.On(Stop|Shutdown) events.
When the SCM starts your service process, it waits for only a short period of time for the new process to call StartServiceCtrlDispatcher(), which connects the process to the SCM so it can start receiving service requests. StartServiceCtrlDispatcher() is called by TServiceApplication.Run() after all TService objects have been fully constructed first. Since the OnCreate event is called while your process is trying to initialize itself, before StartServiceCtrlDispatcher() is called, any delay in service construction can cause the SCM to timeout and kill the process.
Also, you should get rid of your TService.OnExecute event handler completely. You shouldn't even be using that event at all, and what you currently have in it is no better than what TService already does internally when OnExecute is not assigned any handler.
In your service code :
- you can try to add Dependencies on your Firebird Service
- you can increase WaitHint
if it still not work : you can start as automatic but "Delayed"
I found it otherwise to solve, however, I thank everyone for the tips, because in a timely manner you will make improvements to my service.
The solution was to extend the service startup timeout through the Windows ServicesPipeTimeout registry key.
For my case it worked perfectly.
I increased the value of ServicesPipeTimeout to 120000 (2 minutes).
By default the value is 30000 (30 seconds) or less.
To manual Edit:
1) Open the Windows Regedit App;
2) Locate and then click the following registry subkey:
  - HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Control
In the panel values, locate the ServicesPipeTimeout entry.
** Note **:
If the ServicesPipeTimeout entry does not exist, you must create it. To do
this, follow these steps:
 - On the Edit menu, point to New, and then click DWORD Value.
 - Type ServicesPipeTimeout, and then press ENTER.
3) Right-click ServicesPipeTimeout, and then click Modify.
4) Click Decimal, type 120000, and then click OK.
** 120000 miliseconds = 2 minutes
5) Restart the computer.
In Delphi (Sample registry value):
Procedure TForm3.JBButton3Click(Sender: TObject);
Const
CKeyConfigTimeout = 'SYSTEM\CurrentControlSet\Control';
CValueConfigTimeout = 'ServicesPipeTimeout';
Var
LReg: TRegistry;
Begin
LReg := TRegistry.Create;
Try
LReg.RootKey := HKEY_LOCAL_MACHINE;
LReg.OpenKey(CKeyConfigTimeout, False);
LReg.WriteInteger(CValueConfigTimeout, 120000);
Finally
LReg.CloseKey;
FreeAndNil(LReg);
End;
End;
Note: The delphi application with the registry update code needs to run in administrator mode for Windows Vista / Server or Superior versions;

Delphi: What's wrong with REST API based on mORMot?

I try to build REST Web Server based on mORMot framework (Delphi) and have issue with getting data from remote DB.
Server.dpr
const
CONN_STR =
'DRIVER=SQL Server Native Client 10.0;UID=user;PWD=pass;server=server;'
+ 'Trusted_Connection=No;MARS_Connection=yes';
var
Model: TSQLModel;
RESTServer: TSQLRestServerDB;
Application: TwoStreamgateApplication;
HTTPServer: TSQLHttpServer;
ODBCConnProp: TSQLDBConnectionPropertiesThreadSafe;
begin
SQLite3Log.Family.Level := LOG_VERBOSE;
SQLite3Log.Family.PerThreadLog := ptIdentifiedInOnFile;
ODBCConnProp := TODBCConnectionProperties.Create('', CONN_STR, 'wo', 'wo');
try
ODBCConnProp.ThreadingMode := tmMainConnection;
Model := CreateModel;
VirtualTableExternalRegisterAll(Model, ODBCConnProp);
try
RESTServer := TSQLRestServerDB.Create(Model, ':memory:');
try
RESTServer.DB.Synchronous := smNormal;
RESTServer.DB.LockingMode := lmExclusive;
RESTServer.CreateMissingTables;
Application := TwoStreamgateApplication.Create;
try
Application.Start(RESTServer);
HTTPServer := TSQLHttpServer.Create('8092', [RESTServer]
{$IFNDEF ONLYUSEHTTPSOCKET}, '+', useHttpApiRegisteringURI{$ENDIF});
try
HTTPServer.RootRedirectToURI('api/default');
RESTServer.RootRedirectGet := 'api/default';
writeln('"MVC WOStreamgate Server" launched on port 8092 using ',
HTTPServer.HttpServer.ClassName);
writeln(#10'You can check http://localhost:8092/api/info for information');
writeln('or point to http://localhost:8092 to access the web app.');
writeln(#10'Press [Enter] to close the server.'#10);
readln;
writeln('HTTP server shutdown...');
finally
HTTPServer.Free;
end;
finally
Application.Free;
end;
finally
RESTServer.Free;
end;
finally
Model.Free;
end;
finally
ODBCConnProp.Free;
end;
Model is described below in ServerModel.pas unit
type
TSQLBaseData = class(TSQLRecord)
private
FName: RawUTF8;
FDetailURL: RawUTF8;
FLogoURL: RawUTF8;
FDescription: RawUTF8;
published
property Name: RawUTF8 read FName write FName;
property Description: RawUTF8 read FDescription write FDescription;
property LogoURL: RawUTF8 read FLogoURL write FLogoURL;
property DetailURL: RawUTF8 read FDetailURL write FDetailURL;
end;
TSQLStation = class(TSQLBaseData)
end;
function CreateModel: TSQLModel;
implementation
function CreateModel: TSQLModel;
begin
result := TSQLModel.Create(
[TSQLStation],
'api');
end;
View model in ServerViewModel.pas unit
TServerApplication = class(TMVCApplication, IServerApplication)
public
procedure Start(aServer: TSQLRestServer); reintroduce;
procedure StationView(ID: TID; out Station: TSQLStation);
end;
implementation
procedure TServerApplication.Start(aServer: TSQLRestServer);
begin
inherited Start(aServer,TypeInfo(IServerApplication));
fMainRunner := TMVCRunOnRestServer.Create(Self).
SetCache('Default',cacheRootIfNoSession,15);
aServer.Cache.SetCache(TSQLStation);
end;
procedure TServerApplication.StationView(ID: TID; out Station: TSQLStation);
begin
RestModel.Retrieve(ID, Station);
end;
and now once I type http://localhost:8092/api/station/10 in browser, I get response
{ "errorCode":404, "errorText":"Not Found" }
in case I type http://localhost:8092/api/stationview/10 in browser I get rendered page, but without info about station=10 or any other.
Where did I make a mistake? I want simply get JSON-response to my request
UPDATE:
Another info that can help. Once I try the query
procedure TestQuery();
var
SQLDBConnection: TODBCConnection;
Q: TQuery;
begin
SQLDBConnection := TODBCConnection.Create(ODBCConnProp);
Q := TQuery.Create(SQLDBConnection);
try
Q.SQL.Clear; // optional
Q.SQL.Add('select * from dbo.Station');
Q.Open;
...
I catch an error:
Project Server.exe raised exception class EODBCException with message 'TODBCStatement - TODBCLib
error: [HY106] [Microsoft][SQL Server Native Client 10.0]Fetch type
out of range (0) '.
Solution is very simple - need to add:
Database=myDataBase;
to
CONN_STR = 'DRIVER=SQL Server Native Client 10.0;UID=user;PWD=pass;server=server;'
+ 'Trusted_Connection=No;MARS_Connection=yes';Database=myDataBase;
Thanks Arnaud for great framework!!!

Delphi ODBC Connection Dialog Component?

I am thinking about adding ODBC database connectivity to an application.
The user will at runtime configure and select their database odbc connection.
Are there any components that will give me the required series of dialogs ?
Allowing the user to select the data source type, select drivers, browse already
defined ODBC connections etc.
Cheers
Sam
You can try this, if you are using ADO components.
Option 1
Uses
OleDB,
ComObj,
ActiveX;
function Edit_ADO_ODBC_ConnectionString(ParentHandle: THandle; InitialString: WideString;out NewString: string): Boolean;
var
DataInit : IDataInitialize;
DBPrompt : IDBPromptInitialize;
DataSource: IUnknown;
InitStr : PWideChar;
begin
Result := False;
DataInit := CreateComObject(CLSID_DataLinks) as IDataInitialize;
if InitialString <> '' then
DataInit.GetDataSource(nil, CLSCTX_INPROC_SERVER, PWideChar(InitialString),IUnknown, DataSource);
DBPrompt := CreateComObject(CLSID_DataLinks) as IDBPromptInitialize;
{
DBPROMPTOPTIONS_WIZARDSHEET = $1;
DBPROMPTOPTIONS_PROPERTYSHEET = $2;
DBPROMPTOPTIONS_BROWSEONLY = $8;
DBPROMPTOPTIONS_DISABLE_PROVIDER_SELECTION = $10;
}
if Succeeded(DBPrompt.PromptDataSource(nil, ParentHandle,DBPROMPTOPTIONS_PROPERTYSHEET, 0, nil, nil, IUnknown, DataSource)) then
begin
InitStr := nil;
DataInit.GetInitializationString(DataSource, True, InitStr);
NewString := InitStr;
Result := True;
end;
end;
Result:=Edit_ADO_ODBC_ConnectionString(0,OldConnectionString,NewString);
Option 2
Uses
ADODB;
PromptDataSource(Self.Handle, InitialString);
Option 3
Uses
ADODB,
AdoConEd;
procedure TMainForm.Button2Click(Sender: TObject);
Var
ADOConnection1 : TADOConnection;
begin
ADOConnection1:=TADOConnection.Create(Self);
EditConnectionString(ADOConnection1);
end;
You must Select "Microsoft OLE DB Provider for ODBC Drivers"
Bye.
PromptDataSource Function from the ADODB unit. Two parameters are
required:
the calling form's handle
a connection string . If you want no default connection string
just pass an empty string as:
var sConn : WideString;
begin
sConn := PromptDataSource(Form1.Handle, '');
end;

Resources