(200分求助)我想写一个程序A来控制另外一个程序B,主要通过控制程序B的菜单来实现,比如进入程序B一级菜单文件,然后进入其子菜单打开,出现一个打开文件对话框,然后将某个文件打开。请问各位高手有什么好的办法?问题解决马上另外开一个100分帖子散给解答人。

解决方案 »

  1.   

    用下面贴的SendKeys函数,比较长,分两贴。
    以Word为例,
    procedure TForm1.Button1Click(Sender: TObject);
    var h: HWND;
    begin
      h := FindWindow(nil, 'Microsoft Word');
      if h > 0 then begin
        SetForegroundWindow(h);
        //发送按键:Alt+F,O,输入d:\z.doc,Alt+O打开
        SendKeys('%fod:\z.doc%o', True);
      end;
    end;
    (*
    Converts a string of characters and key names to keyboard events and
    passes them to Windows.Example syntax:SendKeys('abc123{left}{left}{left}def{end}456{left 6}ghi{end}789', True);
    *)
    Function SendKeys(SendKeysString : PChar; Wait : Boolean) : Boolean;
    type
      WBytes = array[0..pred(SizeOf(Word))] of Byte;  TSendKey = record
        Name : ShortString;
        VKey : Byte;
      end;const
      {Array of keys that SendKeys recognizes.  If you add to this list, you must be sure to keep it sorted alphabetically
      by Name because a binary search routine is used to scan it.}  MaxSendKeyRecs = 41;
      SendKeyRecs : array[1..MaxSendKeyRecs] of TSendKey =
      (
       (Name:'BKSP';            VKey:VK_BACK),
       (Name:'BS';              VKey:VK_BACK),
       (Name:'BACKSPACE';       VKey:VK_BACK),
       (Name:'BREAK';           VKey:VK_CANCEL),
       (Name:'CAPSLOCK';        VKey:VK_CAPITAL),
       (Name:'CLEAR';           VKey:VK_CLEAR),
       (Name:'DEL';             VKey:VK_DELETE),
       (Name:'DELETE';          VKey:VK_DELETE),
       (Name:'DOWN';            VKey:VK_DOWN),
       (Name:'END';             VKey:VK_END),
       (Name:'ENTER';           VKey:VK_RETURN),
       (Name:'ESC';             VKey:VK_ESCAPE),
       (Name:'ESCAPE';          VKey:VK_ESCAPE),
       (Name:'F1';              VKey:VK_F1),
       (Name:'F10';             VKey:VK_F10),
       (Name:'F11';             VKey:VK_F11),
       (Name:'F12';             VKey:VK_F12),
       (Name:'F13';             VKey:VK_F13),
       (Name:'F14';             VKey:VK_F14),
       (Name:'F15';             VKey:VK_F15),
       (Name:'F16';             VKey:VK_F16),
       (Name:'F2';              VKey:VK_F2),
       (Name:'F3';              VKey:VK_F3),
       (Name:'F4';              VKey:VK_F4),
       (Name:'F5';              VKey:VK_F5),
       (Name:'F6';              VKey:VK_F6),
       (Name:'F7';              VKey:VK_F7),
       (Name:'F8';              VKey:VK_F8),
       (Name:'F9';              VKey:VK_F9),
       (Name:'HELP';            VKey:VK_HELP),
       (Name:'HOME';            VKey:VK_HOME),
       (Name:'INS';             VKey:VK_INSERT),
       (Name:'LEFT';            VKey:VK_LEFT),
       (Name:'NUMLOCK';         VKey:VK_NUMLOCK),
       (Name:'PGDN';            VKey:VK_NEXT),
       (Name:'PGUP';            VKey:VK_PRIOR),
       (Name:'PRTSC';           VKey:VK_PRINT),
       (Name:'RIGHT';           VKey:VK_RIGHT),
       (Name:'SCROLLLOCK';      VKey:VK_SCROLL),
       (Name:'TAB';             VKey:VK_TAB),
       (Name:'UP';              VKey:VK_UP)
      );  {Extra VK constants missing from Delphi's Windows API interface}
      VK_NULL=0;
      VK_SemiColon=186;
      VK_Equal=187;
      VK_Comma=188;
      VK_Minus=189;
      VK_Period=190;
      VK_Slash=191;
      VK_BackQuote=192;
      VK_LeftBracket=219;
      VK_BackSlash=220;
      VK_RightBracket=221;
      VK_Quote=222;
      VK_Last=VK_Quote;  ExtendedVKeys : set of byte =
      [VK_Up,
       VK_Down,
       VK_Left,
       VK_Right,
       VK_Home,
       VK_End,
       VK_Prior,  {PgUp}
       VK_Next,   {PgDn}
       VK_Insert,
       VK_Delete];const
      INVALIDKEY = $FFFF {Unsigned -1};
      VKKEYSCANSHIFTON = $01;
      VKKEYSCANCTRLON = $02;
      VKKEYSCANALTON = $04;
      UNITNAME = 'SendKeys';
    var
      UsingParens, ShiftDown, ControlDown, AltDown, FoundClose : Boolean;
      PosSpace : Byte;
      I, L : Integer;
      NumTimes, MKey : Word;
      KeyString : String[20];
      AllocationSize: Integer;procedure DisplayMessage(Message : PChar);
    begin
      MessageBox(0,Message,UNITNAME,0);
    end;function BitSet(BitTable, BitMask : Byte) : Boolean;
    begin
      Result:=ByteBool(BitTable and BitMask);
    end;procedure SetBit(var BitTable : Byte; BitMask : Byte);
    begin
      BitTable:=BitTable or Bitmask;
    end;Procedure KeyboardEvent(VKey, ScanCode : Byte; Flags : Longint);
    var
      KeyboardMsg : TMsg;
    begin
      keybd_event(VKey, ScanCode, Flags,0);
      If (Wait) then While (PeekMessage(KeyboardMsg,0,WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)) do begin
        TranslateMessage(KeyboardMsg);
        DispatchMessage(KeyboardMsg);
      end;
    end;Procedure SendKeyDown(VKey: Byte; NumTimes : Word; GenUpMsg : Boolean);
    var
      Cnt : Word;
      ScanCode : Byte;
      NumState : Boolean;
      KeyBoardState : TKeyboardState;
    begin
      If (VKey=VK_NUMLOCK) then begin
        NumState:=ByteBool(GetKeyState(VK_NUMLOCK) and 1);
        GetKeyBoardState(KeyBoardState);
        If NumState then KeyBoardState[VK_NUMLOCK]:=(KeyBoardState[VK_NUMLOCK] and not 1)
        else KeyBoardState[VK_NUMLOCK]:=(KeyBoardState[VK_NUMLOCK] or 1);
        SetKeyBoardState(KeyBoardState);
        exit;
      end;  ScanCode:=Lo(MapVirtualKey(VKey,0));
      For Cnt:=1 to NumTimes do
        If (VKey in ExtendedVKeys)then begin
          KeyboardEvent(VKey, ScanCode, KEYEVENTF_EXTENDEDKEY);
          If (GenUpMsg) then
            KeyboardEvent(VKey, ScanCode, KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP)
        end else begin
          KeyboardEvent(VKey, ScanCode, 0);
          If (GenUpMsg) then KeyboardEvent(VKey, ScanCode, KEYEVENTF_KEYUP);
        end;
    end;Procedure SendKeyUp(VKey: Byte);
    var
      ScanCode : Byte;
    begin
      ScanCode:=Lo(MapVirtualKey(VKey,0));
      If (VKey in ExtendedVKeys)then
        KeyboardEvent(VKey, ScanCode, KEYEVENTF_EXTENDEDKEY and KEYEVENTF_KEYUP)
      else KeyboardEvent(VKey, ScanCode, KEYEVENTF_KEYUP);
    end;Procedure SendKey(MKey: Word; NumTimes : Word; GenDownMsg : Boolean);
    begin
      If (BitSet(Hi(MKey),VKKEYSCANSHIFTON)) then SendKeyDown(VK_SHIFT,1,False);
      If (BitSet(Hi(MKey),VKKEYSCANCTRLON)) then SendKeyDown(VK_CONTROL,1,False);
      If (BitSet(Hi(MKey),VKKEYSCANALTON)) then SendKeyDown(VK_MENU,1,False);
      SendKeyDown(Lo(MKey), NumTimes, GenDownMsg);
      If (BitSet(Hi(MKey),VKKEYSCANSHIFTON)) then SendKeyUp(VK_SHIFT);
      If (BitSet(Hi(MKey),VKKEYSCANCTRLON)) then SendKeyUp(VK_CONTROL);
      If (BitSet(Hi(MKey),VKKEYSCANALTON)) then SendKeyUp(VK_MENU);
    end;{Implements a simple binary search to locate special key name strings}Function StringToVKey(KeyString : ShortString) : Word;
    var
      Found, Collided : Boolean;
      Bottom, Top, Middle : Byte;
    begin
      Result:=INVALIDKEY;
      Bottom:=1;
      Top:=MaxSendKeyRecs;
      Found:=false;
      Middle:=(Bottom+Top) div 2;
      Repeat
        Collided:=((Bottom=Middle) or (Top=Middle));
        If (KeyString=SendKeyRecs[Middle].Name) then begin
           Found:=True;
           Result:=SendKeyRecs[Middle].VKey;
        end else begin
           If (KeyString>SendKeyRecs[Middle].Name) then Bottom:=Middle
           else Top:=Middle;
           Middle:=(Succ(Bottom+Top)) div 2;
        end;
      Until (Found or Collided);
      If (Result=INVALIDKEY) then DisplayMessage('Invalid Key Name');
    end;
      

  2.   

    接上贴procedure PopUpShiftKeys;
    begin
      If (not UsingParens) then begin
        If ShiftDown then SendKeyUp(VK_SHIFT);
        If ControlDown then SendKeyUp(VK_CONTROL);
        If AltDown then SendKeyUp(VK_MENU);
        ShiftDown:=false;
        ControlDown:=false;
        AltDown:=false;
      end;
    end;begin
      AllocationSize:=MaxInt;
      Result:=false;
      UsingParens:=false;
      ShiftDown:=false;
      ControlDown:=false;
      AltDown:=false;
      I:=0;
      L:=StrLen(SendKeysString);
      If (L>AllocationSize) then L:=AllocationSize;
      If (L=0) then Exit;  While (I<L) do begin
        case SendKeysString[I] of
        '(' : begin
                UsingParens:=True;
                Inc(I);
              end;
        ')' : begin
                UsingParens:=False;
                PopUpShiftKeys;
                Inc(I);
              end;
        '%' : begin
                 AltDown:=True;
                 SendKeyDown(VK_MENU,1,False);
                 Inc(I);
              end;
        '+' :  begin
                 ShiftDown:=True;
                 SendKeyDown(VK_SHIFT,1,False);
                 Inc(I);
               end;
        '^' :  begin
                 ControlDown:=True;
                 SendKeyDown(VK_CONTROL,1,False);
                 Inc(I);
               end;
        '{' : begin
                NumTimes:=1;
                If (SendKeysString[Succ(I)]='{') then begin
                  MKey:=VK_LEFTBRACKET;
                  SetBit(Wbytes(MKey)[1],VKKEYSCANSHIFTON);
                  SendKey(MKey,1,True);
                  PopUpShiftKeys;
                  Inc(I,3);
                  Continue;
                end;
                KeyString:='';
                FoundClose:=False;
                While (I<=L) do begin
                  Inc(I);
                  If (SendKeysString[I]='}') then begin
                    FoundClose:=True;
                    Inc(I);
                    Break;
                  end;
                  KeyString:=KeyString+Upcase(SendKeysString[I]);
                end;
                If (Not FoundClose) then begin
                   DisplayMessage('No Close');
                   Exit;
                end;
                If (SendKeysString[I]='}') then begin
                  MKey:=VK_RIGHTBRACKET;
                  SetBit(Wbytes(MKey)[1],VKKEYSCANSHIFTON);
                  SendKey(MKey,1,True);
                  PopUpShiftKeys;
                  Inc(I);
                  Continue;
                end;
                PosSpace:=Pos(' ',KeyString);
                If (PosSpace<>0) then begin
                   NumTimes:=StrToInt(Copy(KeyString,Succ(PosSpace),Length(KeyString)-PosSpace));
                   KeyString:=Copy(KeyString,1,Pred(PosSpace));
                end;
                If (Length(KeyString)=1) then MKey:=vkKeyScan(KeyString[1])
                else MKey:=StringToVKey(KeyString);
                If (MKey<>INVALIDKEY) then begin
                  SendKey(MKey,NumTimes,True);
                  PopUpShiftKeys;
                  Continue;
                end;
              end;
        '~' : begin
                SendKeyDown(VK_RETURN,1,True);
                PopUpShiftKeys;
                Inc(I);
              end;
        else  begin
                 MKey:=vkKeyScan(SendKeysString[I]);
                 If (MKey<>INVALIDKEY) then begin
                   SendKey(MKey,1,True);
                   PopUpShiftKeys;
                 end else DisplayMessage('Invalid KeyName');
                 Inc(I);
              end;
        end;
      end;
      Result:=true;
      PopUpShiftKeys;
    end;
      

  3.   

    本程序用了3个BITBTN和2个EDIT,可以启动计算器,调用计算器菜单命令。
    其中: BITBTN1调用计算器,根据系统不同计算器路径可能不同,请自行修改。本系统为2000
          BITBTN2关闭计算器。
          BITBTN3根据EDIT内容调用计算器菜单命令。
    本程序没有错误处理,不要在在EDIT内输入文字。
    procedure TForm1.BitBtn1Click(Sender: TObject);
    var
    dir: string;
    begin   dir:='C:\WINNT\System32';//被调用程序的目录
       SetCurrentDir(dir);
       WinExec('calc.exe',SW_SHOW);//调用被调用程序
    end;procedure TForm1.BitBtn2Click(Sender: TObject);
    var
     hWnd1: HWND   ;
    begin hWnd1 := FindWindow(NiL,'计算器');
     SendMessage(hWnd1,WM_CLOSE,0,0);
    end;procedure TForm1.BitBtn3Click(Sender: TObject);
    var a,b:      integer;
    HWND1 :       hWnd ;
    HMENU1  :     HMENU  ;
    id:           UINT  ;
    begin  a:=StrToInt(Edit1.Text);
      b:=StrToInt(Edit2.Text);
      HWND1:= FindWindow(NiL,'计算器');
      hMenu1 := GetMenu(hWnd1); //hWnd是一个程序的窗口句柄
      hMenu1 := GetSubMenu(hMenu1, a); //取得第二个菜单a=1
      ID := GetMenuItemID(hMenu1, b); //取得第二个菜单的第一个菜单项b=0
      SendMessage(hWnd1, WM_COMMAND, ID, 0);
    end;end.
      

  4.   

    谢谢以上各位兄弟的回复,特别是sysu(死树) 和gfh_79_0(ghf),我会尽快试一下,尽快结帖。
      

  5.   

    sysu(死树)兄的答案已经通过,本帖结帖。请sysu(死树)兄留意我的另外一个散分帖,前来来分。