寻找&使用Skype客户端中当前活动的Chatbox通过WinAPI&德尔福? [英] Finding & using the currently active Chatbox in the Skype Client thru the WinAPI & Delphi?

查看:159
本文介绍了寻找&使用Skype客户端中当前活动的Chatbox通过WinAPI&德尔福?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Delphi中,通过使用Skype API,我可以很容易地向联系人发送消息。但是,我想要做的是在当前关注的联系人的聊天框中输入消息,而不发送消息。

In Delp by using the Skype API, I can send a message to a contact fairly easy. However, what I am trying to do, is enter the message in the Chat Box of the currently focused Contact, without sending the message.

通过使用Winspector,我发现Chatbox的Classname是TChatRichEdit,它放置在TChatEntryControl上,该控件放置在TConversationForm上,最后放在tSkMainForm上。 (显然Skype客户端是用Delphi编码的))

By using Winspector, I found that the Classname of the Chatbox is TChatRichEdit, which is placed on a TChatEntryControl, which is placed on a TConversationForm, and finally, which is placed on the tSkMainForm. (Obviously the Skype Client is coded in Delphi ;) )

通过使用Win API,我如何找到正确的 tSkMainForm> TConversationForm> TChatEntryControl> TChatRichEdit ,然后输入一个信息?

By using the Win API, how can I find the correct tSkMainForm>TConversationForm>TChatEntryControl>TChatRichEdit, and then enter a message into it?

最好的方法是什么?

另外,TConversationForm还包含联系人的名字,所以我想这会更容易吗?

Also, the TConversationForm contains the name of the contact aswell, so I guess that makes it a bit easier?

编辑:这是Windspector Spy的屏幕截图,显示TChatRichEdit:

Here is a screenshot of Windspector Spy, showing the TChatRich

这是我现在的代码:

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;



procedure TForm1.Button1Click(Sender: TObject);
var
  Param: TGetConversationParam;
  RichEditWnd, ControlWnd : HWND;
  ParentWnd : HWND;
begin
  //Param.ProcID := GetSkypeProcessID;
  Param.ContactName := 'xSky Admin';
  ParentWnd := FindWindowEx(0,0,'tSkMainForm',nil);

  if EnumChildWindows(ParentWnd,@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;

  ShowMessage('Got it!');
end;

我从未到达ShowMessage。

I never reach the ShowMessage.

以下是调试模式下IDE的屏幕截图:

Here is a screenshot of my IDE in Debug Mode:

我在中断线上添加了一个断点。

I added a breakpoint at the Abort Line.

任何想法? p>

Any ideas?

推荐答案

我猜 TConversationForm 是一个顶级窗口。使用 EnumWindows 来查找。 (不要打扰 FindWindow ,它总是返回它找到的第一个窗口,所以如果有多个会话活动,你无法控制你会得到什么。 )

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;

该函数检查几件事情,以确保它正在查看所需的窗口。它检查窗口属于Skype进程,它具有预期的窗口类,它的标题是目标联系人的名称。如果Skype在窗口标题中添加了其他文本,则需要确保它看起来足够接近。不要仅仅调用 Pos 来查看联系人姓名是否出现在标题的某个位置;如果任何联系人的姓名是对话窗口标题的子字符串,您可能会无意中找到匹配项。

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.

过程ID不是严格要求的,所以如果您不知道进程ID,可以省略该部分。

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

EnumWindows 函数将为每个顶级窗口调用上述函数一次。如果窗口是您正在寻找的窗口, GetConversationWindow 返回 False 说:我找到了我想要的,所以请停止再询问一下。否则,它返回 True :那不是,所以请给我另一个。如果 GetConversationWindow 返回 False ,那么 EnumWindows 也将返回 False Param.Result 字段将保存您要查找的窗口的句柄。一旦你拥有它,使用 FindWindowEx 导航窗口层次结构的其余部分:

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;

这篇关于寻找&amp;使用Skype客户端中当前活动的Chatbox通过WinAPI&amp;德尔福?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆