home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 1999 February / DPPCPRO0299.ISO / February / Delphi / Install / DATA.Z / REPORT.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1996-06-09  |  35.6 KB  |  1,322 lines

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Delphi Visual Component Library                 }
  5. {                                                       }
  6. {       Copyright (c) 1995,96 Borland International     }
  7. {                                                       }
  8. {*******************************************************}
  9.  
  10. unit Report;
  11.  
  12. {$Z+,R-}
  13.  
  14. interface
  15.  
  16. uses SysUtils, Windows, Classes, Controls, Forms,
  17.   DDEMan, DB, Dsgnintf, Messages, BDE;
  18.  
  19. const
  20.   ctDBase = 2;
  21.   ctExcel = 3;
  22.   ctParadox = 4;
  23.   ctAscii = 5;
  24.   ctSqlServer = 6;
  25.   ctOracle = 7;
  26.   ctDB2 = 8;
  27.   ctNetSQL = 9;
  28.   ctSybase = 10;
  29.   ctBtrieve = 11;
  30.   ctGupta = 12;
  31.   ctIngres = 13;
  32.   ctWatcom = 14;
  33.   ctOcelot = 15;
  34.   ctTeraData = 16;
  35.   ctDB2Gupta = 17;
  36.   ctAS400 = 18;
  37.   ctUnify = 19;
  38.   ctQry = 20;
  39.   ctMinNative = 2;
  40.   ctMaxNative = 20;
  41.   ctODBCDBase = 40;
  42.   ctODBCExcel = 41;
  43.   ctODBCParadox = 42;
  44.   ctODBCSqlServer = 43;
  45.   ctODBCOracle = 44;
  46.   ctODBCDB2 = 45;
  47.   ctODBCNetSql = 46;
  48.   ctODBCSybase = 47;
  49.   ctODBCBtrieve = 48;
  50.   ctODBCGupta = 49;
  51.   ctODBCIngres = 50;
  52.   ctODBCDB2Gupta = 51;
  53.   ctODBCTeraData = 52;
  54.   ctODBCAS400 = 53;
  55.   ctODBCDWatcom = 54;
  56.   ctODBCDefault = 55;
  57.   ctODBCUnify = 56;
  58.   ctMinODBC = 40;
  59.   ctMaxODBC = 56;
  60.   ctIDAPIStandard = 60;
  61.   ctIDAPIParadox = 61;
  62.   ctIDAPIDBase = 62;
  63.   ctIDAPIAscii = 63;
  64.   ctIDAPIOracle = 64;
  65.   ctIDAPISybase = 65;
  66.   ctIDAPINovSql = 66;
  67.   ctIDAPIInterbase = 67;
  68.   ctIDAPIIBMEE = 68;
  69.   ctIDAPIDB2 = 69;
  70.   ctIDAPIInformix = 70;
  71.   ctMinIDAPI = 60;
  72.   ctMaxIDAPI = 70;
  73.  
  74. type
  75.   EReportError = class(Exception);
  76.   TReportManager = class;
  77.   TLaunchType = (ltDefault, ltRunTime, ltDesignTime);
  78.  
  79.   TReport = class(TComponent)
  80.   private
  81.     FOwner: TReportManager;
  82.     FReportName: string;
  83.     FReportDir: string;
  84.     FNumCopies: Word;
  85.     FStartPage: Word;
  86.     FEndPage: Word;
  87.     FMaxRecords: Word;
  88.     FRunTime: Boolean;
  89.     FStartedApp: Boolean;
  90.     FAutoUnload: Boolean;
  91.     FInitialValues: TStrings;
  92.     FLoaded: Boolean;
  93.     FVersionMajor: Integer;
  94.     FVersionMinor: Integer;
  95.     FReportHandle: HWND;
  96.     FPreview: Boolean;
  97.     FLaunchType: TLaunchType;
  98.     function GetBusy: Boolean;
  99.     function GetInitialValues: TStrings;
  100.     function GetReportHandle: HWND;
  101.     procedure RunApp;
  102.     function StartApplication: Boolean;
  103.     function ReportActive: Boolean;
  104.     function RunReport: Integer;
  105.     procedure SetInitialValues(Value: TStrings);
  106.     function UseRunTime: Boolean;
  107.   protected
  108.     procedure Notification(AComponent: TComponent;
  109.       Operation: TOperation); override;
  110.   public
  111.     constructor Create(AOwner: TComponent); override;
  112.     destructor Destroy; override;
  113.     function CloseApplication(ShowDialogs: Boolean): Integer;
  114.     function CloseReport(ShowDialogs: Boolean): Integer;
  115.     function Connect(ServerType: Word; const ServerName,
  116.       UserName, Password, DatabaseName: string): Integer;
  117.     function Print: Integer;
  118.     function RecalcReport: Integer;
  119.     function Run: Integer;
  120.     function RunMacro(const Macro: string): Integer;
  121.     function SetVariable(const Name, Value: string): Integer;
  122.     function SetVariableLines(const Name: string; Value: TStrings): Integer;
  123.     property ReportHandle: HWND read FReportHandle;
  124.     property Busy: Boolean read GetBusy;
  125.     property VersionMajor: Integer read FVersionMajor;
  126.     property VersionMinor: Integer read FVersionMinor;
  127.   published
  128.     property ReportName: string read FReportName write FReportName;
  129.     property ReportDir: string read FReportDir write FReportDir;
  130.     property PrintCopies: Word read FNumCopies write FNumCopies default 1;
  131.     property StartPage: Word read FStartPage write FStartPage default 1;
  132.     property EndPage: Word read FEndPage write FEndPage default 9999;
  133.     property MaxRecords: Word read FMaxRecords write FMaxRecords default 0;
  134.     property AutoUnload: Boolean read FAutoUnload write FAutoUnload default False;
  135.     property InitialValues: TStrings read GetInitialValues write SetInitialValues;
  136.     property Preview: Boolean read FPreview write FPreview default False;
  137.     property LaunchType: TLaunchType read FLaunchType write FLaunchType default ltDefault;
  138.   end;
  139.  
  140. { TReportManager }
  141.  
  142.   TCallType = (ctNone, ctDesignId, ctExecuteSQL, ctEndSQL,
  143.     ctGetError, ctGetTableList, ctGetColumnList, ctGetNext, ctGetMemo);
  144.  
  145.   PCallInfo = ^TCallInfo;
  146.   TCallInfo = record
  147.     ProcessId: THandle;
  148.     CallType: TCallType;
  149.     ErrorCode: Bool;
  150.     Data: record end;
  151.   end;
  152.  
  153.   PRSDateTime= ^TRSDateTime;
  154.   TRSDateTime = record
  155.     Year: Word;
  156.     Month: Word;
  157.     Day: Word;
  158.     Hour: Word;
  159.     Min: Word;
  160.     Sec: Word;
  161.     MSec: Word;
  162.   end;
  163.  
  164.   PDataElement = ^TDataElement;
  165.   TDataElement = packed record
  166.     FieldType: Integer;
  167.     ColumnName: array[0..DBIMAXNAMELEN] of char;
  168.     FieldLength: Word;
  169.     Null: Bool;
  170.     Data: record end;
  171.   end;
  172.  
  173.   PExecInfo = ^TExecInfo;
  174.   TExecInfo = record
  175.     DataSet: TDataSet;
  176.     MoreRecords: Bool;
  177.     NumCols: Word;
  178.   end;
  179.  
  180.   PStartExecInfo = ^TStartExecInfo;
  181.   TStartExecInfo = record
  182.     StmtIndex: Integer;
  183.     StmtName: array[0..19] of char;
  184.     MemoName: array[0..19] of char;
  185.     TableName: array[0..63] of char;
  186.   end;
  187.  
  188.   PMemoStruct = ^TMemoStruct;
  189.   TMemoStruct = record
  190.     DataSet: TDataSet;
  191.     Index: Integer;
  192.     ColumnName: array[0..DBIMAXNAMELEN] of char;
  193.     Pos: Integer;
  194.   end;
  195.  
  196.   PSQLStruct = ^TSQLStruct;
  197.   TSQLStruct = record
  198.     DataSet: TDataSet;
  199.     Index: Integer;
  200.   end;
  201.  
  202.   TReportManager = class(TComponent)
  203.   private
  204.     FReports: TList;
  205.     FDataSets: TList;
  206.     FHandle: HWND;
  207.     FLastError: string;
  208.     FUpdated: Boolean;
  209.     procedure ServerProc(Value: PCallInfo);
  210.     procedure WndProc(var Message: TMessage);
  211.   public
  212.     constructor Create(AOwner: TComponent); override;
  213.     destructor Destroy; override;
  214.     procedure Add(Value: TReport);
  215.     procedure AddDataSet(Root: TComponent);
  216.     procedure Clear;
  217.     function EndSQL(SQLStruct: PSQLStruct): Bool;
  218.     function ExecuteSQL(ExecInfo: PExecInfo;
  219.       StartExecInfo: PStartExecInfo): Bool;
  220.     function GetColumnList(Buffer: PChar): Bool;
  221.     function GetData(DataSet: TDataSet; pStmtMem: PDataElement): Bool;
  222.     function GetDataSet(Index: Integer): TDataSet;
  223.     function GetDataSetByName(Value: string): TDataSet;
  224.     function GetDataSets: TList;
  225.     function GetMemo(MemoStruct: PMemoStruct): Bool;
  226.     function GetNext(SQLStruct: PSQLStruct; var MoreData: Bool): Bool;
  227.     function GetReport(Index: Integer): TReport;
  228.     procedure GetTableList(Buffer: PChar);
  229.     procedure Remove(Value: TReport);
  230.     procedure UpdateDataSets;
  231.     function ValidDataType(Value: TFieldType): Boolean;
  232.     property DataSets: TList read GetDataSets;
  233.     property Reports: TList read FReports;
  234.     property DataSet[Index: Integer]: TDataSet read GetDataSet;
  235.     property Handle: HWND read FHandle;
  236.     property Report[Index: Integer]: TReport read GetReport;
  237.     property Updated: Boolean read FUpdated;
  238.   end;
  239.  
  240.   TReportEditor = class(TComponentEditor)
  241.   private
  242.     procedure Edit; override;
  243.     procedure ExecuteVerb(Index: Integer); override;
  244.     function GetVerb(Index: Integer): string; override;
  245.     function GetVerbCount: Integer; override;
  246.   end;
  247.  
  248.   TReportDirProperty = class(TPropertyEditor)
  249.   public
  250.     function GetValue: string; override;
  251.     procedure SetValue(const Value: string); override;
  252.     function GetAttributes: TPropertyAttributes; override;
  253.     procedure Edit; override;
  254.   end;
  255.  
  256.   TReportNameProperty = class(TPropertyEditor)
  257.   public
  258.     function GetValue: string; override;
  259.     procedure SetValue(const Value: string); override;
  260.     function GetAttributes: TPropertyAttributes; override;
  261.     procedure Edit; override;
  262.   end;
  263.  
  264. implementation
  265.  
  266. uses DBConsts, FileCtrl, Dialogs, IniFiles, Registry, LibHelp;
  267.  
  268. const
  269.   RSAPI = 'rs_api.dll';
  270.   RS_SUCCESS = 0;
  271.   RS_BUSY = 1;
  272.   DesignName = 'ReportSmith';
  273.   RunName = 'RS_RUNTIME';
  274.   TopicName = 'Command';
  275.   ReportClassName: string = 'OwlWindow';
  276.   DesignExeName = 'RptSmith.EXE';
  277.   RunExeName = 'RS_Run.EXE';
  278.   StatementBuffer = $FFFF;
  279.   MemoBuffer = $8000;
  280.  
  281. type
  282.   TServerProc = function(var Data: Integer): Bool stdcall;
  283.   TStmtStruct = record
  284.     StmtHandle: THandle;
  285.     StmtMem: Pointer;
  286.     MemoHandle: THandle;
  287.     MemoMem: Pointer;
  288.   end;
  289.  
  290. var
  291.   StartEvent: THandle;
  292.   SyncEvent: THandle;
  293.   SharedMem: Pointer;
  294.   ProcessId: Integer;
  295.   ReportManager: TReportManager;
  296.   StmtHandles: array[0..9] of TStmtStruct;
  297.   DriverHandle: THandle;
  298.   APIDriverHandle: THandle;
  299.   InitObjects: function(var StartEvent: THandle; var SyncEvent: THandle;
  300.     var SharedMem: Pointer; ThreadFunc: TThreadStartRoutine):Bool stdcall;
  301.   GetThread: function: THandle stdcall;
  302.   RS_PrintReport: function(StartingPage, EndingPage: Integer; Device, Port, Driver: PChar;
  303.     Copies: Integer): Integer; stdcall;
  304.   RS_SetRepVar: function(Name, Value: PChar): Integer; stdcall;
  305.   RS_Recalc: function: Integer; stdcall;
  306.   RS_CloseReport: function(Close: Integer): Integer; stdcall;
  307.   RS_CloseRS: function(Close: Integer): Integer; stdcall;
  308.   RS_SetRecordLimit: function(Limit: Integer): Integer; stdcall;
  309.   RS_LoadReport: function(FileName, Arguments: PChar; DraftMode,
  310.     RunReport: Bool): Integer; stdcall;
  311.   RS_ByteVersion: function(var Major, Minor: Integer): Word; stdcall;
  312.   RS_Connect: function(ServerType: Integer; const Server, UserId, Password,
  313.     Database: PChar): Integer; stdcall;
  314.   RS_IsBusy: function: Bool; stdcall;
  315.   RS_RunMacro: function(Macro: PChar): Integer; stdcall;
  316.   RS_IsReportSmithPresent: function: Bool; stdcall;
  317.   RS_Initiate: function(RunTime: Bool): Integer; stdcall;
  318.   RS_RegisterCallBack: function(Value: Pointer): Integer; stdcall;
  319.  
  320. function AsyncCallback: Boolean;
  321. var
  322.   Msg: TMsg;
  323. begin
  324.   if PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE) then
  325.   begin
  326.     with Application do
  327.     begin
  328.       HandleMessage;
  329.       Result := Terminated;
  330.      end;
  331.   end else
  332.     Result := False
  333. end;
  334.  
  335. function GetRootDir(RunTime: Boolean): string;
  336. var
  337.   Key: string;
  338.   Value: string;
  339. begin
  340.   Key := LoadStr(SRptKey);
  341.   if RunTime then
  342.     Value := LoadStr(SRptRunTimeValue) else
  343.     Value := LoadStr(SRptDesignTimeValue);
  344.   with TRegistry.Create do
  345.   try
  346.     RootKey := HKEY_LOCAL_MACHINE;
  347.     OpenKey(Key, True);
  348.     Result := ReadString(Value);
  349.   finally
  350.     Free;
  351.   end;
  352. end;
  353.  
  354. function APIDriverLoaded: Boolean;
  355. begin
  356.   Result := APIDriverHandle >= HINSTANCE_ERROR;
  357. end;
  358.  
  359. function InitAPIDriver: Boolean;
  360. var
  361.   OldError: Word;
  362.   Path: string;
  363. begin
  364.   OldError := SetErrorMode(SEM_NOOPENFILEERRORBOX);
  365.   try
  366.     Path := GetRootDir(False);
  367.     if Path = '' then
  368.       Path := GetRootDir(True);
  369.     if (Path <> '') and (Path[Length(Path)] <> '\') then
  370.       Path := Path + '\';
  371.     Path := Path + RSAPI;
  372.     APIDriverHandle := LoadLibrary(PChar(Path));
  373.     if APIDriverLoaded then
  374.     begin
  375.       @RS_PrintReport := GetProcAddress(APIDriverHandle, 'RS_PrintReport');
  376.       @RS_SetRepVar := GetProcAddress(APIDriverHandle, 'RS_SetRepVar');
  377.       @RS_Recalc := GetProcAddress(APIDriverHandle, 'RS_Recalc');
  378.       @RS_CloseReport := GetProcAddress(APIDriverHandle, 'RS_CloseReport');
  379.       @RS_CloseRS := GetProcAddress(APIDriverHandle, 'RS_CloseRS');
  380.       @RS_SetRecordLimit := GetProcAddress(APIDriverHandle, 'RS_SetRecordLimit');
  381.       @RS_LoadReport := GetProcAddress(APIDriverHandle, 'RS_LoadReport');
  382.       @RS_ByteVersion := GetProcAddress(APIDriverHandle, 'RS_ByteVersion');
  383.       @RS_Connect := GetProcAddress(APIDriverHandle, 'RS_Connect');
  384.       @RS_IsBusy := GetProcAddress(APIDriverHandle, 'RS_IsAPIBusy');
  385.       @RS_RunMacro := GetProcAddress(APIDriverHandle, 'RS_RunMacroCode');
  386.       @RS_IsReportSmithPresent := GetProcAddress(APIDriverHandle, 'RS_IsReportSmithPresent');
  387.       @RS_Initiate := GetProcAddress(APIDriverHandle, 'RS_InitiateAPI');
  388.       @RS_RegisterCallBack := GetProcAddress(APIDriverHandle, 'RS_RegisterWaitLoopCallback');
  389.     end
  390.     else APIDriverHandle := 1;
  391.   finally
  392.     SetErrorMode(OldError);
  393.   end;
  394.   Result := APIDriverLoaded;
  395. end;
  396.  
  397. function DriverLoaded: Boolean;
  398. begin
  399.   Result := DriverHandle >= HINSTANCE_ERROR;
  400. end;
  401.  
  402. function InitDriver: Boolean;
  403. const
  404.   RSDriverName = 'RS_DELPH.DLL';
  405. var
  406.   OldError: Word;
  407.   Path: string;
  408. begin
  409.   OldError := SetErrorMode(SEM_NOOPENFILEERRORBOX);
  410.   try
  411.     Path := GetRootDir(False);
  412.     if Path = '' then
  413.       Path := GetRootDir(True);
  414.     if (Path <> '') and (Path[Length(Path)] <> '\') then
  415.       Path := Path + '\';
  416.     Path := Path + RSDriverName;
  417.     DriverHandle := LoadLibrary(PChar(Path));
  418.     if DriverLoaded then
  419.     begin
  420.       @InitObjects := GetProcAddress(DriverHandle, 'InitObjects');
  421.       @GetThread := GetProcAddress(DriverHandle, 'GetThread');
  422.     end
  423.     else DriverHandle := 1;
  424.   finally
  425.     SetErrorMode(OldError);
  426.   end;
  427.   Result := DriverLoaded;
  428. end;
  429.  
  430. procedure RaiseError(const Message: string);
  431. begin
  432.   raise EReportError.Create(Message);
  433. end;
  434.  
  435. procedure GetDecodedDate(Date: TDateTime; var Value: TRSDateTime);
  436. begin
  437.   FillChar(Value, 0, SizeOf(TRSDateTime));
  438.   with Value do
  439.     DecodeDate(Date, Year, Month, Day);
  440. end;
  441.  
  442. procedure GetDecodedTime(Time: TDateTime; var Value: TRSDateTime);
  443. begin
  444.   FillChar(Value, 0, SizeOf(TRSDateTime));
  445.   with Value do
  446.     DecodeTime(Time, Hour, Min, Sec, MSec);
  447. end;
  448.  
  449. procedure GetDecodedDateTime(DateTime: TDateTime; var Value: TRSDateTime);
  450. begin
  451.   with Value do
  452.   begin
  453.     DecodeDate(DateTime, Year, Month, Day);
  454.     DecodeTime(DateTime, Hour, Min, Sec, MSec);
  455.   end;
  456. end;
  457.  
  458. procedure CleanUpStmt(Value: TStmtStruct);
  459. begin
  460.   with Value do
  461.   begin
  462.     if StmtMem <> nil then UnmapViewOfFile(StmtMem);
  463.     StmtMem := nil;
  464.     CloseHandle(StmtHandle);
  465.     StmtHandle := 0;
  466.     if MemoMem <> nil then UnmapViewOfFile(MemoMem);
  467.     MemoMem := nil;
  468.     CloseHandle(MemoHandle);
  469.     MemoHandle := 0;
  470.   end;
  471. end;
  472.  
  473. { TReport }
  474.  
  475. constructor TReport.Create(AOwner: TComponent);
  476. begin
  477.   inherited Create(AOwner);
  478.   ReportManager.Add(Self);
  479.   PrintCopies := 1;
  480.   StartPage := 1;
  481.   EndPage := 9999;
  482.   MaxRecords := 0;
  483.   FInitialValues := TStringList.Create;
  484.   LaunchType := ltDefault;
  485. end;
  486.  
  487. destructor TReport.Destroy;
  488. begin
  489.   ReportManager.Remove(Self);
  490.   if FRunTime and FStartedApp then CloseApplication(True);
  491.   FInitialValues.Free;
  492.   inherited Destroy;
  493. end;
  494.  
  495. procedure TReport.SetInitialValues(Value: TStrings);
  496. begin
  497.   FInitialValues.Assign(Value);
  498. end;
  499.  
  500. function TReport.GetInitialValues: TStrings;
  501. begin
  502.   Result := FInitialValues;
  503. end;
  504.  
  505. function TReport.SetVariable(const Name, Value: string): Integer;
  506. begin
  507.   if not Busy then
  508.   begin
  509.     Result := RS_SetRepVar(PChar(Name), PChar(Value));
  510.   end else
  511.     Result := RS_BUSY;
  512. end;
  513.  
  514. function TReport.SetVariableLines(const Name: string; Value: TStrings): Integer;
  515. var
  516.   Buffer, StrEnd: PChar;
  517.   BufLen: Word;
  518.   I, L, Count: Integer;
  519.   Temp: array[0..255] of Char;
  520.   S: string;
  521. begin
  522.   if not Busy then
  523.   begin
  524.     BufLen := 3;
  525.     for I := 0 to Value.Count - 1 do
  526.     begin
  527.       L := Length(Value[I]) + 2;
  528.       if L > 65520 - BufLen then Break;
  529.       Inc(BufLen, L);
  530.     end;
  531.     Buffer := AllocMem(BufLen);
  532.     try
  533.       StrEnd := StrECopy(Buffer, '"');
  534.       Count := Value.Count - 1;
  535.       for I := 0 to Count do
  536.       begin
  537.         StrCopy(Temp, PChar(Value[I]));
  538.         StrEnd := StrECopy(StrEnd, Temp);
  539.         if I <> Count then StrEnd := StrECopy(StrEnd, ' ');
  540.       end;
  541.       Buffer[StrLen(Buffer)] := '"';
  542.       S := Buffer;
  543.       Result := RS_SetRepVar(PChar(S), nil);
  544.     finally
  545.       FreeMem(Buffer, BufLen);
  546.     end;
  547.   end else
  548.     Result := RS_BUSY;
  549. end;
  550.  
  551. function TReport.RecalcReport: Integer;
  552. begin
  553.   if not Busy then
  554.     Result := RS_Recalc else
  555.     Result := RS_BUSY;
  556. end;
  557.  
  558. function TReport.ReportActive: Boolean;
  559. begin
  560.   Result := (ReportHandle <> 0) and (@RS_IsReportSmithPresent <> nil) and
  561.     RS_IsReportSmithPresent;
  562. end;
  563.  
  564. function TReport.UseRunTime: Boolean;
  565. begin
  566.   Result := (LaunchType = ltRunTime) or
  567.     ((LaunchType = ltDefault) and not (csDesigning in ComponentState));
  568. end;
  569.  
  570. function TReport.Print: Integer;
  571. begin
  572.   if not Busy then
  573.     Result := RS_PrintReport(StartPage, EndPage, nil, nil, nil, PrintCopies) else
  574.     Result := RS_BUSY;
  575. end;
  576.  
  577. function TReport.StartApplication: Boolean;
  578. var
  579.   ExeName: string;
  580.   ExePath: string;
  581.   StartupInfo: TStartupInfo;
  582.   ProcessInfo: TProcessInformation;
  583. begin
  584.   ExePath := GetRootDir(FRunTime);
  585.   if FRunTime then
  586.     ExeName := RunExeName else
  587.     ExeName := DesignExeName;
  588.   if (ExePath <> '') and (ExePath[Length(ExePath)] <> '\') then
  589.     ExePath := ExePath + '\';
  590.   ExeName := ExePath + ExeName;
  591.   FillChar(StartupInfo, SizeOf(TStartupInfo), 0);
  592.   with StartupInfo do
  593.   begin
  594.     cb := SizeOf(TStartupInfo);
  595.     dwFlags := STARTF_USESHOWWINDOW or STARTF_FORCEONFEEDBACK;
  596.     if not FRunTime or Preview then wShowWindow := SW_SHOWNORMAL
  597.     else wShowWindow := SW_SHOWMINNOACTIVE;
  598.   end;
  599.   Result := CreateProcess(PChar(ExeName), nil, nil, nil, False,
  600.     NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo, ProcessInfo);
  601.   if Result then
  602.     with ProcessInfo do
  603.     begin
  604.       WaitForInputIdle(hProcess, INFINITE);
  605.       CloseHandle(hThread);
  606.       CloseHandle(hProcess);
  607.       FReportHandle := GetReportHandle;
  608.     end;
  609.   FStartedApp := Result;
  610. end;
  611.  
  612. function TReport.CloseReport(ShowDialogs: Boolean): Integer;
  613. begin
  614.   if not RS_IsBusy then
  615.   begin
  616.     if ReportActive then
  617.       Result := RS_CloseReport(Ord(ShowDialogs))
  618.     else Result := RS_SUCCESS;
  619.   end else
  620.     Result := RS_BUSY;
  621. end;
  622.  
  623. function TReport.Connect(ServerType: Word; const ServerName,
  624.   UserName, Password, DatabaseName: string): Integer;
  625. begin
  626.   if not Busy then
  627.   begin
  628.     if ((ServerType >= ctMinNative) and (ServerType <= ctMaxNative)) or
  629.       ((ServerType >= ctMinODBC) and (ServerType <= ctMaxODBC)) or
  630.       ((ServerType >= ctMinIDAPI) and (ServerType <= ctMaxIDAPI)) then
  631.       Result := RS_Connect(ServerType, PChar(ServerName), PChar(UserName),
  632.         PChar(Password), PChar(DatabaseName))
  633.     else RaiseError(LoadStr(SInvalidServer));
  634.   end else
  635.     Result := RS_BUSY;
  636. end;
  637.  
  638. function TReport.CloseApplication(ShowDialogs: Boolean): Integer;
  639. begin
  640.   if not RS_IsBusy then
  641.   begin
  642.     if ReportActive then
  643.     begin
  644.       Result := RS_CloseRS(Ord(ShowDialogs));
  645.       if Result = RS_SUCCESS then
  646.       begin
  647.         FStartedApp := False;
  648.         FReportHandle := 0;
  649.       end;
  650.     end
  651.     else Result := RS_SUCCESS;
  652.   end else
  653.     Result := RS_BUSY;
  654. end;
  655.  
  656. function TReport.GetReportHandle: HWND;
  657. var
  658.   S: string;
  659. begin
  660.   if FRunTime then S := RunName
  661.   else S := DesignName;
  662.   Result := FindWindow(PChar(ReportClassName), PChar(S));
  663. end;
  664.  
  665. function TReport.GetBusy: Boolean;
  666. begin
  667.   if not ReportActive then RunApp;
  668.   Result := RS_IsBusy;
  669. end;
  670.  
  671. function TReport.RunMacro(const Macro: string): Integer;
  672. begin
  673.   if not Busy then
  674.   begin
  675.     if Macro <> '' then
  676.       Result := RS_RunMacro(PChar(Macro)) else
  677.       Result := RS_SUCCESS;
  678.   end else
  679.     Result := RS_BUSY;
  680. end;
  681.  
  682. procedure TReport.RunApp;
  683. var
  684.   AppName: string;
  685. begin
  686.   if not APIDriverLoaded then
  687.     raise Exception.Create(FmtLoadStr(SUnableToLoadAPIDLL, [RSAPI]));
  688.   if not ReportActive and not RS_IsBusy then
  689.   begin
  690.     FRunTime := UseRunTime;
  691.     FReportHandle := GetReportHandle;
  692.     if ReportHandle = 0 then
  693.       if not StartApplication then
  694.       begin
  695.         if FRunTime then raise Exception.Create(LoadStr(SRunLoadFailed))
  696.         else raise Exception.Create(LoadStr(SDesignLoadFailed));
  697.       end;
  698.     RS_Initiate(FRunTime);
  699.     if FRunTime then AppName := RunName
  700.     else AppName := DesignName;
  701.     if RS_ByteVersion(FVersionMajor, FVersionMinor) <> RS_SUCCESS then
  702.       raise Exception.CreateFmt(LoadStr(SCannotGetVersionInfo), [AppName]);
  703.     if VersionMajor = 0 then
  704.     begin
  705.       if FStartedApp then CloseApplication(False);
  706.       raise Exception.Create(LoadStr(SIncorrectVersion));
  707.     end;
  708.   end;
  709. end;
  710.  
  711. function TReport.Run: Integer;
  712. begin
  713.   Result := RunReport;
  714.   if FRunTime and FStartedApp and
  715.     AutoUnload and not Preview then CloseApplication(True);
  716. end;
  717.  
  718. function TReport.RunReport: Integer;
  719. var
  720.   Path, FileName: string;
  721.   Temp: array[0..255] of Char;
  722.   Buffer, StrEnd: PChar;
  723.   BufLen: Word;
  724.   I, L, Count: Integer;
  725.   S: string;
  726. begin
  727.   if not Busy then
  728.   begin
  729.     Result := RS_SetRecordLimit(MaxRecords);
  730.     if Result = RS_SUCCESS then
  731.     begin
  732.       Path := ReportDir;
  733.       if (Path <> EmptyStr) and (Path[Length(Path)] <> '\') then
  734.         Path := Path + '\';
  735.       FileName := ReportName;
  736.       if (FileName <> '') and (Pos('.', FileName) = 0) then
  737.         FileName := FileName + '.rpt';
  738.       if FileName <> '' then
  739.       begin
  740.         FileName := Path + FileName;
  741.         if not FileExists(FileName) then
  742.           raise Exception.Create(FmtLoadStr(SNoFile, [FileName]));
  743.         BufLen := 3;
  744.         for I := 0 to FInitialValues.Count - 1 do
  745.         begin
  746.           L := Length(FInitialValues[I]) + 2;
  747.           if L > 65520 - BufLen then Break;
  748.           Inc(BufLen, L);
  749.         end;
  750.         Buffer := AllocMem(BufLen);
  751.         try
  752.           StrEnd := StrECopy(Buffer, '"');
  753.           Count := FInitialValues.Count - 1;
  754.           for I := 0 to Count do
  755.           begin
  756.             StrCopy(Temp, PChar(FInitialValues[I]));
  757.             StrEnd := StrECopy(StrEnd, Temp);
  758.             if (I <> Count) and (Pos('>', FInitialValues[I]) > 0) then
  759.               StrEnd := StrECopy(StrEnd, ', ');
  760.           end;
  761.           Buffer[StrLen(Buffer)] := '"';
  762.           S := Buffer;
  763.           FmtStr(S, '%s,"#%x"', [S, ProcessId]);
  764.           Result := RS_LoadReport(PChar(FileName), PChar(S), False, True);
  765.         finally
  766.           FreeMem(Buffer, BufLen);
  767.         end;
  768.         if (Result = RS_SUCCESS) and FRunTime and not Preview then
  769.           Result := Print;
  770.       end;
  771.     end;
  772.   end else
  773.     Result := RS_BUSY;
  774. end;
  775.  
  776. { TReportEditor }
  777.  
  778. procedure TReportEditor.Edit;
  779. begin
  780.   TReport(Component).Run;
  781. end;
  782.  
  783. procedure TReportEditor.ExecuteVerb(Index: Integer);
  784. begin
  785.   if Index = 0 then Edit;
  786. end;
  787.  
  788. function TReportEditor.GetVerb(Index: Integer): string;
  789. begin
  790.   Result := LoadStr(SReportVerb);
  791. end;
  792.  
  793. function TReportEditor.GetVerbCount: Integer;
  794. begin
  795.   Result := 1;
  796. end;
  797.  
  798. { TReportDirProperty }
  799.  
  800. function TReportDirProperty.GetValue: string;
  801. begin
  802.   Result := (GetComponent(0) as TReport).ReportDir;
  803. end;
  804.  
  805. procedure TReportDirProperty.SetValue(const Value: string);
  806. begin
  807.   (GetComponent(0) as TReport).ReportDir := Value;
  808.   Modified;
  809. end;
  810.  
  811. function TReportDirProperty.GetAttributes: TPropertyAttributes;
  812. begin
  813.   Result := [paDialog, paMultiSelect];
  814. end;
  815.  
  816. procedure TReportDirProperty.Edit;
  817. var
  818.   FilePath: TFileName;
  819. begin
  820.   FilePath := '';
  821.   if SelectDirectory(FilePath, [], hcDSelectReportDir) then
  822.   begin
  823.     if FilePath[Length(FilePath)] <> '\' then FilePath := FilePath + '\';
  824.     SetValue(FilePath);
  825.   end;
  826. end;
  827.  
  828. { TReportNameProperty }
  829.  
  830. function TReportNameProperty.GetValue: string;
  831. begin
  832.   Result := (GetComponent(0) as TReport).ReportName;
  833. end;
  834.  
  835. procedure TReportNameProperty.SetValue(const Value: string);
  836. begin
  837.   (GetComponent(0) as TReport).ReportName := Value;
  838.   Modified;
  839. end;
  840.  
  841. function TReportNameProperty.GetAttributes: TPropertyAttributes;
  842. begin
  843.   Result := [paDialog, paMultiSelect];
  844. end;
  845.  
  846. procedure TReportNameProperty.Edit;
  847. var
  848.   Dialog: TOpenDialog;
  849.   FilePath: string;
  850. begin
  851.   Dialog := TOpenDialog.Create(nil);
  852.   try
  853.     with Dialog do
  854.     begin
  855.       DefaultExt := 'rpt';
  856.       Filter := LoadStr(SReportFilter);
  857.       if Execute then
  858.         with GetComponent(0) as TReport do
  859.         begin
  860.           FileName := FileName;
  861.           FilePath := ExtractFilePath(FileName);
  862.           ReportDir := FilePath;
  863.           ReportName := ExtractFileName(FileName);
  864.           Modified;
  865.         end;
  866.     end;
  867.   finally
  868.     Dialog.Free;
  869.   end;
  870. end;
  871.  
  872. procedure TReport.Notification(AComponent: TComponent;
  873.   Operation: TOperation);
  874. begin
  875.   inherited Notification(AComponent, Operation);
  876.   if AComponent is TDataSet then ReportManager.FUpdated := False;
  877. end;
  878.  
  879. { TReportManager }
  880.  
  881. constructor TReportManager.Create(AOwner: TComponent);
  882. begin
  883.   inherited Create(AOwner);
  884.   FReports := TList.Create;
  885.   FDataSets := TList.Create;
  886.   FHandle := AllocateHWnd(WndProc);
  887. end;
  888.  
  889. destructor TReportManager.Destroy;
  890. begin
  891.   Clear;
  892.   Reports.Free;
  893.   FDataSets.Free;
  894.   DeallocateHWnd(FHandle);
  895.   inherited Destroy;
  896. end;
  897.  
  898. procedure TReportManager.Clear;
  899. begin
  900.   while Reports.Count > 0 do TReport(Reports.Last).Free;
  901. end;
  902.  
  903. procedure TReportManager.WndProc(var Message: TMessage);
  904. begin
  905.   if Message.Msg = $7F00 then
  906.   begin
  907.     ServerProc(PCallInfo(SharedMem));
  908.   end
  909.   else with Message do
  910.     Result := DefWindowProc(FHandle, Msg, WParam, LParam);
  911. end;
  912.  
  913. procedure TReportManager.ServerProc(Value: PCallInfo);
  914. var
  915.   pData: Pointer;
  916. begin
  917.   pData := @Value^.Data;
  918.   with Value^ do
  919.   begin
  920.     ErrorCode := False;
  921.     case CallType of
  922.       ctExecuteSQL: ErrorCode := not ExecuteSQL(PExecInfo(pData),
  923.         PStartExecInfo(pData));
  924.       ctEndSQL: ErrorCode := not EndSQL(PSQLStruct(pData));
  925.       ctGetTableList: GetTableList(PChar(pData));
  926.       ctGetColumnList: ErrorCode := not GetColumnList(PChar(pData));
  927.       ctGetNext: ErrorCode := not GetNext(PSQLStruct(pData), Bool(pData^));
  928.       ctGetMemo: ErrorCode := not GetMemo(PMemoStruct(pData));
  929.       ctGetError: StrCopy(PChar(pData), PChar(FLastError));
  930.     end;
  931.   end;
  932. end;
  933.  
  934. procedure TReportManager.Add(Value: TReport);
  935. begin
  936.   Reports.Add(Value);
  937.   Value.FOwner := Self;
  938.   FUpdated := False;
  939. end;
  940.  
  941. procedure TReportManager.Remove(Value: TReport);
  942. begin
  943.   with Reports do Delete(IndexOf(Value));
  944.   Value.FOwner := nil;
  945.   FUpdated := False;
  946. end;
  947.  
  948. procedure TReportManager.AddDataSet(Root: TComponent);
  949. var
  950.   I: Integer;
  951. begin
  952.   if Root is TDataSet then FDataSets.Add(Root);
  953.   for I := 0 to Root.ComponentCount - 1 do
  954.     AddDataSet(Root.Components[I]);
  955. end;
  956.  
  957. function TReportManager.GetDataSet(Index: Integer): TDataSet;
  958. begin
  959.   Result := DataSets[Index];
  960. end;
  961.  
  962. function TReportManager.GetReport(Index: Integer): TReport;
  963. begin
  964.   Result := FReports[Index];
  965. end;
  966.  
  967. procedure TReportManager.UpdateDataSets;
  968. var
  969.   I, J: Integer;
  970.   Matched: Boolean;
  971. begin
  972.   FDataSets.Clear;
  973.   for I := 0 to Reports.Count - 1 do
  974.   begin
  975.     Matched := False;
  976.     for J := I + 1 to Reports.Count - 1 do
  977.       if Report[I].Owner = Report[J].Owner then
  978.       begin
  979.         Matched := True;
  980.         Break;
  981.       end;
  982.     if not Matched then AddDataSet(Report[I].Owner);
  983.   end;
  984.   FUpdated := True;
  985. end;
  986.  
  987. function TReportManager.ExecuteSQL(ExecInfo: PExecInfo;
  988.   StartExecInfo: PStartExecInfo): Bool;
  989. var
  990.   I, Size: Integer;
  991.   S: string;
  992.   DataElement: PDataElement;
  993.   pStmtMem, pMemoMem: Pointer;
  994.  
  995.   function GetDataSize(Value: TField): Integer;
  996.   begin
  997.     case Value.DataType of
  998.       ftString: Result := Value.Size + 1;
  999.       ftSmallint, ftInteger, ftWord, ftBoolean, ftAutoInc:
  1000.         Result := SizeOf(Integer);
  1001.       ftFloat, ftCurrency, ftBCD:
  1002.         Result := SizeOf(Double);
  1003.       ftDate, ftTime, ftDateTime:
  1004.         Result := SizeOf(TRSDateTime);
  1005.       else Result := 0;
  1006.     end;
  1007.   end;
  1008.  
  1009. begin
  1010.   Result := False;
  1011.   S := StartExecInfo^.TableName;
  1012.   with StmtHandles[StartExecInfo^.StmtIndex] do
  1013.   begin
  1014.     StmtHandle := OpenFileMapping(FILE_MAP_WRITE, False, StartExecInfo^.StmtName);
  1015.     if StmtHandle <> 0 then
  1016.       pStmtMem := MapViewOfFile(StmtHandle, FILE_MAP_WRITE, 0, 0, 0) else
  1017.       pStmtMem := nil;
  1018.     StmtMem := pStmtMem;
  1019.     MemoHandle := OpenFileMapping(FILE_MAP_WRITE, False, StartExecInfo^.MemoName);
  1020.     if MemoHandle <> 0 then
  1021.       pMemoMem := MapViewOfFile(MemoHandle, FILE_MAP_WRITE, 0, 0, 0) else
  1022.       pMemoMem := nil;
  1023.     MemoMem := pMemoMem;
  1024.   end;
  1025.   if (StmtHandles[StartExecInfo^.StmtIndex].StmtHandle <> 0) and
  1026.     (StmtHandles[StartExecInfo^.StmtIndex].MemoHandle <> 0) then
  1027.     with ExecInfo^ do
  1028.     begin
  1029.       DataSet := GetDataSetByName(S);
  1030.       if DataSet <> nil then
  1031.       try
  1032.         if DataSet.Active then DataSet.First
  1033.         else DataSet.Open;
  1034.         MoreRecords := not DataSet.EOF;
  1035.         NumCols := 0;
  1036.         DataElement := PDataElement(pStmtMem);
  1037.         Size := 0;
  1038.         for I := 0 to DataSet.FieldCount - 1 do
  1039.           Inc(Size, GetDataSize(DataSet.Fields[I]) + SizeOf(TDataElement));
  1040.         if Size < StatementBuffer then
  1041.         begin
  1042.           for I := 0 to DataSet.FieldCount - 1 do
  1043.             with DataSet.Fields[I], DataElement^ do
  1044.               if ValidDataType(DataType) then
  1045.               begin
  1046.                 StrLCopy(ColumnName, PChar(FieldName), SizeOf(ColumnName) - 1);
  1047.                 FieldType := Ord(DataType);
  1048.                 FieldLength := GetDataSize(DataSet.Fields[I]);
  1049.                 Inc(Integer(DataElement), SizeOf(TDataElement) + FieldLength);
  1050.                 Inc(NumCols);
  1051.               end;
  1052.           Result := GetData(DataSet, pStmtMem);
  1053.         end
  1054.         else FLastError := LoadStr(SRptBindBuffer);
  1055.       except
  1056.         on E: Exception do
  1057.           FLastError := E.Message;
  1058.       end
  1059.       else FLastError := LoadStr(SRptDataSetNotAvailable);
  1060.     end
  1061.   else FLastError := LoadStr(SRptSharedMemoryError);
  1062. end;
  1063.  
  1064. function TReportManager.GetData(DataSet: TDataSet; pStmtMem: PDataElement): Bool;
  1065. var
  1066.   I: Integer;
  1067.   DataValue: Pointer;
  1068.   DataElement: PDataElement;
  1069. begin
  1070.   Result := True;
  1071.   try
  1072.     DataElement := pStmtMem;
  1073.     for I := 0 to DataSet.FieldCount - 1 do
  1074.       with DataSet.Fields[I], DataElement^ do
  1075.         if ValidDataType(DataType) then
  1076.         begin
  1077.           DataValue := Pointer(@DataElement^.Data);
  1078.           Null := IsNull;
  1079.           if not Null then
  1080.           begin
  1081.             case DataType of
  1082.               ftString, ftVarBytes:
  1083.                 StrCopy(PChar(DataValue), PChar(AsString));
  1084.               ftBoolean: Bool(DataValue^) := AsBoolean;
  1085.               ftSmallint, ftInteger, ftWord, ftAutoInc:
  1086.                 Integer(DataValue^) := AsInteger;
  1087.               ftFloat, ftCurrency, ftBCD:
  1088.                 Double(DataValue^) := AsFloat;
  1089.               ftDate, ftTime, ftDateTime:
  1090.                 GetDecodedDateTime(AsDateTime, TRSDateTime(DataValue^));
  1091.             end;
  1092.           end;
  1093.           Inc(Integer(DataElement), SizeOf(TDataElement) + FieldLength);
  1094.         end;
  1095.   except
  1096.     on E: Exception do
  1097.       begin
  1098.         FLastError := E.Message;
  1099.         Result := False;
  1100.       end;
  1101.   end;
  1102. end;
  1103.  
  1104. function TReportManager.GetNext(SQLStruct: PSQLStruct; var MoreData: Bool): Bool;
  1105. var
  1106.   pStmtMem: Pointer;
  1107.   DataSet: TDataSet;
  1108. begin
  1109.   Result := False;
  1110.   pStmtMem := StmtHandles[SQLStruct^.Index].StmtMem;
  1111.   DataSet := SQLStruct^.DataSet;
  1112.   if DataSet <> nil then
  1113.     try
  1114.       DataSet.Next;
  1115.       Result := GetData(DataSet, pStmtMem);
  1116.       MoreData := not DataSet.EOF;
  1117.     except
  1118.       on E: Exception do
  1119.         FLastError := E.Message;
  1120.     end
  1121.   else FLastError := LoadStr(SRptNoDataSetAvailable);
  1122. end;
  1123.  
  1124. function TReportManager.GetMemo(MemoStruct: PMemoStruct): Bool;
  1125. var
  1126.   MemoMem: Pointer;
  1127.   DataSet: TDataSet;
  1128.   S: string;
  1129. begin
  1130.   Result := False;
  1131.   MemoMem := StmtHandles[MemoStruct^.Index].MemoMem;
  1132.   PChar(MemoMem)^ := #0;
  1133.   DataSet := MemoStruct^.DataSet;
  1134.   if DataSet <> nil then
  1135.     try
  1136.       S := DataSet.FieldByName(MemoStruct^.ColumnName).AsString;
  1137.       if Length(S) >= MemoStruct^.Pos then
  1138.         StrLCopy(MemoMem, @S[MemoStruct^.Pos + 1], MemoBuffer - 1);
  1139.       Result := True;
  1140.     except
  1141.       on E: Exception do
  1142.         FLastError := E.Message;
  1143.     end
  1144.   else FLastError := LoadStr(SRptNoDataSetAvailable);
  1145. end;
  1146.  
  1147. function TReportManager.ValidDataType(Value: TFieldType): Boolean;
  1148. begin
  1149.   Result := not (Value in [ftUnknown, ftBytes, ftVarBytes,
  1150.     ftGraphic, ftFmtMemo, ftParadoxOle, ftDBaseOle, ftTypedBinary])
  1151. end;
  1152.  
  1153. function TReportManager.EndSQL(SQLStruct: PSQLStruct): Bool;
  1154. begin
  1155.   Result := True;
  1156.   if SQLStruct^.DataSet <> nil then
  1157.   try
  1158.     SQLStruct^.DataSet.Close;
  1159.     CleanUpStmt(StmtHandles[SQLStruct^.Index]);
  1160.   except
  1161.     on E: Exception do
  1162.     begin
  1163.       FLastError := E.Message;
  1164.       Result := False;
  1165.     end;
  1166.   end
  1167. end;
  1168.  
  1169. function TReportManager.GetDataSets: TList;
  1170. begin
  1171.   if not Updated then UpdateDataSets;
  1172.   Result := FDataSets;
  1173. end;
  1174.  
  1175. procedure TReportManager.GetTableList(Buffer: PChar);
  1176. var
  1177.   S: string;
  1178.   I: Integer;
  1179. begin
  1180.   Buffer^ := #0;
  1181.   for I := 0 to DataSets.Count - 1 do
  1182.   begin
  1183.     S := DataSet[I].Name;
  1184.     StrCopy(Buffer, PChar(S));
  1185.     Inc(Integer(Buffer), Length(S) + 1);
  1186.   end;
  1187.   Buffer^ := #0;
  1188. end;
  1189.  
  1190. function TReportManager.GetDataSetByName(Value: string): TDataSet;
  1191. var
  1192.   I: Integer;
  1193. begin
  1194.   Result := nil;
  1195.   for I := 0 to DataSets.Count - 1 do
  1196.     if DataSet[I].Name = Value then
  1197.     begin
  1198.       Result := DataSet[I];
  1199.       Break;
  1200.     end;
  1201. end;
  1202.  
  1203. function TReportManager.GetColumnList(Buffer: PChar): Bool;
  1204. var
  1205.   S: string;
  1206.   DataSet: TDataSet;
  1207.  
  1208.   procedure GetNamesByField;
  1209.   var
  1210.     I: Integer;
  1211.   begin
  1212.     for I := 0 to DataSet.FieldCount - 1 do
  1213.       if ValidDataType(DataSet.Fields[I].DataType) then
  1214.       begin
  1215.         S := DataSet.Fields[I].FieldName;
  1216.         StrCopy(Buffer, PChar(S));
  1217.         Inc(Integer(Buffer), Length(S) + 1);
  1218.       end;
  1219.   end;
  1220.  
  1221.   procedure GetNamesByFieldDef;
  1222.   var
  1223.     I: Integer;
  1224.   begin
  1225.     for I := 0 to DataSet.FieldDefs.Count - 1 do
  1226.       if ValidDataType(DataSet.FieldDefs[I].DataType) then
  1227.       begin
  1228.         S := DataSet.FieldDefs[I].Name;
  1229.         StrCopy(Buffer, PChar(S));
  1230.         Inc(Integer(Buffer), Length(S) + 1);
  1231.       end;
  1232.   end;
  1233.  
  1234. begin
  1235.   Result := True;
  1236.   S := Buffer;
  1237.   Buffer^ := #0;
  1238.   DataSet := GetDataSetByName(S);
  1239.   if DataSet <> nil then
  1240.     with DataSet do
  1241.     try
  1242.       FieldDefs.Update;
  1243.       if FieldCount <> 0 then
  1244.         GetNamesByField else
  1245.         GetNamesByFieldDef;
  1246.     except
  1247.       on E: Exception do
  1248.         begin
  1249.           FLastError := E.Message;
  1250.           Result := False;
  1251.         end;
  1252.     end
  1253.   else begin
  1254.     FLastError := LoadStr(SRptNoDataSetAvailable);
  1255.     Result := False;
  1256.   end;
  1257.   Buffer^ := #0;
  1258. end;
  1259.  
  1260. procedure ProcessRequest;
  1261. var
  1262.   pData: Pointer;
  1263.   CallRec: PCallInfo;
  1264. begin
  1265.   CallRec := PCallInfo(SharedMem);
  1266.   pData := @CallRec^.Data;
  1267.   if (CallRec^.CallType = ctDesignId) and
  1268.     (ReportManager.Reports.Count > 0) and
  1269.     (csDesigning in ReportManager.Report[0].ComponentState) then
  1270.   begin
  1271.     CallRec^.ErrorCode := False;
  1272.     DWORD(pData^) := ProcessId;
  1273.   end
  1274.   else if CallRec^.ProcessId = ProcessId then
  1275.     SendMessage(ReportManager.Handle, $7F00, 0, 0);
  1276.   ResetEvent(StartEvent);
  1277.   SetEvent(SyncEvent);
  1278. end;
  1279.  
  1280. function WaitForRequest(pData: Pointer): Integer; stdcall;
  1281. begin
  1282.   while True do
  1283.   begin
  1284.     Result := WaitForSingleObject(StartEvent, INFINITE);
  1285.     if Result = WAIT_OBJECT_0 then ProcessRequest
  1286.     else break;
  1287.   end;
  1288. end;
  1289.  
  1290. procedure Initialize;
  1291. begin
  1292.   ReportManager := TReportManager.Create(nil);
  1293.   ProcessId := GetCurrentProcessId;
  1294.   if InitDriver then
  1295.     InitObjects(StartEvent, SyncEvent, SharedMem, @WaitForRequest);
  1296.   if InitAPIDriver then
  1297.     RS_RegisterCallBack(@AsyncCallback);
  1298. end;
  1299.  
  1300. procedure Finalize;
  1301. var
  1302.   Thread: THandle;
  1303.   I: Integer;
  1304. begin
  1305.   for I := Low(StmtHandles) to High(StmtHandles) do
  1306.     CleanUpStmt(StmtHandles[I]);
  1307.   if @GetThread <> nil then
  1308.   begin
  1309.     Thread := GetThread;
  1310.     if Thread <> 0 then TerminateThread(Thread, 0);
  1311.   end;
  1312.   ReportManager.Free;
  1313.   if DriverLoaded then FreeLibrary(DriverHandle);
  1314.   if APIDriverLoaded then FreeLibrary(APIDriverHandle);
  1315. end;
  1316.  
  1317. initialization
  1318.   Initialize;
  1319. finalization
  1320.   Finalize;
  1321. end.
  1322.