Finding & using the currently active Chatbox in the Skype Client thru the WinAPI & Delphi?

别说谁变了你拦得住时间么 提交于 2019-11-29 12:03:55

I guess TConversationForm is a top-level window. Use EnumWindows to find that. (Don't bother with FindWindow yet; it always returns the first window it finds, so if there are multiple conversations active, you have no control over which you'll get.)

type
  PGetConversationParam = ^TGetConversationParam;
  TGetConversationParam = record
    ProcID: DWord;
    ContactName: string;
    Result: HWnd;
  end;

function GetConversationWindow(Wnd: HWnd; P: LParam): Bool; stdcall;
var
  Param: PGetConversationParam;
  ProcID: DWord;
  // WndClass docs say maximum class-name length is 256.
  ClassName: array[0..256] of Char;
  WindowTitle: array[0..256] of Char;
begin
  Result := True; // assume it doesn't match; keep searching
  Param := PGetConversationParam(P);

  GetWindowThreadProcessID(Wnd, @ProcID);
  if ProcID <> Param.ProcID then
    Exit;

  if GetClassName(Wnd, ClassName, Length(ClassName)) = 0 then
    Exit;
  if StrComp(ClassName, 'TConversationForm') <> 0 then
    Exit;

  if SendMessage(Wnd, wm_GetText, Length(WindowTitle), LParam(@WindowTitle[0])) = 0 then
    Exit;
  if Param.ContactName = WindowTitle then begin
    Param.Result := Wnd;
    Result := False;
  end;
end;

That function checks several things to make sure it's looking at the desired window. It checks that the window belongs to the Skype process, that it has the expected window class, and that its title is the name of the target contact. If Skype puts additional text in the window title, you'll need to make sure it looks "close enough." Don't just call Pos to see whether the contact name appears somewhere in the title; if any contact has a name that's a substring of the a conversation window's title, you might inadvertently find a match when you shouldn't.

The process ID isn't strictly required, so you can omit that part if you don't know the process ID.

The EnumWindows function will call the above function once for each top-level window. If the window is the one you're looking for, GetConversationWindow returns False to say, "I've found what I want, so please stop asking about any more." Otherwise, it returns True: "That one wasn't it, so please give me another." If GetConversationWindow ever returns False, then EnumWindows will also return False and the Param.Result field will hold the handle of the window you were looking for. Once you have it, use FindWindowEx to navigate the rest of the window hierarchy:

var
  Param: TGetConversationParam;
begin
  Param.ProcID := GetSkypeProcessID;
  Param.ContactName := GetSkypeContactName;
  if EnumWindows(@GetConversationWindow, LParam(@Param)) then
    Abort; // Didn't find it.

  // Param.Result holds the conversation window's handle. Now walk its children.
  ControlWnd := FindWindowEx(Param.Result, 0, 'TChatEntryControl', nil);
  if ControlWnd = 0 then
    Abort; // Conversation doesn't have an entry control

  RichEditWnd := FindWindowEx(ControlWnd, 0, 'TChatRichEdit', nil);
  if RichEditWnd = 0 then
    Abort;

  // Voila!
end;

Something like this:

var
  aHandle   : cardinal;
begin
   aHandle := FindWindow(PWideChar('TChatRichEdit'), nil);
   result  := aHandle <> 0;
   if result then
      PostMessage(aHandle, WM_...); 

Then you have a handle of that window. You can use WM_SETTEXT or something to input text. But Skype uses WM_COPYDATA to communicate with other programs, and vice versa. You should search StackOverflow for that.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!