{----------------------------------------------------------------------------- The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/MPL-1.1.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is: JvAppDdeCmd.PAS, released Jan 2, 1998. The Initial Developer of the Original Code is Petr Vones (petr dott v att mujmail dott cz) Portions created by Petr Vones are Copyright (C) 1999 Petr Vones. Portions created by Microsoft are Copyright (C) 1998, 1999 Microsoft Corp. All Rights Reserved. Contributor(s): ______________________________________. You may retrieve the latest version of this file at the Project JEDI's JVCL home page, located at http://jvcl.sourceforge.net Known Issues: -----------------------------------------------------------------------------} // $Id: JvDdeCmd.pas,v 1.18 2005/09/15 07:22:54 marquardt Exp $ unit JvDdeCmd; {$I jvcl.inc} {$I windowsonly.inc} interface uses {$IFDEF UNITVERSIONING} JclUnitVersioning, {$ENDIF UNITVERSIONING} Messages, DdeMan, Classes, JvComponentBase, JvTypes; type EJvADCParserError = class(EJVCLException); TJvADCBusyEvent = procedure(Sender: TObject; IsBusy: Boolean) of object; TJvADCParsedEvent = procedure(Sender: TObject; const Command: string; Parameters: TStrings) of object; TJvADCMacroEvent = procedure(Sender: TObject; const CommandStr: string) of object; TJvAppDdeCmd = class(TJvComponent) private FCorrectParams: Boolean; FEnabled: Boolean; FCommands: TStringList; FIgnoreAppBusy: Boolean; FModalState: Boolean; FOnBusyChanged: TJvADCBusyEvent; FOnExecCommand: TJvADCMacroEvent; FOnExecParsedCmd: TJvADCParsedEvent; function GetCommands: TStrings; procedure SetEnabled(Value: Boolean); procedure SetIgnoreAppBusy(Value: Boolean); procedure SetModalState(Value: Boolean); function AppBusy: Boolean; procedure ExecuteCommands; procedure ExecuteParsedCommands(const CmdStr: string); function HookWndProc(var AMsg: TMessage): Boolean; procedure Notify(ACommands: TStrings); protected procedure BusyStateChanged; dynamic; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; property Commands: TStrings read GetCommands; published property CorrectParams: Boolean read FCorrectParams write FCorrectParams default True; property Enabled: Boolean read FEnabled write SetEnabled default True; property IgnoreAppBusy: Boolean read FIgnoreAppBusy write SetIgnoreAppBusy default False; property OnBusyChanged: TJvADCBusyEvent read FOnBusyChanged write FOnBusyChanged; property OnExecCommand: TJvADCMacroEvent read FOnExecCommand write FOnExecCommand; property OnExecParsedCmd: TJvADCParsedEvent read FOnExecParsedCmd write FOnExecParsedCmd; end; {$IFDEF UNITVERSIONING} const UnitVersioning: TUnitVersionInfo = ( RCSfile: '$RCSfile: JvDdeCmd.pas,v $'; Revision: '$Revision: 1.18 $'; Date: '$Date: 2005/09/15 07:22:54 $'; LogPath: 'JVCL\run' ); {$ENDIF UNITVERSIONING} implementation uses SysUtils, Forms, JvResources; const DdeTopicStr = 'System'; //=== { TAppDdeMgr } ========================================================= type TAppDdeMgr = class(TObject) private DdeServ: TDdeServerConv; Commands: TStringList; Components: TList; procedure DdeServerConvExecuteMacro(Sender: TObject; Msg: TStrings); procedure NotifyComponents; public constructor Create; destructor Destroy; override; procedure AddComponent(AComponent: TComponent); procedure DeleteComponent(AComponent: TComponent); end; var AppDdeMgr: TAppDdeMgr = nil; constructor TAppDdeMgr.Create; begin inherited Create; if Application.FindComponent(DdeTopicStr) = nil then begin DdeServ := TDdeServerConv.Create(Application); with DdeServ do begin Name := DdeTopicStr; OnExecuteMacro := DdeServerConvExecuteMacro; end; Commands := TStringList.Create; Components := TList.Create; end; end; destructor TAppDdeMgr.Destroy; begin FreeAndNil(Components); FreeAndNil(Commands); inherited Destroy; end; procedure TAppDdeMgr.AddComponent(AComponent: TComponent); begin Components.Add(AComponent); end; procedure TAppDdeMgr.DeleteComponent(AComponent: TComponent); begin Components.Remove(AComponent); end; procedure TAppDdeMgr.DdeServerConvExecuteMacro(Sender: TObject; Msg: TStrings); begin if Components <> nil then begin Commands.Add(Msg[0]); NotifyComponents; end; end; procedure TAppDdeMgr.NotifyComponents; var I: Integer; begin with Components do for I := 0 to Count - 1 do TJvAppDdeCmd(Items[I]).Notify(Commands); Commands.Clear; end; //=== { TJvAppDdeCmd } ======================================================= constructor TJvAppDdeCmd.Create(AOwner: TComponent); begin inherited Create(AOwner); FCorrectParams := True; FEnabled := True; FIgnoreAppBusy := False; FModalState := False; FCommands := TStringList.Create; if not (csDesigning in ComponentState) then begin if not Assigned(AppDdeMgr) then AppDdeMgr := TAppDdeMgr.Create; AppDdeMgr.AddComponent(Self); Application.HookMainWindow(HookWndProc); end; end; destructor TJvAppDdeCmd.Destroy; begin if not (csDesigning in ComponentState) then begin Application.UnhookMainWindow(HookWndProc); AppDdeMgr.DeleteComponent(Self); end; FreeAndNil(FCommands); inherited Destroy; end; function TJvAppDdeCmd.GetCommands: TStrings; begin Result := FCommands; end; procedure TJvAppDdeCmd.SetEnabled(Value: Boolean); begin if FEnabled <> Value then begin FEnabled := Value; BusyStateChanged; end; end; procedure TJvAppDdeCmd.SetIgnoreAppBusy(Value: Boolean); begin if FIgnoreAppBusy <> Value then begin FIgnoreAppBusy := Value; BusyStateChanged; end; end; procedure TJvAppDdeCmd.SetModalState(Value: Boolean); begin if FModalState <> Value then begin FModalState := Value; BusyStateChanged; end; end; function TJvAppDdeCmd.AppBusy: Boolean; begin Result := (not FEnabled) or (FModalState and (not FIgnoreAppBusy)); end; procedure TJvAppDdeCmd.BusyStateChanged; begin if Assigned(FOnBusyChanged) then FOnBusyChanged(Self, AppBusy); ExecuteCommands; end; procedure TJvAppDdeCmd.ExecuteCommands; begin with FCommands do while (not AppBusy) and (Count > 0) do begin try if Assigned(FOnExecCommand) then FOnExecCommand(Self, Strings[0]); if Assigned(FOnExecParsedCmd) then ExecuteParsedCommands(Strings[0]); Delete(0); except Delete(0); Application.HandleException(Self); end; end; end; procedure TJvAppDdeCmd.ExecuteParsedCommands(const CmdStr: string); var I: Integer; CmdSPos, CmdEPos, ParamsSPos, ParamsEPos: Integer; StartCmd, StartParams, StartString: Boolean; S, Cmd: string; Params: TStringList; procedure CorrParams; var I, ErrCode, Value: Integer; C: ShortString; begin with Params do for I := 0 to Count - 1 do begin C := Strings[I]; if Length(C) >= 2 then begin if C[1] = '"' then System.Delete(C, 1, 1); if C[Length(C)] = '"' then System.Delete(C, Length(C), 1); Strings[I] := C; end; Val(C, Value, ErrCode); if ErrCode = 0 then Objects[I] := Pointer(Value); end; end; begin I := 1; StartCmd := False; StartParams := False; StartString := False; CmdSPos := 0; CmdEPos := 0; ParamsSPos := 0; // ParamsEPos := 0; Params := TStringList.Create; try S := Trim(CmdStr); while I <= Length(S) do begin if not StartCmd then begin if S[I] <> '[' then raise EJvADCParserError.CreateRes(@RsEErrorCommandStart); StartCmd := True; StartParams := False; StartString := False; CmdSPos := I + 1; CmdEPos := 0; ParamsSPos := 0; // ParamsEPos := 0; Params.Clear; end else begin if S[I] = '"' then StartString := not StartString else if not StartString then begin if (S[I] = ',') and StartParams then begin Params.Add(Copy(S, ParamsSPos, I - ParamsSPos)); ParamsSPos := I + 1; end else if S[I] = '(' then begin CmdEPos := I - 1; StartParams := True; ParamsSPos := I + 1; end else if (S[I] = ')') and StartParams then begin ParamsEPos := I - 1; StartParams := False; Params.Add(Copy(S, ParamsSPos, ParamsEPos - ParamsSPos + 1)); end else if (S[I] = ']') and (not StartParams) then begin if CmdEPos = 0 then CmdEPos := I - 1; Cmd := AnsiUpperCase(Copy(S, CmdSPos, CmdEPos - CmdSPos + 1)); if FCorrectParams then CorrParams; FOnExecParsedCmd(Self, Cmd, Params); StartCmd := False; end; end; end; Inc(I); end; if StartCmd or StartParams or StartString then raise EJvADCParserError.CreateResFmt(@RsEErrorCommandFormat, [S]); finally Params.Free; end; end; function TJvAppDdeCmd.HookWndProc(var AMsg: TMessage): Boolean; begin Result := False; if AMsg.Msg = WM_ENABLE then SetModalState(not TWMEnable(AMsg).Enabled); end; procedure TJvAppDdeCmd.Notify(ACommands: TStrings); begin FCommands.AddStrings(ACommands); ExecuteCommands; end; initialization {$IFDEF UNITVERSIONING} RegisterUnitVersion(HInstance, UnitVersioning); {$ENDIF UNITVERSIONING} finalization FreeAndNil(AppDdeMgr); {$IFDEF UNITVERSIONING} UnregisterUnitVersion(HInstance); {$ENDIF UNITVERSIONING} end.