home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / Runimage / Delphi50 / Source / Vcl / DDEMAN.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1999-08-11  |  45.2 KB  |  1,795 lines

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Borland Delphi Visual Component Library         }
  5. {                                                       }
  6. {       Copyright (c) 1995,99 Inprise Corporation       }
  7. {                                                       }
  8. {*******************************************************}
  9.  
  10. unit DdeMan;
  11.  
  12. {$R-,T-,H+,X+}
  13.  
  14. interface
  15.  
  16. uses
  17.   Windows, Classes, Graphics, Forms, Controls, DDEML, StdCtrls;
  18.  
  19. type
  20.   TDataMode = (ddeAutomatic, ddeManual);
  21.   TDdeServerConv = class;
  22.  
  23.   TMacroEvent = procedure(Sender: TObject; Msg: TStrings) of object;
  24.  
  25.   TDdeClientItem = class;
  26.  
  27. { TDdeClientConv }
  28.  
  29.   TDdeClientConv = class(TComponent)
  30.   private
  31.     FDdeService: string;
  32.     FDdeTopic: string;
  33.     FConv: HConv;
  34.     FCnvInfo: TConvInfo;
  35.     FItems: TList;
  36.     FHszApp: HSZ;
  37.     FHszTopic: HSZ;
  38.     FDdeFmt: Integer;
  39.     FOnClose: TNotifyEvent;
  40.     FOnOpen: TNotifyEvent;
  41.     FAppName: string;
  42.     FDataMode: TDataMode;
  43.     FConnectMode: TDataMode;
  44.     FWaitStat: Boolean;
  45.     FFormatChars: Boolean;
  46.     procedure SetDdeService(const Value: string);
  47.     procedure SetDdeTopic(const Value: string);
  48.     procedure SetService(const Value: string);
  49.     procedure SetTopic(const Value: string);
  50.     procedure SetConnectMode(NewMode: TDataMode);
  51.     procedure SetFormatChars(NewFmt: Boolean);
  52.     procedure XactComplete;
  53.     procedure SrvrDisconnect;
  54.     procedure DataChange(DdeDat: HDDEData; hszIt: HSZ);
  55.   protected
  56.     function CreateDdeConv(FHszApp: HSZ; FHszTopic: HSZ): Boolean;
  57.     function GetCliItemByName(const ItemName: string): TPersistent;
  58.     function GetCliItemByCtrl(ACtrl: TDdeClientItem): TPersistent;
  59.     procedure Loaded; override;
  60.     procedure DefineProperties(Filer: TFiler); override;
  61.     procedure ReadLinkInfo(Reader: TReader);
  62.     procedure WriteLinkInfo(Writer: TWriter);
  63.     function OnSetItem(aCtrl: TDdeClientItem; const S: string): Boolean;
  64.     procedure OnAttach(aCtrl: TDdeClientItem);
  65.     procedure OnDetach(aCtrl: TDdeClientItem);
  66.     procedure Close; dynamic;
  67.     procedure Open; dynamic;
  68.     function ChangeLink(const App, Topic, Item: string): Boolean;
  69.     procedure ClearItems;
  70.     procedure Notification(AComponent: TComponent;
  71.       Operation: TOperation); override;
  72.   public
  73.     constructor Create(AOwner: TComponent); override;
  74.     destructor Destroy; override;
  75.     function PasteLink: Boolean;
  76.     function OpenLink: Boolean;
  77.     function SetLink(const Service, Topic: string): Boolean;
  78.     procedure CloseLink;
  79.     function StartAdvise: Boolean;
  80.     function PokeDataLines(const Item: string; Data: TStrings): Boolean;
  81.     function PokeData(const Item: string; Data: PChar): Boolean;
  82.     function ExecuteMacroLines(Cmd: TStrings; waitFlg: Boolean): Boolean;
  83.     function ExecuteMacro(Cmd: PChar; waitFlg: Boolean): Boolean;
  84.     function RequestData(const Item: string): PChar;
  85.     property DdeFmt: Integer read FDdeFmt;
  86.     property WaitStat: Boolean read FWaitStat;
  87.     property Conv: HConv read FConv;
  88.     property DataMode: TDataMode read FDataMode write FDataMode;
  89.   published
  90.     property ServiceApplication: string read FAppName write FAppName;
  91.     property DdeService: string read FDdeService write SetDdeService;
  92.     property DdeTopic: string read FDdeTopic write SetDdeTopic;
  93.     property ConnectMode: TDataMode read FConnectMode write SetConnectMode default ddeAutomatic;
  94.     property FormatChars: Boolean read FFormatChars write SetFormatChars default False;
  95.     property OnClose: TNotifyEvent read FOnClose write FOnClose;
  96.     property OnOpen: TNotifyEvent read FOnOpen write FOnOpen;
  97.   end;
  98.  
  99. { TDdeClientItem }
  100.  
  101.   TDdeClientItem = class(TComponent)
  102.   private
  103.     FLines: TStrings;
  104.     FDdeClientConv: TDdeClientConv;
  105.     FDdeClientItem: string;
  106.     FOnChange: TNotifyEvent;
  107.     function GetText: string;
  108.     procedure SetDdeClientItem(const Val: string);
  109.     procedure SetDdeClientConv(Val: TDdeClientConv);
  110.     procedure SetText(const S: string);
  111.     procedure SetLines(L: TStrings);
  112.     procedure OnAdvise;
  113.   protected
  114.     procedure Notification(AComponent: TComponent;
  115.       Operation: TOperation); override;
  116.   public
  117.     constructor Create(AOwner: TComponent); override;
  118.     destructor Destroy; override;
  119.   published
  120.     property Text: string read GetText write SetText;
  121.     property Lines: TStrings read FLines write SetLines;
  122.     property DdeConv: TDdeClientConv read FDdeClientConv write SetDdeClientConv;
  123.     property DdeItem: string read FDdeClientItem write SetDdeClientItem;
  124.     property OnChange: TNotifyEvent read FOnChange write FOnChange;
  125.   end;
  126.  
  127. { TDdeServerConv }
  128.  
  129.   TDdeServerConv = class(TComponent)
  130.   private
  131.     FOnOpen: TNotifyEvent;
  132.     FOnClose: TNotifyEvent;
  133.     FOnExecuteMacro: TMacroEvent;
  134.   protected
  135.     procedure Connect; dynamic;
  136.     procedure Disconnect; dynamic;
  137.   public
  138.     constructor Create(AOwner: TComponent); override;
  139.     destructor Destroy; override;
  140.     function ExecuteMacro(Data: HDdeData): LongInt;
  141.   published
  142.     property OnOpen: TNotifyEvent read FOnOpen write FOnOpen;
  143.     property OnClose: TNotifyEvent read FOnClose write FOnClose;
  144.     property OnExecuteMacro: TMacroEvent read FOnExecuteMacro write FOnExecuteMacro;
  145.   end;
  146.  
  147. { TDdeServerItem }
  148.  
  149.   TDdeServerItem = class(TComponent)
  150.   private
  151.     FLines: TStrings;
  152.     FServerConv: TDdeServerConv;
  153.     FOnChange: TNotifyEvent;
  154.     FOnPokeData: TNotifyEvent;
  155.     FFmt: Integer;
  156.     procedure ValueChanged;
  157.   protected
  158.     function GetText: string;
  159.     procedure SetText(const Item: string);
  160.     procedure SetLines(Value: TStrings);
  161.     procedure SetServerConv(SConv: TDdeServerConv);
  162.     procedure Notification(AComponent: TComponent;
  163.       Operation: TOperation); override;
  164.   public
  165.     constructor Create(AOwner: TComponent); override;
  166.     destructor Destroy; override;
  167.     function PokeData(Data: HDdeData): LongInt;
  168.     procedure CopyToClipboard;
  169.     procedure Change; dynamic;
  170.     property Fmt: Integer read FFmt;
  171.   published
  172.     property ServerConv: TDdeServerConv read FServerConv write SetServerConv;
  173.     property Text: string read GetText write SetText;
  174.     property Lines: TStrings read FLines write SetLines;
  175.     property OnChange: TNotifyEvent read FOnChange write FOnChange;
  176.     property OnPokeData: TNotifyEvent read FOnPokeData write FOnPokeData;
  177.   end;
  178.  
  179. { TDdeMgr }
  180.  
  181.   TDdeMgr = class(TComponent)
  182.   private
  183.     FAppName: string;
  184.     FHszApp: HSZ;
  185.     FConvs: TList;
  186.     FCliConvs: TList;
  187.     FConvCtrls: TList;
  188.     FDdeInstId: Longint;
  189.     FLinkClipFmt: Word;
  190.     procedure Disconnect(DdeSrvrConv: TComponent);
  191.     function GetSrvrConv(const Topic: string ): TComponent;
  192.     function AllowConnect(hszApp: HSZ; hszTopic: HSZ): Boolean;
  193.     function AllowWildConnect(hszApp: HSZ; hszTopic: HSZ): HDdeData;
  194.     function Connect(Conv: HConv; hszTopic: HSZ; SameInst: Boolean): Boolean;
  195.     procedure PostDataChange(const Topic: string; Item: string);
  196.     procedure SetAppName(const Name: string);
  197.     procedure ResetAppName;
  198.     function  GetServerConv(const Topic: string): TDdeServerConv;
  199.     procedure InsertServerConv(SConv: TDdeServerConv);
  200.     procedure RemoveServerConv(SConv: TDdeServerConv);
  201. //    procedure DoError;
  202.     function  GetForm(const Topic: string): TForm;
  203.   public
  204.     constructor Create(AOwner: TComponent); override;
  205.     destructor Destroy; override;
  206.     function GetExeName: string;     // obsolete
  207.     property DdeInstId: LongInt read FDdeInstId write FDdeInstId;
  208.     property AppName: string read FAppName write SetAppName;
  209.     property LinkClipFmt: Word read FLinkClipFmt;
  210.   end;
  211.  
  212.   function GetPasteLinkInfo(var Service: string; var Topic: string;
  213.     var Item: string): Boolean;
  214. var
  215.   ddeMgr: TDdeMgr;
  216.  
  217. implementation
  218.  
  219. uses SysUtils, Dialogs, Consts, Clipbrd;
  220.  
  221. type
  222.   EDdeError = class(Exception);
  223.   TDdeSrvrConv = class;
  224.  
  225. { TDdeSrvrItem }
  226.  
  227.   TDdeSrvrItem = class(TComponent)
  228.   private
  229.     FConv: TDdeSrvrConv;
  230.     FItem: string;
  231.     FHszItem: HSZ;
  232.     FSrvr: TDdeServerItem;
  233.   protected
  234.     procedure SetItem(const Value: string);
  235.   public
  236.     constructor Create(AOwner: TComponent); override;
  237.     destructor Destroy; override;
  238.     function RequestData(Fmt: Word): HDdeData;
  239.     procedure PostDataChange;
  240.     property Conv: TDdeSrvrConv read FConv write FConv;
  241.     property Item: string read FItem write SetItem;
  242.     property Srvr: TDdeServerItem read FSrvr write FSrvr;
  243.     property HszItem: HSZ read FHszItem;
  244.   end;
  245.  
  246. { TDdeSrvrConv }
  247.  
  248.   TDdeSrvrConv = class(TComponent)
  249.   private
  250.     FTopic: string;
  251.     FHszTopic: HSZ;
  252.     FForm: TForm;
  253.     FSConv: TDdeServerConv;
  254.     FConv: HConv;
  255. //    FCnvInfo: TConvInfo;
  256. //    FDdeFmt: Integer;
  257.     FItems: TList;
  258.   protected
  259.     function GetControl(WinCtrl: TWinControl; DdeConv: TDdeServerConv; const ItemName: string): TDdeServerItem;
  260.     function GetSrvrItem(hszItem: HSZ): TDdeSrvrItem;
  261.   public
  262.     constructor Create(AOwner: TComponent); override;
  263.     destructor Destroy; override;
  264.     function RequestData(Conv: HConv; hszTopic: HSZ; hszItem: HSZ;
  265.       Fmt: Word): HDdeData;
  266.     function AdvStart(Conv: HConv; hszTopic: HSZ; hszItem: HSZ;
  267.       Fmt: Word): Boolean;
  268.     procedure AdvStop(Conv: HConv; hszTopic: HSZ; hszItem: HSZ);
  269.     function PokeData(Conv: HConv; hszTopic: HSZ; hszItem: HSZ; Data: HDdeData;
  270.       Fmt: Integer): LongInt;
  271.     function ExecuteMacro(Conv: HConv; hszTopic: HSZ; Data: HDdeData): Integer;
  272.     function GetItem(const ItemName: string): TDdeSrvrItem;
  273.     property Conv: HConv read FConv;
  274.     property Form: TForm read FForm;
  275.     property SConv: TDdeServerConv read FSConv;
  276.     property Topic: string read FTopic write FTopic;
  277.     property HszTopic: HSZ read FHszTopic;
  278.   end;
  279.  
  280. { TDdeCliItem }
  281.  
  282.   TDdeCliItem = class(TPersistent)
  283.   protected
  284.     FItem: string;
  285.     FHszItem: HSZ;
  286.     FCliConv: TDdeClientConv;
  287.     FCtrl: TDdeClientItem;
  288.     function StartAdvise: Boolean;
  289.     function StopAdvise: Boolean;
  290.     procedure StoreData(DdeDat: HDDEData);
  291.     procedure DataChange;
  292.     function AccessData(DdeDat: HDDEData; pDataLen: PDWORD): Pointer;
  293.     procedure ReleaseData(DdeDat: HDDEData);
  294.   public
  295.     constructor Create(ADS: TDdeClientConv);
  296.     destructor Destroy; override;
  297.     function RefreshData: Boolean;
  298.     function SetItem(const S: string): Boolean;
  299.     procedure SrvrDisconnect;
  300.     property HszItem: HSZ read FHszItem;
  301.     property Control: TDdeClientItem read FCtrl write FCtrl;
  302.   published
  303.     property Item: string read FItem;
  304.   end;
  305.  
  306. procedure DDECheck(Success: Boolean);
  307. var
  308.   err: Integer;
  309.   ErrStr: string;
  310. begin
  311.   if Success then Exit;
  312.   err := DdeGetLastError(DDEMgr.DdeInstId);
  313.   case err of
  314.     DMLERR_LOW_MEMORY, DMLERR_MEMORY_ERROR:
  315.       ErrStr := Format(SDdeMemErr, [err]);
  316.     DMLERR_NO_CONV_ESTABLISHED:
  317.       ErrStr := Format(SDdeConvErr, [err]);
  318.   else
  319.     ErrStr := Format(SDdeErr, [err]);
  320.   end;
  321.   raise EDdeError.Create(ErrStr);
  322. end;
  323.  
  324. function DdeMgrCallBack(CallType, Fmt : UINT; Conv: HConv; hsz1, hsz2: HSZ;
  325.   Data: HDDEData; Data1, Data2: DWORD): HDDEData; stdcall;
  326. var
  327.   ci: TConvInfo;
  328.   ddeCli: TComponent;
  329.   ddeSrv: TDdeSrvrConv;
  330.   ddeObj: TComponent;
  331.   xID: DWORD;
  332. begin
  333.   Result := 0;
  334.   case CallType of
  335.     XTYP_CONNECT:
  336.       Result := HDdeData(ddeMgr.AllowConnect(hsz2, hsz1));
  337.     XTYP_WILDCONNECT:
  338.       Result := ddeMgr.AllowWildConnect(hsz2, hsz1);
  339.     XTYP_CONNECT_CONFIRM:
  340.       ddeMgr.Connect(Conv, hsz1, Boolean(Data2));
  341.   end;
  342.   if Conv <> 0 then
  343.   begin
  344.     ci.cb := sizeof(TConvInfo);
  345.     if CallType = XTYP_XACT_COMPLETE then
  346.       xID := Data1
  347.     else
  348.       xID := QID_SYNC;
  349.     if DdeQueryConvInfo(Conv, xID, @ci) = 0 then Exit;
  350.     case CallType of
  351.       XTYP_ADVREQ:
  352.         begin
  353.           ddeSrv := TDdeSrvrConv(ci.hUser);
  354.           Result := ddeSrv.RequestData(Conv, hsz1, hsz2, Fmt);
  355.         end;
  356.       XTYP_REQUEST:
  357.         begin
  358.           ddeSrv := TDdeSrvrConv(ci.hUser);
  359.           Result := ddeSrv.RequestData(Conv, hsz1, hsz2, Fmt);
  360.         end;
  361.       XTYP_ADVSTOP:
  362.         begin
  363.           ddeSrv := TDdeSrvrConv(ci.hUser);
  364.           ddeSrv.AdvStop(Conv, hsz1, hsz2);
  365.         end;
  366.       XTYP_ADVSTART:
  367.         begin
  368.           ddeSrv := TDdeSrvrConv(ci.hUser);
  369.           Result := HDdeData(ddeSrv.AdvStart(Conv, hsz1, hsz2, Fmt));
  370.         end;
  371.       XTYP_POKE:
  372.         begin
  373.           ddeSrv := TDdeSrvrConv(ci.hUser);
  374.           Result := HDdeData(ddeSrv.PokeData(Conv, hsz1, hsz2, Data, Fmt));
  375.         end;
  376.       XTYP_EXECUTE:
  377.         begin
  378.           ddeSrv := TDdeSrvrConv(ci.hUser);
  379.           Result := HDdeData(ddeSrv.ExecuteMacro(Conv, hsz1, Data));
  380.         end;
  381.       XTYP_XACT_COMPLETE:
  382.         begin
  383.           ddeCli := TComponent(ci.hUser);
  384.           if ddeCli <> nil then TDdeClientConv(ddeCli).XactComplete
  385.         end;
  386.       XTYP_ADVDATA:
  387.         begin
  388.           ddeCli := TComponent(ci.hUser);
  389.           TDdeClientConv(ddeCli).DataChange(Data, hsz2);
  390.         end;
  391.       XTYP_DISCONNECT:
  392.         begin
  393.           ddeObj := TComponent(ci.hUser);
  394.           if ddeObj <> nil then
  395.           begin
  396.             if ddeObj is TDdeClientConv then
  397.               TDdeClientConv(ddeObj).SrvrDisconnect
  398.             else
  399.               ddeMgr.Disconnect(ddeObj);
  400.           end;
  401.         end;
  402.     end;
  403.   end;
  404. end;
  405.  
  406. function GetPasteLinkInfo(var Service, Topic, Item: string): Boolean;
  407. var
  408.   hData: THandle;
  409.   pData: Pointer;
  410.   P: PChar;
  411. begin
  412.   Result := False;
  413.   Clipboard.Open;
  414.   hData := Clipboard.GetAsHandle(ddeMgr.LinkClipFmt);
  415.   if hData <> 0 then
  416.   begin
  417.     pData := GlobalLock(hData);
  418.     try
  419.       P := PChar(pData);
  420.       Service := PChar(pData);
  421.       P := P + Length(Service) + 1;
  422.       Topic := P;
  423.       P := P + Length(Topic) + 1;
  424.       Item := P;
  425.     finally
  426.       GlobalUnlock(hData);
  427.     end;
  428.     Result := True;
  429.   end;
  430.   Clipboard.Close;
  431. end;
  432.  
  433.  
  434. { TDdeMgr }
  435.  
  436. constructor TDdeMgr.Create(AOwner: TComponent);
  437. begin
  438.   inherited Create(AOwner);
  439.   FLinkClipFmt := RegisterClipboardFormat('Link');
  440.   FDdeInstId := 0;
  441.   DDECheck(DdeInitialize(FDdeInstId, DdeMgrCallBack, APPCLASS_STANDARD, 0) = 0);
  442.   FConvs := TList.Create;
  443.   FCliConvs := TList.Create;
  444.   FConvCtrls := TList.Create;
  445.   AppName := ParamStr(0);
  446. end;
  447.  
  448. destructor TDdeMgr.Destroy;
  449. var
  450.   I: Integer;
  451. begin
  452.   if FConvs <> nil then
  453.   begin
  454.     for I := 0 to FConvs.Count - 1 do
  455.       TDdeSrvrConv(FConvs[I]).Free;
  456.     FConvs.Free;
  457.     FConvs := nil;
  458.   end;
  459.   if FCliConvs <> nil then
  460.   begin
  461.     for I := 0 to FCliConvs.Count - 1 do
  462.       TDdeSrvrConv(FCliConvs[I]).Free;
  463.     FCliConvs.Free;
  464.     FCliConvs := nil;
  465.   end;
  466.   if FConvCtrls <> nil then
  467.   begin
  468.     FConvCtrls.Free;
  469.     FConvCtrls := nil;
  470.   end;
  471.   ResetAppName;
  472.   DdeUnInitialize(FDdeInstId);
  473.   inherited Destroy;
  474. end;
  475.  
  476. function TDdeMgr.AllowConnect(hszApp: HSZ; hszTopic: HSZ): Boolean;
  477. var
  478.   Topic: string;
  479.   Buffer: array[0..4095] of Char;
  480.   Form: TForm;
  481.   SConv: TDdeServerConv;
  482. begin
  483.   Result := False;
  484.   if (hszApp = 0) or (DdeCmpStringHandles(hszApp, FHszApp) = 0)  then
  485.   begin
  486.     SetString(Topic, Buffer, DdeQueryString(FDdeInstId, hszTopic, Buffer,
  487.       SizeOf(Buffer), CP_WINANSI));
  488.     SConv := GetServerConv(Topic);
  489.     if SConv <> nil then
  490.       Result := True
  491.     else begin
  492.       Form := GetForm(Topic);
  493.       if Form <> nil then Result := True;
  494.     end;
  495.   end;
  496. end;
  497.  
  498. function TDdeMgr.AllowWildConnect(hszApp: HSZ; hszTopic: HSZ): HDdeData;
  499. var
  500.   conns: packed array[0..1] of THSZPair;
  501. begin
  502.   Result := 0;
  503.   if hszTopic = 0 then Exit;
  504.   if AllowConnect(hszApp, hszTopic) = True then
  505.   begin
  506.     conns[0].hszSvc := FHszApp;
  507.     conns[0].hszTopic := hszTopic;
  508.     conns[1].hszSvc := 0;
  509.     conns[1].hszTopic := 0;
  510.     Result := DdeCreateDataHandle(ddeMgr.DdeInstId, @conns,
  511.       2 * sizeof(THSZPair), 0, 0, CF_TEXT, 0);
  512.   end;
  513. end;
  514.  
  515. function TDdeMgr.Connect(Conv: HConv; hszTopic: HSZ; SameInst: Boolean): Boolean;
  516. var
  517.   Topic: string;
  518.   Buffer: array[0..4095] of Char;
  519.   DdeConv: TDdeSrvrConv;
  520. begin
  521.   DdeConv := TDdeSrvrConv.Create(Self);
  522.   SetString(Topic, Buffer, DdeQueryString(FDdeInstId, hszTopic, Buffer,
  523.     SizeOf(Buffer), CP_WINANSI));
  524.   DdeConv.Topic := Topic;
  525.   DdeConv.FSConv := GetServerConv(Topic);
  526.   if DdeConv.FSConv = nil then
  527.     DdeConv.FForm := GetForm(Topic);
  528.   DdeConv.FConv := Conv;
  529.   DdeSetUserHandle(Conv, QID_SYNC, DWORD(DdeConv));
  530.   FConvs.Add(DdeConv);
  531.   if DdeConv.FSConv <> nil then DdeConv.FSConv.Connect;
  532.   Result := True;
  533. end;
  534.  
  535. procedure TDdeMgr.Disconnect(DdeSrvrConv: TComponent);
  536. var
  537.   DdeConv: TDdeSrvrConv;
  538. begin
  539.   DdeConv := TDdeSrvrConv(DdeSrvrConv);
  540.   if DdeConv.FSConv <> nil then DdeConv.FSConv.Disconnect;
  541.   if DdeConv.FConv <> 0 then DdeSetUserHandle(DdeConv.FConv, QID_SYNC, 0);
  542.   DdeConv.FConv := 0;
  543.   if FConvs <> nil then
  544.   begin
  545.     FConvs.Remove(DdeConv);
  546.     DdeConv.Free;
  547.   end;
  548. end;
  549.  
  550. function TDdeMgr.GetExeName: string;
  551. begin
  552.   Result := ParamStr(0);
  553. end;
  554.  
  555. procedure TDdeMgr.SetAppName(const Name: string);
  556. var
  557.   Dot: Integer;
  558. begin
  559.   ResetAppName;
  560.   FAppName := ExtractFileName(Name);
  561.   Dot := Pos('.', FAppName);
  562.   if Dot <> 0 then
  563.     Delete(FAppName, Dot, Length(FAppName));
  564.   FHszApp := DdeCreateStringHandle(FDdeInstId, PChar(FAppName), CP_WINANSI);
  565.   DdeNameService(FDdeInstId, FHszApp, 0, DNS_REGISTER);
  566. end;
  567.  
  568. procedure TDdeMgr.ResetAppName;
  569. begin
  570.   if FHszApp <> 0 then
  571.   begin
  572.     DdeNameService(FDdeInstId, FHszApp, 0, DNS_UNREGISTER);
  573.     DdeFreeStringHandle(FDdeInstId, FHszApp);
  574.   end;
  575.   FHszApp := 0;
  576. end;
  577.  
  578. function TDdeMgr.GetServerConv(const Topic: string): TDdeServerConv;
  579. var
  580.   I: Integer;
  581.   SConv: TDdeServerConv;
  582. begin
  583.   Result := nil;
  584.   for I := 0 to FConvCtrls.Count - 1 do
  585.   begin
  586.     SConv := TDdeServerConv(FConvCtrls[I]);
  587.     if AnsiCompareText(SConv.Name, Topic) = 0 then
  588.     begin
  589.       Result := SConv;
  590.       Exit;
  591.     end;
  592.   end;
  593. end;
  594.  
  595. function TDdeMgr.GetForm(const Topic: string): TForm;
  596. var
  597.   I: Integer;
  598.   Form: TForm;
  599. begin
  600.   Result := nil;
  601.   for I := 0 to Screen.FormCount - 1 do
  602.   begin
  603.     Form := TForm(Screen.Forms[I]);
  604.     if AnsiCompareText(Form.Caption, Topic) = 0 then
  605.     begin
  606.       Result := Form;
  607.       Exit;
  608.     end;
  609.   end;
  610. end;
  611.  
  612. function TDdeMgr.GetSrvrConv(const Topic: string ): TComponent;
  613. var
  614.   I: Integer;
  615.   Conv: TDdeSrvrConv;
  616. begin
  617.   Result := nil;
  618.   for I := 0 to FConvs.Count - 1 do
  619.   begin
  620.     Conv := FConvs[I];
  621.     if AnsiCompareText(Conv.Topic, Topic) = 0 then
  622.     begin
  623.       Result := Conv;
  624.       Exit;
  625.     end;
  626.   end;
  627. end;
  628.  
  629. procedure TDdeMgr.PostDataChange(const Topic: string; Item: string);
  630. var
  631.   Conv: TDdeSrvrConv;
  632.   Itm: TDdeSrvrItem;
  633. begin
  634.   Conv := TDdeSrvrConv(GetSrvrConv (Topic));
  635.   If Conv <> nil then
  636.   begin
  637.     Itm := Conv.GetItem(Item);
  638.     if Itm <> nil then Itm.PostDataChange;
  639.   end;
  640. end;
  641.  
  642. procedure TDdeMgr.InsertServerConv(SConv: TDdeServerConv);
  643. begin
  644.   FConvCtrls.Insert(FConvCtrls.Count, SConv);
  645. end;
  646.  
  647. procedure TDdeMgr.RemoveServerConv(SConv: TDdeServerConv);
  648. begin
  649.   FConvCtrls.Remove(SConv);
  650. end;
  651.  
  652. {procedure TDdeMgr.DoError;
  653. begin
  654.   DDECheck(False);
  655. end;}
  656.  
  657. constructor TDdeClientConv.Create(AOwner: TComponent);
  658. begin
  659.   inherited Create(AOwner);
  660.   FItems := TList.Create;
  661. end;
  662.  
  663. destructor TDdeClientConv.Destroy;
  664. begin
  665.   CloseLink;
  666.   inherited Destroy;
  667.   FItems.Free;
  668.   FItems := nil;
  669. end;
  670.  
  671. procedure TDdeClientConv.DefineProperties(Filer: TFiler);
  672. begin
  673.   inherited DefineProperties(Filer);
  674.   Filer.DefineProperty('LinkInfo', ReadLinkInfo, WriteLinkInfo,
  675.     not ((DdeService = '') and (DdeTopic = '')));
  676. end;
  677.  
  678. procedure TDdeClientConv.Loaded;
  679. var
  680.   Service, Topic: string;
  681. begin
  682.   inherited Loaded;
  683.   Service := DdeService;
  684.   Topic := DdeTopic;
  685.   if (Length(Service) <> 0) and (ConnectMode <> ddeManual) then
  686.     ChangeLink(Service, Topic, '');
  687. end;
  688.  
  689. procedure TDdeClientConv.ReadLinkInfo (Reader: TReader);
  690. var
  691.   Value: string;
  692.   Text: string;
  693.   Temp: Integer;
  694. begin
  695.   Reader.ReadListBegin;
  696.   while not Reader.EndOfList do
  697.   begin
  698.     Value := Reader.ReadString;
  699.     Temp := Pos(' ', Value);
  700.     Text := Copy(Value, Temp + 1, Length (Value) - Temp);
  701.     case Value[1] of
  702.       'S': SetService(Text);
  703.       'T': SetTopic(Text);
  704.     end;
  705.   end;
  706.   Reader.ReadListEnd;
  707. end;
  708.  
  709. procedure TDdeClientConv.WriteLinkInfo (Writer: TWriter);
  710. var
  711.   Value: string;
  712. begin
  713.   Writer.WriteListBegin;
  714.   Value := DdeService;
  715.   Writer.WriteString(Format('Service %s', [Value]));
  716.   Value := DdeTopic;
  717.   Writer.WriteString(Format('Topic %s', [Value]));
  718.   Writer.WriteListEnd;
  719. end;
  720.  
  721. procedure TDdeClientConv.OnAttach(aCtrl: TDdeClientItem);
  722. var
  723.   ItemLnk: TDdeCliItem;
  724. begin
  725.   ItemLnk := TDdeCliItem.Create(Self);
  726.   FItems.Insert(FItems.Count, ItemLnk);
  727.   ItemLnk.Control := aCtrl;
  728.   ItemLnk.SetItem('');
  729. end;
  730.  
  731. procedure TDdeClientConv.OnDetach(aCtrl: TDdeClientItem);
  732. var
  733.   ItemLnk: TDdeCliItem;
  734. begin
  735.   ItemLnk := TDdeCliItem(GetCliItemByCtrl(aCtrl));
  736.   if ItemLnk <> nil then
  737.   begin
  738.     ItemLnk.SetItem('');
  739.     FItems.Remove(ItemLnk);
  740.     ItemLnk.Free;
  741.   end;
  742. end;
  743.  
  744. function TDdeClientConv.OnSetItem(aCtrl: TDdeClientItem; const S: string): Boolean;
  745. var
  746.   ItemLnk: TDdeCliItem;
  747. begin
  748.   Result := True;
  749.   ItemLnk := TDdeCliItem(GetCliItemByCtrl(aCtrl));
  750.  
  751.   if (ItemLnk = nil) and (Length(S) > 0) then
  752.   begin
  753.     OnAttach (aCtrl);
  754.     ItemLnk := TDdeCliItem(GetCliItemByCtrl(aCtrl));
  755.   end;
  756.  
  757.   if (ItemLnk <> nil) and (Length(S) = 0) then
  758.   begin
  759.     OnDetach (aCtrl);
  760.   end
  761.   else if ItemLnk <> nil then
  762.   begin
  763.     Result := ItemLnk.SetItem(S);
  764.     if Not (Result) and Not (csLoading in ComponentState) then
  765.       OnDetach (aCtrl);  {error occurred, do cleanup}
  766.   end;
  767. end;
  768.  
  769. function TDdeClientConv.GetCliItemByCtrl(ACtrl: TDdeClientItem): TPersistent;
  770. var
  771.   ItemLnk: TDdeCliItem;
  772.   I: word;
  773. begin
  774.   Result := nil;
  775.   I := 0;
  776.   while I < FItems.Count do
  777.   begin
  778.     ItemLnk := FItems[I];
  779.     if ItemLnk.Control = aCtrl then
  780.     begin
  781.       Result := ItemLnk;
  782.       Exit;
  783.     end;
  784.     Inc(I);
  785.   end;
  786. end;
  787.  
  788. function TDdeClientConv.PasteLink: Boolean;
  789. var
  790.   Service, Topic, Item: string;
  791. begin
  792.   if GetPasteLinkInfo(Service, Topic, Item) = True then
  793.     Result := ChangeLink(Service, Topic, Item) else
  794.     Result := False;
  795. end;
  796.  
  797. function TDdeClientConv.ChangeLink(const App, Topic, Item: string): Boolean;
  798. begin
  799.   CloseLink;
  800.   SetService(App);
  801.   SetTopic(Topic);
  802.   Result := OpenLink;
  803.   if Not Result then
  804.   begin
  805.     SetService('');
  806.     SetTopic('');
  807.   end;
  808. end;
  809.  
  810. function TDdeClientConv.OpenLink: Boolean;
  811. var
  812.   CharVal: array[0..255] of Char;
  813.   Res: Boolean;
  814. begin
  815.   Result := False;
  816.   if FConv <> 0 then Exit;
  817.  
  818.   if (Length(DdeService) = 0) and (Length(DdeTopic) = 0) then
  819.   begin
  820.     ClearItems;
  821.     Exit;
  822.   end;
  823.  
  824.   if FHszApp = 0 then
  825.   begin
  826.     StrPCopy(CharVal, DdeService);
  827.     FHszApp := DdeCreateStringHandle(ddeMgr.DdeInstId, CharVal, CP_WINANSI);
  828.   end;
  829.   if FHszTopic = 0 then
  830.   begin
  831.     StrPCopy(CharVal, DdeTopic);
  832.     FHszTopic := DdeCreateStringHandle(ddeMgr.DdeInstId, CharVal, CP_WINANSI);
  833.   end;
  834.   Res := CreateDdeConv(FHszApp, FHszTopic);
  835.   if Not Res then
  836.   begin
  837.     if Not((Length(DdeService) = 0) and
  838.       (Length(ServiceApplication) = 0)) then
  839.     begin
  840.       if Length(ServiceApplication) <> 0 then
  841.         StrPCopy(CharVal, ServiceApplication)
  842.       else
  843.         StrPCopy(CharVal, DdeService + ' ' + DdeTopic);
  844.       if WinExec(CharVal, SW_SHOWMINNOACTIVE) >= 32 then
  845.         Res := CreateDdeConv(FHszApp, FHszTopic);
  846.     end;
  847.   end;
  848.   if Not Res then
  849.   begin
  850.     ClearItems;
  851.     Exit;
  852.   end;
  853.   if FCnvInfo.wFmt <> 0 then FDdeFmt := FCnvInfo.wFmt
  854.   else FDdeFmt := CF_TEXT;
  855.   if StartAdvise = False then Exit;
  856.   Open;
  857.   DataChange(0, 0);
  858.   Result := True;
  859. end;
  860.  
  861. procedure TDdeClientConv.CloseLink;
  862. var
  863.   OldConv: HConv;
  864. begin
  865.   if FConv <> 0 then
  866.   begin
  867.     OldConv := FConv;
  868.     SrvrDisconnect;
  869.     FConv := 0;
  870.     DdeSetUserHandle(OldConv, QID_SYNC, 0);
  871.     DdeDisconnect(OldConv);
  872.   end;
  873.  
  874.   if FHszApp <> 0 then
  875.   begin
  876.     DdeFreeStringHandle(ddeMgr.DdeInstId, FHszApp);
  877.     FHszApp := 0;
  878.   end;
  879.  
  880.   if FHszTopic <> 0 then
  881.   begin
  882.     DdeFreeStringHandle(ddeMgr.DdeInstId, FHszTopic);
  883.     FHszTopic := 0;
  884.   end;
  885.   SetService('');
  886.   SetTopic('');
  887. end;
  888.  
  889. procedure TDdeClientConv.ClearItems;
  890. var
  891.   ItemLnk: TDdeCliItem;
  892.   i: word;
  893. begin
  894.   if FItems.Count = 0 then Exit;
  895.  
  896.   for I := 0 to FItems.Count - 1 do
  897.   begin
  898.     ItemLnk := TDdeCliItem(FItems [0]);
  899.     ItemLnk.Control.DdeItem := EmptyStr;
  900.   end;
  901. end;
  902.  
  903. function TDdeClientConv.CreateDdeConv(FHszApp: HSZ; FHszTopic: HSZ): Boolean;
  904. var
  905.   Context: TConvContext;
  906. begin
  907.   FillChar(Context, SizeOf(Context), 0);
  908.   with Context do
  909.   begin
  910.     cb := SizeOf(TConvConText);
  911.     iCodePage := CP_WINANSI;
  912.   end;
  913.   FConv := DdeConnect(ddeMgr.DdeInstId, FHszApp, FHszTopic, @Context);
  914.   Result := FConv <> 0;
  915.   if Result then
  916.   begin
  917.     FCnvInfo.cb := sizeof(TConvInfo);
  918.     DdeQueryConvInfo(FConv, QID_SYNC, @FCnvInfo);
  919.     DdeSetUserHandle(FConv, QID_SYNC, LongInt(Self));
  920.   end;
  921. end;
  922.  
  923. function TDdeClientConv.StartAdvise: Boolean;
  924. var
  925.   ItemLnk: TDdeCliItem;
  926.   i: word;
  927. begin
  928.   Result := False;
  929.   if FConv = 0 then Exit;
  930.  
  931.   i := 0;
  932.   while i < FItems.Count do
  933.   begin
  934.     ItemLnk := TDdeCliItem(FItems [i]);
  935.     if Not ItemLnk.StartAdvise then
  936.     begin
  937.       ItemLnk.Control.DdeItem := EmptyStr;
  938.     end else
  939.       Inc(i);
  940.     if i >= FItems.Count then
  941.       break;
  942.   end;
  943.   Result := True;
  944. end;
  945.  
  946. function TDdeClientConv.ExecuteMacroLines(Cmd: TStrings; waitFlg: Boolean): Boolean;
  947. begin
  948.   Result := False;
  949.   if (FConv = 0) or FWaitStat then Exit;
  950.   Result := ExecuteMacro(PChar(Cmd.Text), waitFlg);
  951. end;
  952.  
  953. function TDdeClientConv.ExecuteMacro(Cmd: PChar; waitFlg: Boolean): Boolean;
  954. var
  955.   hszCmd: HDDEData;
  956.   hdata: HDDEData;
  957.   ddeRslt: LongInt;
  958. begin
  959.   Result := False;
  960.   if (FConv = 0) or FWaitStat then Exit;
  961.   hszCmd := DdeCreateDataHandle(ddeMgr.DdeInstId, Cmd, StrLen(Cmd) + 1,
  962.     0, 0, FDdeFmt, 0);
  963.   if hszCmd = 0 then Exit;
  964.   if waitFlg = True then FWaitStat := True;
  965.   hdata := DdeClientTransaction(Pointer(hszCmd), DWORD(-1), FConv, 0, FDdeFmt,
  966.      XTYP_EXECUTE, TIMEOUT_ASYNC, @ddeRslt);
  967.   if hdata = 0 then FWaitStat := False
  968.   else Result := True;
  969. end;
  970.  
  971. function TDdeClientConv.PokeDataLines(const Item: string; Data: TStrings): Boolean;
  972. begin
  973.   Result := False;
  974.   if (FConv = 0) or FWaitStat then Exit;
  975.   Result := PokeData(Item, PChar(Data.Text));
  976. end;
  977.  
  978. function TDdeClientConv.PokeData(const Item: string; Data: PChar): Boolean;
  979. var
  980.   hszDat: HDDEData;
  981.   hdata: HDDEData;
  982.   hszItem: HSZ;
  983. begin
  984.   Result := False;
  985.   if (FConv = 0) or FWaitStat then Exit;
  986.   hszItem := DdeCreateStringHandle(ddeMgr.DdeInstId, PChar(Item), CP_WINANSI);
  987.   if hszItem = 0 then Exit;
  988.   hszDat := DdeCreateDataHandle (ddeMgr.DdeInstId, Data, StrLen(Data) + 1,
  989.     0, hszItem, FDdeFmt, 0);
  990.   if hszDat <> 0 then
  991.   begin
  992.     hdata := DdeClientTransaction(Pointer(hszDat), DWORD(-1), FConv, hszItem,
  993.       FDdeFmt, XTYP_POKE, TIMEOUT_ASYNC, nil);
  994.     Result := hdata <> 0;
  995.   end;
  996.   DdeFreeStringHandle (ddeMgr.DdeInstId, hszItem);
  997. end;
  998.  
  999. function TDdeClientConv.RequestData(const Item: string): PChar;
  1000. var
  1001.   hData: HDDEData;
  1002.   ddeRslt: LongInt;
  1003.   hItem: HSZ;
  1004.   pData: Pointer;
  1005.   Len: Integer;
  1006. begin
  1007.   Result := nil;
  1008.   if (FConv = 0) or FWaitStat then Exit;
  1009.   hItem := DdeCreateStringHandle(ddeMgr.DdeInstId, PChar(Item), CP_WINANSI);
  1010.   if hItem <> 0 then
  1011.   begin
  1012.     hData := DdeClientTransaction(nil, 0, FConv, hItem, FDdeFmt,
  1013.       XTYP_REQUEST, 10000, @ddeRslt);
  1014.     DdeFreeStringHandle(ddeMgr.DdeInstId, hItem);
  1015.     if hData <> 0 then
  1016.     try
  1017.       pData := DdeAccessData(hData, @Len);
  1018.       if pData <> nil then
  1019.       try
  1020.         Result := StrAlloc(Len + 1);
  1021.         Move(pData^, Result^, len);    // data is binary, may contain nulls
  1022.         Result[len] := #0;
  1023.       finally
  1024.         DdeUnaccessData(hData);
  1025.       end;
  1026.     finally
  1027.       DdeFreeDataHandle(hData);
  1028.     end;
  1029.   end;
  1030. end;
  1031.  
  1032. function TDdeClientConv.GetCliItemByName(const ItemName: string): TPersistent;
  1033. var
  1034.   ItemLnk: TDdeCliItem;
  1035.   i: word;
  1036. begin
  1037.   Result := nil;
  1038.   i := 0;
  1039.   while i < FItems.Count do
  1040.   begin
  1041.     ItemLnk := TDdeCliItem(FItems[i]);
  1042.     if ItemLnk.Item = ItemName then
  1043.     begin
  1044.       Result := ItemLnk;
  1045.       Exit;
  1046.     end;
  1047.     Inc(i);
  1048.   end;
  1049. end;
  1050.  
  1051. procedure TDdeClientConv.XactComplete;
  1052. begin
  1053.    FWaitStat := False;
  1054. end;
  1055.  
  1056. procedure TDdeClientConv.SrvrDisconnect;
  1057. var
  1058.   ItemLnk: TDdeCliItem;
  1059.   i: word;
  1060. begin
  1061.   if FConv <> 0 then Close;
  1062.   FConv := 0;
  1063.   i := 0;
  1064.   while i < FItems.Count do
  1065.   begin
  1066.     ItemLnk := TDdeCliItem(FItems [i]);
  1067.     ItemLnk.SrvrDisconnect;
  1068.     inc(i);
  1069.   end;
  1070. end;
  1071.  
  1072. procedure TDdeClientConv.DataChange(DdeDat: HDDEData; hszIt: HSZ);
  1073. var
  1074.   ItemLnk: TDdeCliItem;
  1075.   i: word;
  1076. begin
  1077.   i := 0;
  1078.   while i < FItems.Count do
  1079.   begin
  1080.     ItemLnk := TDdeCliItem(FItems [i]);
  1081.     if (hszIt = 0) or (ItemLnk.HszItem = hszIt) then
  1082.     begin
  1083.         { data has changed and we found a link that might be interested }
  1084.       ItemLnk.StoreData(DdeDat);
  1085.     end;
  1086.     Inc(i);
  1087.   end;
  1088. end;
  1089.  
  1090. function TDdeClientConv.SetLink(const Service, Topic: string): Boolean;
  1091. begin
  1092.   CloseLink;
  1093.   if FConnectMode = ddeAutomatic then
  1094.     Result := ChangeLink(Service, Topic, '')
  1095.   else begin
  1096.     SetService(Service);
  1097.     SetTopic(Topic);
  1098.     DataChange(0,0);
  1099.     Result := True;
  1100.   end;
  1101. end;
  1102.  
  1103. procedure TDdeClientConv.SetConnectMode(NewMode: TDataMode);
  1104. begin
  1105.   if FConnectMode <> NewMode then
  1106.   begin
  1107.     if (NewMode = ddeAutomatic) and (Length(DdeService) <> 0) and
  1108.       (Length(DdeTopic) <> 0) and not OpenLink then
  1109.       raise Exception.CreateRes(@SDdeNoConnect);
  1110.     FConnectMode := NewMode;
  1111.   end;
  1112. end;
  1113.  
  1114. procedure TDdeClientConv.SetFormatChars(NewFmt: Boolean);
  1115. begin
  1116.   if FFormatChars <> NewFmt then
  1117.   begin
  1118.     FFormatChars := NewFmt;
  1119.     if FConv <> 0 then DataChange(0, 0);
  1120.   end;
  1121. end;
  1122.  
  1123. procedure TDdeClientConv.SetDdeService(const Value: string);
  1124. begin
  1125. end;
  1126.  
  1127. procedure TDdeClientConv.SetDdeTopic(const Value: string);
  1128. begin
  1129. end;
  1130.  
  1131. procedure TDdeClientConv.SetService(const Value: string);
  1132. begin
  1133.   FDdeService := Value;
  1134. end;
  1135.  
  1136. procedure TDdeClientConv.SetTopic(const Value: string);
  1137. begin
  1138.   FDdeTopic := Value;
  1139. end;
  1140.  
  1141. procedure TDdeClientConv.Close;
  1142. begin
  1143.   if Assigned(FOnClose) then FOnClose(Self);
  1144. end;
  1145.  
  1146. procedure TDdeClientConv.Open;
  1147. begin
  1148.   if Assigned(FOnOpen) then FOnOpen(Self);
  1149. end;
  1150.  
  1151. procedure TDdeClientConv.Notification(AComponent: TComponent;
  1152.   Operation: TOperation);
  1153. var
  1154.   ItemLnk: TDdeCliItem;
  1155.   i: word;
  1156. begin
  1157.   inherited Notification(AComponent, Operation);
  1158.   if (Operation = opRemove) and (FItems <> nil) then
  1159.   begin
  1160.     i := 0;
  1161.     while i < FItems.Count do
  1162.     begin
  1163.       ItemLnk := TDdeCliItem(FItems [i]);
  1164.       if (AComponent = ItemLnk.Control) then
  1165.         ItemLnk.Control.DdeItem := EmptyStr;
  1166.       if i >= FItems.Count then break;
  1167.       Inc(I);
  1168.     end;
  1169.   end;
  1170. end;
  1171.  
  1172. constructor TDdeClientItem.Create(AOwner: TComponent);
  1173. begin
  1174.   inherited Create(AOwner);
  1175.   FLines := TStringList.Create;
  1176. end;
  1177.  
  1178. destructor TDdeClientItem.Destroy;
  1179. begin
  1180.   FLines.Free;
  1181.   inherited Destroy;
  1182. end;
  1183.  
  1184. procedure TDdeClientItem.SetDdeClientConv(Val: TDdeClientConv);
  1185. var
  1186.   OldItem: string;
  1187. begin
  1188.   if Val <> FDdeClientConv then
  1189.   begin
  1190.     OldItem := DdeItem;
  1191.     FDdeClientItem := '';
  1192.     if FDdeClientConv <> nil then
  1193.       FDdeClientConv.OnDetach (Self);
  1194.  
  1195.     FDdeClientConv := Val;
  1196.     if FDdeClientConv <> nil then
  1197.     begin
  1198.       FDdeClientConv.FreeNotification(Self);
  1199.       if Length(OldItem) <> 0 then SetDdeClientItem (OldItem);
  1200.     end;
  1201.   end;
  1202. end;
  1203.  
  1204. procedure TDdeClientItem.SetDdeClientItem(const Val: string);
  1205. begin
  1206.   if FDdeClientConv <> nil then
  1207.   begin
  1208.     FDdeClientItem := Val;
  1209.     if Not FDdeClientConv.OnSetItem (Self, Val) then
  1210.     begin
  1211.       if Not (csLoading in ComponentState) or
  1212.         not ((FDdeClientConv.FConv = 0) and
  1213.         (FDdeClientConv.ConnectMode = ddeManual)) then
  1214.         FDdeClientItem := '';
  1215.     end;
  1216.   end
  1217.   else if (csLoading in ComponentState) then
  1218.     FDdeClientItem := Val;
  1219. end;
  1220.  
  1221. procedure TDdeClientItem.Notification(AComponent: TComponent;
  1222.   Operation: TOperation);
  1223. begin
  1224.   inherited Notification(AComponent, Operation);
  1225.   if (Operation = opRemove) and (AComponent = FDdeClientConv) then
  1226.   begin
  1227.     FDdeClientConv.OnDetach (Self);
  1228.     FDdeClientConv := nil;
  1229.     FDdeClientItem := '';
  1230.   end;
  1231. end;
  1232.  
  1233. procedure TDdeClientItem.OnAdvise;
  1234. begin
  1235.   if csDesigning in ComponentState then
  1236.   begin
  1237.     if Owner.InheritsFrom (TForm) and (TForm(Owner).Designer <> nil) then
  1238.       TForm(Owner).Designer.Modified;
  1239.   end;
  1240.   if Assigned(FOnChange) then FOnChange(Self);
  1241. end;
  1242.  
  1243. function TDdeClientItem.GetText: string;
  1244. begin
  1245.   if FLines.Count > 0 then
  1246.     Result := FLines.Strings[0]
  1247.   else Result := '';
  1248. end;
  1249.  
  1250. procedure TDdeClientItem.SetText(const S: string);
  1251. begin
  1252. end;
  1253.  
  1254. procedure TDdeClientItem.SetLines(L: TStrings);
  1255. begin
  1256. end;
  1257.  
  1258. constructor TDdeCliItem.Create(ADS: TDdeClientConv);
  1259. begin
  1260.   inherited Create;
  1261.   FHszItem := 0;
  1262.   FCliConv := ADS;
  1263. end;
  1264.  
  1265. destructor TDdeCliItem.Destroy;
  1266. begin
  1267.   StopAdvise;
  1268.   inherited Destroy;
  1269. end;
  1270.  
  1271. function TDdeCliItem.SetItem(const S: string): Boolean;
  1272. var
  1273.   OldItem: string;
  1274. begin
  1275.   Result := False;
  1276.   OldItem := Item;
  1277.   if FHszItem <> 0 then StopAdvise;
  1278.  
  1279.   FItem := S;
  1280.   FCtrl.Lines.Clear;
  1281.  
  1282.   if (Length(Item) <> 0) then
  1283.   begin
  1284.     if (FCliConv.Conv <> 0) then
  1285.     begin
  1286.       Result := StartAdvise;
  1287.       if Not Result then
  1288.         FItem := '';
  1289.     end
  1290.     else if FCliConv.ConnectMode = ddeManual then Result := True;
  1291.   end;
  1292.   RefreshData;
  1293. end;
  1294.  
  1295. procedure TDdeCliItem.StoreData(DdeDat: HDDEData);
  1296. var
  1297.   Len: Longint;
  1298.   Data: string;
  1299.   I: Integer;
  1300. begin
  1301.   if DdeDat = 0 then
  1302.   begin
  1303.     RefreshData;
  1304.     Exit;
  1305.   end;
  1306.  
  1307.   Data := PChar(AccessData(DdeDat, @Len));
  1308.   if Data <> '' then
  1309.   begin
  1310.     FCtrl.Lines.Text := Data;
  1311.     ReleaseData(DdeDat);
  1312.     if FCliConv.FormatChars = False then
  1313.     begin
  1314.       for I := 1 to Length(Data) do
  1315.         if (Data[I] > #0) and (Data[I] < ' ') then Data[I] := ' ';
  1316.       FCtrl.Lines.Text := Data;
  1317.     end;
  1318.   end;
  1319.   DataChange;
  1320. end;
  1321.  
  1322. function TDdeCliItem.RefreshData: Boolean;
  1323. var
  1324.   ddeRslt: LongInt;
  1325.   DdeDat: HDDEData;
  1326. begin
  1327.   Result := False;
  1328.   if (FCliConv.Conv <> 0) and (FHszItem <> 0) then
  1329.   begin
  1330.     if FCliConv.WaitStat = True then Exit;
  1331.     DdeDat := DdeClientTransaction(nil, DWORD(-1), FCliConv.Conv, FHszItem,
  1332.       FCliConv.DdeFmt, XTYP_REQUEST, 1000, @ddeRslt);
  1333.     if DdeDat = 0 then Exit
  1334.     else begin
  1335.       StoreData(DdeDat);
  1336.       DdeFreeDataHandle(DdeDat);
  1337.       Result := True;
  1338.       Exit;
  1339.     end;
  1340.   end;
  1341.   DataChange;
  1342. end;
  1343.  
  1344. function TDdeCliItem.AccessData(DdeDat: HDDEData; pDataLen: PDWORD): Pointer;
  1345. begin
  1346.   Result := DdeAccessData(DdeDat, pDataLen);
  1347. end;
  1348.  
  1349. procedure TDdeCliItem.ReleaseData(DdeDat: HDDEData);
  1350. begin
  1351.   DdeUnaccessData(DdeDat);
  1352. end;
  1353.  
  1354. function TDdeCliItem.StartAdvise: Boolean;
  1355. var
  1356.   ddeRslt: LongInt;
  1357.   hdata: HDDEData;
  1358. begin
  1359.   Result := False;
  1360.   if FCliConv.Conv = 0 then Exit;
  1361.   if Length(Item) = 0 then Exit;
  1362.   if FHszItem = 0 then
  1363.     FHszItem := DdeCreateStringHandle(ddeMgr.DdeInstId, PChar(Item), CP_WINANSI);
  1364.   hdata := DdeClientTransaction(nil, DWORD(-1), FCliConv.Conv, FHszItem,
  1365.     FCliConv.DdeFmt, XTYP_ADVSTART or XTYPF_NODATA, 1000, @ddeRslt);
  1366.   if hdata = 0 then
  1367.   begin
  1368.     DdeGetLastError(ddeMgr.DdeInstId);
  1369.     DdeFreeStringHandle(ddeMgr.DdeInstId, FHszItem);
  1370.     FHszItem := 0;
  1371.     FCtrl.Lines.Clear;
  1372.   end else
  1373.     Result := True;
  1374. end;
  1375.  
  1376. function TDdeCliItem.StopAdvise: Boolean;
  1377. var
  1378.   ddeRslt: LongInt;
  1379. begin
  1380.   if FCliConv.Conv <> 0 then
  1381.     if FHszItem <> 0 then
  1382.       DdeClientTransaction(nil, DWORD(-1), FCliConv.Conv, FHszItem,
  1383.         FCliConv.DdeFmt, XTYP_ADVSTOP, 1000, @ddeRslt);
  1384.   SrvrDisconnect;
  1385.   Result := True;
  1386. end;
  1387.  
  1388. procedure TDdeCliItem.SrvrDisconnect;
  1389. begin
  1390.   if FHszItem <> 0 then
  1391.   begin
  1392.     DdeFreeStringHandle(ddeMgr.DdeInstId, FHszItem);
  1393.     FHszItem := 0;
  1394.   end;
  1395. end;
  1396.  
  1397. procedure TDdeCliItem.DataChange;
  1398. begin
  1399.   FCtrl.OnAdvise;
  1400. end;
  1401.  
  1402. constructor TDdeServerItem.Create(AOwner: TComponent);
  1403. begin
  1404.   inherited Create(AOwner);
  1405.   FFmt := CF_TEXT;
  1406.   FLines := TStringList.Create;
  1407. end;
  1408.  
  1409. destructor TDdeServerItem.Destroy;
  1410. begin
  1411.   FLines.Free;
  1412.   inherited Destroy;
  1413. end;
  1414.  
  1415. procedure TDdeServerItem.SetServerConv(SConv: TDdeServerConv);
  1416. begin
  1417.   FServerConv := SConv;
  1418.   if SConv <> nil then SConv.FreeNotification(Self);
  1419. end;
  1420.  
  1421. function TDdeServerItem.GetText: string;
  1422. begin
  1423.   if FLines.Count > 0 then
  1424.     Result := FLines.Strings[0]
  1425.   else Result := '';
  1426. end;
  1427.  
  1428. procedure TDdeServerItem.SetText(const Item: string);
  1429. begin
  1430.   FFmt := CF_TEXT;
  1431.   FLines.Clear;
  1432.   FLines.Add(Item);
  1433.   ValueChanged;
  1434. end;
  1435.  
  1436. procedure TDdeServerItem.SetLines(Value: TStrings);
  1437. begin
  1438.   if AnsiCompareStr(Value.Text, FLines.Text) <> 0 then
  1439.   begin
  1440.     FFmt := CF_TEXT;
  1441.     FLines.Assign(Value);
  1442.     ValueChanged;
  1443.   end;
  1444. end;
  1445.  
  1446. procedure TDdeServerItem.ValueChanged;
  1447. begin
  1448.   if Assigned(FOnChange) then FOnChange(Self);
  1449.   if FServerConv <> nil then
  1450.     ddeMgr.PostDataChange(FServerConv.Name, Name)
  1451.   else if (Owner <> nil) and (Owner is TForm) then
  1452.     ddeMgr.PostDataChange(TForm(Owner).Caption, Name);
  1453. end;
  1454.  
  1455. function TDdeServerItem.PokeData(Data: HDdeData): LongInt;
  1456. var
  1457.   Len: Integer;
  1458.   pData: Pointer;
  1459. begin
  1460.   Result := dde_FNotProcessed;
  1461.   pData := DdeAccessData(Data, @Len);
  1462.   if pData <> nil then
  1463.   begin
  1464.     Lines.Text := PChar(pData);
  1465.     DdeUnaccessData(Data);
  1466.     ValueChanged;
  1467.     if Assigned(FOnPokeData) then FOnPokeData(Self);
  1468.     Result := dde_FAck;
  1469.   end;
  1470. end;
  1471.  
  1472. procedure TDdeServerItem.CopyToClipboard;
  1473. var
  1474.   Data: THandle;
  1475.   LinkData: string;
  1476.   DataPtr: Pointer;
  1477. begin
  1478.   if FServerConv <> nil then
  1479.     LinkData := ddeMgr.AppName + #0 + FServerConv.Name + #0 + Name
  1480.   else if (Owner =nil) then Exit
  1481.   else if Owner is TForm then
  1482.     LinkData := ddeMgr.AppName + #0 + TForm(Owner).Caption + #0 + Name;
  1483.   try
  1484.     Clipboard.AsText := Text;
  1485.     Data := GlobalAlloc(GMEM_MOVEABLE, Length(LinkData) + 1);
  1486.     try
  1487.       DataPtr := GlobalLock(Data);
  1488.       try
  1489.         Move(PChar(LinkData)^, DataPtr^, Length(LinkData) + 1);
  1490.         Clipboard.SetAsHandle(DdeMgr.LinkClipFmt, Data);
  1491.       finally
  1492.         GlobalUnlock(Data);
  1493.       end;
  1494.     except
  1495.       GlobalFree(Data);
  1496.       raise;
  1497.     end;
  1498.   finally
  1499.     Clipboard.Close;
  1500.   end;
  1501. end;
  1502.  
  1503. procedure TDdeServerItem.Change;
  1504. begin
  1505.   if Assigned(FOnChange) then FOnChange(Self);
  1506. end;
  1507.  
  1508. procedure TDdeServerItem.Notification(AComponent: TComponent;
  1509.   Operation: TOperation);
  1510. begin
  1511.   inherited Notification(AComponent, Operation);
  1512.   if (AComponent = FServerConv) and (Operation = opRemove) then
  1513.     FServerConv := nil;
  1514. end;
  1515.  
  1516. constructor TDdeServerConv.Create(AOwner: TComponent);
  1517. begin
  1518.   inherited Create(AOwner);
  1519.   ddeMgr.InsertServerConv (Self);
  1520. end;
  1521.  
  1522. destructor TDdeServerConv.Destroy;
  1523. begin
  1524.   ddeMgr.RemoveServerConv(Self);
  1525.   inherited Destroy;
  1526. end;
  1527.  
  1528. function TDdeServerConv.ExecuteMacro(Data: HDdeData): LongInt;
  1529. var
  1530.   Len: Integer;
  1531.   pData: Pointer;
  1532.   MacroLines: TStringList;
  1533. begin
  1534.   Result := dde_FNotProcessed;
  1535.   pData := DdeAccessData(Data, @Len);
  1536.   if pData <> nil then
  1537.   begin
  1538.     if Assigned(FOnExecuteMacro) then
  1539.     begin
  1540.       MacroLines := TStringList.Create;
  1541.       MacroLines.Text := PChar(pData);
  1542.       FOnExecuteMacro(Self, MacroLines);
  1543.       MacroLines.Destroy;
  1544.     end;
  1545.     Result := dde_FAck;
  1546.   end;
  1547. end;
  1548.  
  1549. procedure TDdeServerConv.Connect;
  1550. begin
  1551.   if Assigned(FOnOpen) then FOnOpen(Self);
  1552. end;
  1553.  
  1554. procedure TDdeServerConv.Disconnect;
  1555. begin
  1556.   if Assigned(FOnClose) then FOnClose(Self);
  1557. end;
  1558.  
  1559. constructor TDdeSrvrConv.Create(AOwner: TComponent);
  1560. begin
  1561.   inherited Create(AOwner);
  1562.   FItems := TList.Create;
  1563. end;
  1564.  
  1565. destructor TDdeSrvrConv.Destroy;
  1566. var
  1567.   I: Integer;
  1568. begin
  1569.   if FItems <> nil then
  1570.   begin
  1571.     for I := 0 to FItems.Count - 1 do
  1572.       TDdeSrvrItem(FItems[I]).Free;
  1573.     FItems.Free;
  1574.     FItems := nil;
  1575.   end;
  1576.   if FConv <> 0 then DdeDisconnect(FConv);
  1577.   if FHszTopic <> 0 then
  1578.   begin
  1579.     DdeFreeStringHandle(ddeMgr.DdeInstId, FHszTopic);
  1580.     FHszTopic := 0;
  1581.   end;
  1582.   inherited Destroy;
  1583. end;
  1584.  
  1585. function TDdeSrvrConv.AdvStart(Conv: HConv; hszTopic: HSZ; hszItem: HSZ;
  1586.   Fmt: Word): Boolean;
  1587. var
  1588.   Srvr: TDdeServerItem;
  1589.   Buffer: array[0..4095] of Char;
  1590.   SrvrItem: TDdeSrvrItem;
  1591. begin
  1592.   Result := False;
  1593.   if Fmt <> CF_TEXT then Exit;
  1594.   DdeQueryString(ddeMgr.DdeInstId, hszItem, Buffer, SizeOf(Buffer), CP_WINANSI);
  1595.   Srvr := GetControl(FForm, FSConv, Buffer);
  1596.   if Srvr = nil then Exit;
  1597.   SrvrItem := TDdeSrvrItem.Create(Self);
  1598.   SrvrItem.Srvr := Srvr;
  1599.   SrvrItem.Item := Buffer;
  1600.   FItems.Add(SrvrItem);
  1601.   SrvrItem.FreeNotification(Self);
  1602.   if FHszTopic = 0 then
  1603.     FHszTopic := DdeCreateStringHandle(ddeMgr.DdeInstId, PChar(Topic), CP_WINANSI);
  1604.   Result := True;
  1605. end;
  1606.  
  1607. procedure TDdeSrvrConv.AdvStop(Conv: HConv; hszTopic: HSZ; hszItem :HSZ);
  1608. var
  1609.   SrvrItem: TDdeSrvrItem;
  1610. begin
  1611.   SrvrItem := GetSrvrItem(hszItem);
  1612.   if SrvrItem <> nil then
  1613.   begin
  1614.     FItems.Remove(SrvrItem);
  1615.     SrvrItem.Free;
  1616.   end;
  1617. end;
  1618.  
  1619. function TDdeSrvrConv.PokeData(Conv: HConv; hszTopic: HSZ; hszItem: HSZ;
  1620.   Data: HDdeData; Fmt: Integer): LongInt;
  1621. var
  1622.   Srvr: TDdeServerItem;
  1623.   Buffer: array[0..4095] of Char;
  1624. begin
  1625.   Result := dde_FNotProcessed;
  1626.   if Fmt <> CF_TEXT then Exit;
  1627.   DdeQueryString(ddeMgr.DdeInstId, hszItem, Buffer, SizeOf(Buffer), CP_WINANSI);
  1628.   Srvr := GetControl(FForm, FSConv, Buffer);
  1629.   if Srvr <> nil then Result := Srvr.PokeData(Data);
  1630. end;
  1631.  
  1632. function TDdeSrvrConv.ExecuteMacro(Conv: HConv; hszTopic: HSZ;
  1633.   Data: HDdeData): Integer;
  1634. begin
  1635.   Result := dde_FNotProcessed;
  1636.   if (FSConv <> nil)  then
  1637.     Result := FSConv.ExecuteMacro(Data);
  1638. end;
  1639.  
  1640. function TDdeSrvrConv.RequestData(Conv: HConv; hszTopic: HSZ; hszItem :HSZ;
  1641.   Fmt: Word): HDdeData;
  1642. var
  1643.   Data: string;
  1644.   Buffer: array[0..4095] of Char;
  1645.   SrvrIt: TDdeSrvrItem;
  1646.   Srvr: TDdeServerItem;
  1647. begin
  1648.   Result := 0;
  1649.   SrvrIt := GetSrvrItem(hszItem);
  1650.   if SrvrIt <> nil then
  1651.     Result := SrvrIt.RequestData(Fmt)
  1652.   else
  1653.   begin
  1654.     DdeQueryString(ddeMgr.DdeInstId, hszItem, Buffer, SizeOf(Buffer), CP_WINANSI);
  1655.     Srvr := GetControl(FForm, FSConv, Buffer);
  1656.     if Srvr <> nil then
  1657.     begin
  1658.       if Fmt = CF_TEXT then
  1659.       begin
  1660.         Data := Srvr.Lines.Text;
  1661.         Result := DdeCreateDataHandle(ddeMgr.DdeInstId, PChar(Data),
  1662.           Length(Data) + 1, 0, hszItem, Fmt, 0 );
  1663.       end;
  1664.     end;
  1665.   end;
  1666. end;
  1667.  
  1668. function TDdeSrvrConv.GetControl(WinCtrl: TWinControl; DdeConv: TDdeServerConv; const ItemName: string): TDdeServerItem;
  1669. var
  1670.   I: Integer;
  1671.   Ctrl: TComponent;
  1672.   MainCtrl: TWinControl;
  1673.   Srvr: TDdeServerItem;
  1674. begin
  1675.   Result := nil;
  1676.   MainCtrl := WinCtrl;
  1677.   if MainCtrl = nil then
  1678.   begin
  1679.     if (DdeConv <> nil) and (DdeConv.Owner <> nil) and
  1680.       (DdeConv.Owner is TForm) then
  1681.       MainCtrl := TWinControl(DdeConv.Owner);
  1682.   end;
  1683.   if MainCtrl = nil then Exit;
  1684.   for I := 0 to MainCtrl.ComponentCount - 1 do
  1685.   begin
  1686.     Ctrl := MainCtrl.Components[I];
  1687.     if Ctrl is TDdeServerItem then
  1688.     begin
  1689.       if (Ctrl.Name = ItemName) and
  1690.         (TDdeServerItem(Ctrl).ServerConv = DdeConv) then
  1691.       begin
  1692.         Result := TDdeServerItem(Ctrl);
  1693.         Exit;
  1694.       end;
  1695.     end;
  1696.     if Ctrl is TWinControl then
  1697.     begin
  1698.       Srvr := GetControl(TWinControl(Ctrl), DdeConv, ItemName);
  1699.       if Srvr <> nil then
  1700.       begin
  1701.         Result := Srvr;
  1702.         Exit;
  1703.       end;
  1704.     end;
  1705.   end;
  1706. end;
  1707.  
  1708. function TDdeSrvrConv.GetItem(const ItemName: string): TDdeSrvrItem;
  1709. var
  1710.   I: Integer;
  1711.   Item: TDdeSrvrItem;
  1712. begin
  1713.   Result := nil;
  1714.   for I := 0 to FItems.Count - 1 do
  1715.   begin
  1716.     Item := FItems[I];
  1717.     If Item.Item = ItemName then
  1718.     begin
  1719.       Result := Item;
  1720.       Exit;
  1721.     end;
  1722.   end;
  1723. end;
  1724.  
  1725. function TDdeSrvrConv.GetSrvrItem(hszItem: HSZ): TDdeSrvrItem;
  1726. var
  1727.   I: Integer;
  1728.   Item: TDdeSrvrItem;
  1729. begin
  1730.   Result := nil;
  1731.   for I := 0 to FItems.Count - 1 do
  1732.   begin
  1733.     Item := FItems[I];
  1734.     If DdeCmpStringHandles(Item.HszItem, hszItem) = 0 then
  1735.     begin
  1736.       Result := Item;
  1737.       Exit;
  1738.     end;
  1739.   end;
  1740. end;
  1741.  
  1742. constructor TDdeSrvrItem.Create(AOwner: TComponent);
  1743. begin
  1744.   FConv := TDdeSrvrConv(AOwner);
  1745.   inherited Create(AOwner);
  1746. end;
  1747.  
  1748. destructor TDdeSrvrItem.Destroy;
  1749. begin
  1750.   if FHszItem <> 0 then
  1751.   begin
  1752.     DdeFreeStringHandle(ddeMgr.DdeInstId, FHszItem);
  1753.     FHszItem := 0;
  1754.   end;
  1755.   inherited Destroy;
  1756. end;
  1757.  
  1758. function TDdeSrvrItem.RequestData(Fmt: Word): HDdeData;
  1759. var
  1760.   Data: string;
  1761.   Buffer: array[0..4095] of Char;
  1762. begin
  1763.   Result := 0;
  1764.   SetString(FItem, Buffer, DdeQueryString(ddeMgr.DdeInstId, FHszItem, Buffer,
  1765.     SizeOf(Buffer), CP_WINANSI));
  1766.   if Fmt = CF_TEXT then
  1767.   begin
  1768.     Data := FSrvr.Lines.Text;
  1769.     Result := DdeCreateDataHandle(ddeMgr.DdeInstId, PChar(Data), Length(Data) + 1,
  1770.       0, FHszItem, Fmt, 0 );
  1771.   end;
  1772. end;
  1773.  
  1774. procedure TDdeSrvrItem.PostDataChange;
  1775. begin
  1776.   DdePostAdvise(ddeMgr.DdeInstId, FConv.HszTopic, FHszItem);
  1777. end;
  1778.  
  1779. procedure TDdeSrvrItem.SetItem(const Value: string);
  1780. begin
  1781.   FItem := Value;
  1782.   if FHszItem <> 0 then
  1783.   begin
  1784.     DdeFreeStringHandle(ddeMgr.DdeInstId, FHszItem);
  1785.     FHszItem := 0;
  1786.   end;
  1787.   if Length(FItem) > 0 then
  1788.     FHszItem := DdeCreateStringHandle(ddeMgr.DdeInstId, PChar(FItem), CP_WINANSI);
  1789. end;
  1790.  
  1791. begin
  1792.   ddeMgr := TDdeMgr.Create(Application);
  1793. end.
  1794.  
  1795.