home *** CD-ROM | disk | FTP | other *** search
/ Chip 1997 April / Chip_1997-04_cd.bin / prezent / cb / data.z / REPORT.PAS < prev    next >
Pascal/Delphi Source File  |  1997-01-16  |  36KB  |  1,323 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, SizeOf(TRSDateTime), 0);
  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, SizeOf(TRSDateTime), 0);
  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 not IsPathDelimiter(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 not IsPathDelimiter(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 not IsPathDelimiter(FilePath, Length(FilePath)) then
  824.       FilePath := FilePath + '\';
  825.     SetValue(FilePath);
  826.   end;
  827. end;
  828.  
  829. { TReportNameProperty }
  830.  
  831. function TReportNameProperty.GetValue: string;
  832. begin
  833.   Result := (GetComponent(0) as TReport).ReportName;
  834. end;
  835.  
  836. procedure TReportNameProperty.SetValue(const Value: string);
  837. begin
  838.   (GetComponent(0) as TReport).ReportName := Value;
  839.   Modified;
  840. end;
  841.  
  842. function TReportNameProperty.GetAttributes: TPropertyAttributes;
  843. begin
  844.   Result := [paDialog, paMultiSelect];
  845. end;
  846.  
  847. procedure TReportNameProperty.Edit;
  848. var
  849.   Dialog: TOpenDialog;
  850.   FilePath: string;
  851. begin
  852.   Dialog := TOpenDialog.Create(nil);
  853.   try
  854.     with Dialog do
  855.     begin
  856.       DefaultExt := 'rpt';
  857.       Filter := LoadStr(SReportFilter);
  858.       if Execute then
  859.         with GetComponent(0) as TReport do
  860.         begin
  861.           FileName := FileName;
  862.           FilePath := ExtractFilePath(FileName);
  863.           ReportDir := FilePath;
  864.           ReportName := ExtractFileName(FileName);
  865.           Modified;
  866.         end;
  867.     end;
  868.   finally
  869.     Dialog.Free;
  870.   end;
  871. end;
  872.  
  873. procedure TReport.Notification(AComponent: TComponent;
  874.   Operation: TOperation);
  875. begin
  876.   inherited Notification(AComponent, Operation);
  877.   if AComponent is TDataSet then ReportManager.FUpdated := False;
  878. end;
  879.  
  880. { TReportManager }
  881.  
  882. constructor TReportManager.Create(AOwner: TComponent);
  883. begin
  884.   inherited Create(AOwner);
  885.   FReports := TList.Create;
  886.   FDataSets := TList.Create;
  887.   FHandle := AllocateHWnd(WndProc);
  888. end;
  889.  
  890. destructor TReportManager.Destroy;
  891. begin
  892.   Clear;
  893.   Reports.Free;
  894.   FDataSets.Free;
  895.   DeallocateHWnd(FHandle);
  896.   inherited Destroy;
  897. end;
  898.  
  899. procedure TReportManager.Clear;
  900. begin
  901.   while Reports.Count > 0 do TReport(Reports.Last).Free;
  902. end;
  903.  
  904. procedure TReportManager.WndProc(var Message: TMessage);
  905. begin
  906.   if Message.Msg = $7F00 then
  907.   begin
  908.     ServerProc(PCallInfo(SharedMem));
  909.   end
  910.   else with Message do
  911.     Result := DefWindowProc(FHandle, Msg, WParam, LParam);
  912. end;
  913.  
  914. procedure TReportManager.ServerProc(Value: PCallInfo);
  915. var
  916.   pData: Pointer;
  917. begin
  918.   pData := @Value^.Data;
  919.   with Value^ do
  920.   begin
  921.     ErrorCode := False;
  922.     case CallType of
  923.       ctExecuteSQL: ErrorCode := not ExecuteSQL(PExecInfo(pData),
  924.         PStartExecInfo(pData));
  925.       ctEndSQL: ErrorCode := not EndSQL(PSQLStruct(pData));
  926.       ctGetTableList: GetTableList(PChar(pData));
  927.       ctGetColumnList: ErrorCode := not GetColumnList(PChar(pData));
  928.       ctGetNext: ErrorCode := not GetNext(PSQLStruct(pData), Bool(pData^));
  929.       ctGetMemo: ErrorCode := not GetMemo(PMemoStruct(pData));
  930.       ctGetError: StrCopy(PChar(pData), PChar(FLastError));
  931.     end;
  932.   end;
  933. end;
  934.  
  935. procedure TReportManager.Add(Value: TReport);
  936. begin
  937.   Reports.Add(Value);
  938.   Value.FOwner := Self;
  939.   FUpdated := False;
  940. end;
  941.  
  942. procedure TReportManager.Remove(Value: TReport);
  943. begin
  944.   with Reports do Delete(IndexOf(Value));
  945.   Value.FOwner := nil;
  946.   FUpdated := False;
  947. end;
  948.  
  949. procedure TReportManager.AddDataSet(Root: TComponent);
  950. var
  951.   I: Integer;
  952. begin
  953.   if Root is TDataSet then FDataSets.Add(Root);
  954.   for I := 0 to Root.ComponentCount - 1 do
  955.     AddDataSet(Root.Components[I]);
  956. end;
  957.  
  958. function TReportManager.GetDataSet(Index: Integer): TDataSet;
  959. begin
  960.   Result := DataSets[Index];
  961. end;
  962.  
  963. function TReportManager.GetReport(Index: Integer): TReport;
  964. begin
  965.   Result := FReports[Index];
  966. end;
  967.  
  968. procedure TReportManager.UpdateDataSets;
  969. var
  970.   I, J: Integer;
  971.   Matched: Boolean;
  972. begin
  973.   FDataSets.Clear;
  974.   for I := 0 to Reports.Count - 1 do
  975.   begin
  976.     Matched := False;
  977.     for J := I + 1 to Reports.Count - 1 do
  978.       if Report[I].Owner = Report[J].Owner then
  979.       begin
  980.         Matched := True;
  981.         Break;
  982.       end;
  983.     if not Matched then AddDataSet(Report[I].Owner);
  984.   end;
  985.   FUpdated := True;
  986. end;
  987.  
  988. function TReportManager.ExecuteSQL(ExecInfo: PExecInfo;
  989.   StartExecInfo: PStartExecInfo): Bool;
  990. var
  991.   I, Size: Integer;
  992.   S: string;
  993.   DataElement: PDataElement;
  994.   pStmtMem, pMemoMem: Pointer;
  995.  
  996.   function GetDataSize(Value: TField): Integer;
  997.   begin
  998.     case Value.DataType of
  999.       ftString: Result := Value.Size + 1;
  1000.       ftSmallint, ftInteger, ftWord, ftBoolean, ftAutoInc:
  1001.         Result := SizeOf(Integer);
  1002.       ftFloat, ftCurrency, ftBCD:
  1003.         Result := SizeOf(Double);
  1004.       ftDate, ftTime, ftDateTime:
  1005.         Result := SizeOf(TRSDateTime);
  1006.       else Result := 0;
  1007.     end;
  1008.   end;
  1009.  
  1010. begin
  1011.   Result := False;
  1012.   S := StartExecInfo^.TableName;
  1013.   with StmtHandles[StartExecInfo^.StmtIndex] do
  1014.   begin
  1015.     StmtHandle := OpenFileMapping(FILE_MAP_WRITE, False, StartExecInfo^.StmtName);
  1016.     if StmtHandle <> 0 then
  1017.       pStmtMem := MapViewOfFile(StmtHandle, FILE_MAP_WRITE, 0, 0, 0) else
  1018.       pStmtMem := nil;
  1019.     StmtMem := pStmtMem;
  1020.     MemoHandle := OpenFileMapping(FILE_MAP_WRITE, False, StartExecInfo^.MemoName);
  1021.     if MemoHandle <> 0 then
  1022.       pMemoMem := MapViewOfFile(MemoHandle, FILE_MAP_WRITE, 0, 0, 0) else
  1023.       pMemoMem := nil;
  1024.     MemoMem := pMemoMem;
  1025.   end;
  1026.   if (StmtHandles[StartExecInfo^.StmtIndex].StmtHandle <> 0) and
  1027.     (StmtHandles[StartExecInfo^.StmtIndex].MemoHandle <> 0) then
  1028.     with ExecInfo^ do
  1029.     begin
  1030.       DataSet := GetDataSetByName(S);
  1031.       if DataSet <> nil then
  1032.       try
  1033.         if DataSet.Active then DataSet.First
  1034.         else DataSet.Open;
  1035.         MoreRecords := not DataSet.EOF;
  1036.         NumCols := 0;
  1037.         DataElement := PDataElement(pStmtMem);
  1038.         Size := 0;
  1039.         for I := 0 to DataSet.FieldCount - 1 do
  1040.           Inc(Size, GetDataSize(DataSet.Fields[I]) + SizeOf(TDataElement));
  1041.         if Size < StatementBuffer then
  1042.         begin
  1043.           for I := 0 to DataSet.FieldCount - 1 do
  1044.             with DataSet.Fields[I], DataElement^ do
  1045.               if ValidDataType(DataType) then
  1046.               begin
  1047.                 StrLCopy(ColumnName, PChar(FieldName), SizeOf(ColumnName) - 1);
  1048.                 FieldType := Ord(DataType);
  1049.                 FieldLength := GetDataSize(DataSet.Fields[I]);
  1050.                 Inc(Integer(DataElement), SizeOf(TDataElement) + FieldLength);
  1051.                 Inc(NumCols);
  1052.               end;
  1053.           Result := GetData(DataSet, pStmtMem);
  1054.         end
  1055.         else FLastError := LoadStr(SRptBindBuffer);
  1056.       except
  1057.         on E: Exception do
  1058.           FLastError := E.Message;
  1059.       end
  1060.       else FLastError := LoadStr(SRptDataSetNotAvailable);
  1061.     end
  1062.   else FLastError := LoadStr(SRptSharedMemoryError);
  1063. end;
  1064.  
  1065. function TReportManager.GetData(DataSet: TDataSet; pStmtMem: PDataElement): Bool;
  1066. var
  1067.   I: Integer;
  1068.   DataValue: Pointer;
  1069.   DataElement: PDataElement;
  1070. begin
  1071.   Result := True;
  1072.   try
  1073.     DataElement := pStmtMem;
  1074.     for I := 0 to DataSet.FieldCount - 1 do
  1075.       with DataSet.Fields[I], DataElement^ do
  1076.         if ValidDataType(DataType) then
  1077.         begin
  1078.           DataValue := Pointer(@DataElement^.Data);
  1079.           Null := IsNull;
  1080.           if not Null then
  1081.           begin
  1082.             case DataType of
  1083.               ftString, ftVarBytes:
  1084.                 StrCopy(PChar(DataValue), PChar(AsString));
  1085.               ftBoolean: Bool(DataValue^) := AsBoolean;
  1086.               ftSmallint, ftInteger, ftWord, ftAutoInc:
  1087.                 Integer(DataValue^) := AsInteger;
  1088.               ftFloat, ftCurrency, ftBCD:
  1089.                 Double(DataValue^) := AsFloat;
  1090.               ftDate, ftTime, ftDateTime:
  1091.                 GetDecodedDateTime(AsDateTime, TRSDateTime(DataValue^));
  1092.             end;
  1093.           end;
  1094.           Inc(Integer(DataElement), SizeOf(TDataElement) + FieldLength);
  1095.         end;
  1096.   except
  1097.     on E: Exception do
  1098.       begin
  1099.         FLastError := E.Message;
  1100.         Result := False;
  1101.       end;
  1102.   end;
  1103. end;
  1104.  
  1105. function TReportManager.GetNext(SQLStruct: PSQLStruct; var MoreData: Bool): Bool;
  1106. var
  1107.   pStmtMem: Pointer;
  1108.   DataSet: TDataSet;
  1109. begin
  1110.   Result := False;
  1111.   pStmtMem := StmtHandles[SQLStruct^.Index].StmtMem;
  1112.   DataSet := SQLStruct^.DataSet;
  1113.   if DataSet <> nil then
  1114.     try
  1115.       DataSet.Next;
  1116.       Result := GetData(DataSet, pStmtMem);
  1117.       MoreData := not DataSet.EOF;
  1118.     except
  1119.       on E: Exception do
  1120.         FLastError := E.Message;
  1121.     end
  1122.   else FLastError := LoadStr(SRptNoDataSetAvailable);
  1123. end;
  1124.  
  1125. function TReportManager.GetMemo(MemoStruct: PMemoStruct): Bool;
  1126. var
  1127.   MemoMem: Pointer;
  1128.   DataSet: TDataSet;
  1129.   S: string;
  1130. begin
  1131.   Result := False;
  1132.   MemoMem := StmtHandles[MemoStruct^.Index].MemoMem;
  1133.   PChar(MemoMem)^ := #0;
  1134.   DataSet := MemoStruct^.DataSet;
  1135.   if DataSet <> nil then
  1136.     try
  1137.       S := DataSet.FieldByName(MemoStruct^.ColumnName).AsString;
  1138.       if Length(S) >= MemoStruct^.Pos then
  1139.         StrLCopy(MemoMem, @S[MemoStruct^.Pos + 1], MemoBuffer - 1);
  1140.       Result := True;
  1141.     except
  1142.       on E: Exception do
  1143.         FLastError := E.Message;
  1144.     end
  1145.   else FLastError := LoadStr(SRptNoDataSetAvailable);
  1146. end;
  1147.  
  1148. function TReportManager.ValidDataType(Value: TFieldType): Boolean;
  1149. begin
  1150.   Result := not (Value in [ftUnknown, ftBytes, ftVarBytes,
  1151.     ftGraphic, ftFmtMemo, ftParadoxOle, ftDBaseOle, ftTypedBinary])
  1152. end;
  1153.  
  1154. function TReportManager.EndSQL(SQLStruct: PSQLStruct): Bool;
  1155. begin
  1156.   Result := True;
  1157.   if SQLStruct^.DataSet <> nil then
  1158.   try
  1159.     SQLStruct^.DataSet.Close;
  1160.     CleanUpStmt(StmtHandles[SQLStruct^.Index]);
  1161.   except
  1162.     on E: Exception do
  1163.     begin
  1164.       FLastError := E.Message;
  1165.       Result := False;
  1166.     end;
  1167.   end
  1168. end;
  1169.  
  1170. function TReportManager.GetDataSets: TList;
  1171. begin
  1172.   if not Updated then UpdateDataSets;
  1173.   Result := FDataSets;
  1174. end;
  1175.  
  1176. procedure TReportManager.GetTableList(Buffer: PChar);
  1177. var
  1178.   S: string;
  1179.   I: Integer;
  1180. begin
  1181.   Buffer^ := #0;
  1182.   for I := 0 to DataSets.Count - 1 do
  1183.   begin
  1184.     S := DataSet[I].Name;
  1185.     StrCopy(Buffer, PChar(S));
  1186.     Inc(Integer(Buffer), Length(S) + 1);
  1187.   end;
  1188.   Buffer^ := #0;
  1189. end;
  1190.  
  1191. function TReportManager.GetDataSetByName(Value: string): TDataSet;
  1192. var
  1193.   I: Integer;
  1194. begin
  1195.   Result := nil;
  1196.   for I := 0 to DataSets.Count - 1 do
  1197.     if DataSet[I].Name = Value then
  1198.     begin
  1199.       Result := DataSet[I];
  1200.       Break;
  1201.     end;
  1202. end;
  1203.  
  1204. function TReportManager.GetColumnList(Buffer: PChar): Bool;
  1205. var
  1206.   S: string;
  1207.   DataSet: TDataSet;
  1208.  
  1209.   procedure GetNamesByField;
  1210.   var
  1211.     I: Integer;
  1212.   begin
  1213.     for I := 0 to DataSet.FieldCount - 1 do
  1214.       if ValidDataType(DataSet.Fields[I].DataType) then
  1215.       begin
  1216.         S := DataSet.Fields[I].FieldName;
  1217.         StrCopy(Buffer, PChar(S));
  1218.         Inc(Integer(Buffer), Length(S) + 1);
  1219.       end;
  1220.   end;
  1221.  
  1222.   procedure GetNamesByFieldDef;
  1223.   var
  1224.     I: Integer;
  1225.   begin
  1226.     for I := 0 to DataSet.FieldDefs.Count - 1 do
  1227.       if ValidDataType(DataSet.FieldDefs[I].DataType) then
  1228.       begin
  1229.         S := DataSet.FieldDefs[I].Name;
  1230.         StrCopy(Buffer, PChar(S));
  1231.         Inc(Integer(Buffer), Length(S) + 1);
  1232.       end;
  1233.   end;
  1234.  
  1235. begin
  1236.   Result := True;
  1237.   S := Buffer;
  1238.   Buffer^ := #0;
  1239.   DataSet := GetDataSetByName(S);
  1240.   if DataSet <> nil then
  1241.     with DataSet do
  1242.     try
  1243.       FieldDefs.Update;
  1244.       if FieldCount <> 0 then
  1245.         GetNamesByField else
  1246.         GetNamesByFieldDef;
  1247.     except
  1248.       on E: Exception do
  1249.         begin
  1250.           FLastError := E.Message;
  1251.           Result := False;
  1252.         end;
  1253.     end
  1254.   else begin
  1255.     FLastError := LoadStr(SRptNoDataSetAvailable);
  1256.     Result := False;
  1257.   end;
  1258.   Buffer^ := #0;
  1259. end;
  1260.  
  1261. procedure ProcessRequest;
  1262. var
  1263.   pData: Pointer;
  1264.   CallRec: PCallInfo;
  1265. begin
  1266.   CallRec := PCallInfo(SharedMem);
  1267.   pData := @CallRec^.Data;
  1268.   if (CallRec^.CallType = ctDesignId) and
  1269.     (ReportManager.Reports.Count > 0) and
  1270.     (csDesigning in ReportManager.Report[0].ComponentState) then
  1271.   begin
  1272.     CallRec^.ErrorCode := False;
  1273.     DWORD(pData^) := ProcessId;
  1274.   end
  1275.   else if CallRec^.ProcessId = ProcessId then
  1276.     SendMessage(ReportManager.Handle, $7F00, 0, 0);
  1277.   ResetEvent(StartEvent);
  1278.   SetEvent(SyncEvent);
  1279. end;
  1280.  
  1281. function WaitForRequest(pData: Pointer): Integer; stdcall;
  1282. begin
  1283.   while True do
  1284.   begin
  1285.     Result := WaitForSingleObject(StartEvent, INFINITE);
  1286.     if Result = WAIT_OBJECT_0 then ProcessRequest
  1287.     else break;
  1288.   end;
  1289. end;
  1290.  
  1291. procedure Initialize;
  1292. begin
  1293.   ReportManager := TReportManager.Create(nil);
  1294.   ProcessId := GetCurrentProcessId;
  1295.   if InitDriver then
  1296.     InitObjects(StartEvent, SyncEvent, SharedMem, @WaitForRequest);
  1297.   if InitAPIDriver then
  1298.     RS_RegisterCallBack(@AsyncCallback);
  1299. end;
  1300.  
  1301. procedure Finalize;
  1302. var
  1303.   Thread: THandle;
  1304.   I: Integer;
  1305. begin
  1306.   for I := Low(StmtHandles) to High(StmtHandles) do
  1307.     CleanUpStmt(StmtHandles[I]);
  1308.   if @GetThread <> nil then
  1309.   begin
  1310.     Thread := GetThread;
  1311.     if Thread <> 0 then TerminateThread(Thread, 0);
  1312.   end;
  1313.   ReportManager.Free;
  1314.   if DriverLoaded then FreeLibrary(DriverHandle);
  1315.   if APIDriverLoaded then FreeLibrary(APIDriverHandle);
  1316. end;
  1317.  
  1318. initialization
  1319.   Initialize;
  1320. finalization
  1321.   Finalize;
  1322. end.
  1323.