在Skype客户端通过WinAPI和Delphi查找和使用当前活动的聊天室?

在Delphi中,通过使用Skype API,我可以很容易地向联系人发送消息。 但是,我正在尝试做的是在当前重点联系人的聊天框中input消息,而不发送消息。

通过使用Winspector,我发现Chatbox的Classname是TChatRichEdit,放在TChatEntryControl上,放在TConversationForm上,最后放在tSkMainForm上。 (很明显,Skype客户端是用Delphi编码的;))

通过使用Win API,我怎样才能find正确的tSkMainForm> TConversationForm> TChatEntryControl> TChatRichEdit ,然后在其中input消息?

最好的办法是什么呢?

此外,TConversationForm也包含联系人的名称,所以我想这使得它更容易一些?

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

Winspector间谍

这是我现在的代码:

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。

这是我的IDE在debugging模式下的屏幕截图:

在调试模式下的IDE

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

有任何想法吗?

Solutions Collecting From Web of "在Skype客户端通过WinAPI和Delphi查找和使用当前活动的聊天室?"

我猜TConversationForm是一个顶级窗口。 使用EnumWindows来查找。 (不要FindWindow ;它总是返回它找到的第一个窗口,所以如果有多个对话处于活动状态,则无法控制您将获得哪个对话框。)

 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来查看联系人姓名是否出现在标题的某处; 如果任何联系人的名称是对话窗口标题的子字符串 ,则可能会在无意中找到匹配项。

进程ID不是严格要求的,所以如果你不知道进程ID,你可以省略这个部分。

EnumWindows函数将为每个顶层窗口调用一次上述函数。 如果窗口是你正在寻找的那个窗口, GetConversationWindow返回False来说:“我找到了我想要的,所以请停止询问。 否则,它返回True :“那不是,所以请给我另一个。” 如果GetConversationWindow曾经返回False ,那么EnumWindows也会返回False ,而Param.Result域将保存你正在寻找的窗口的句柄。 一旦你有了它,使用FindWindowEx浏览窗口层次结构的其余部分:

 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; 

像这样的东西:

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

那么你有一个窗口的句柄。 您可以使用WM_SETTEXT或其他东西来输入文字。 但Skype使用WM_COPYDATA与其他程序进行通信,反之亦然。 你应该为此搜索StackOverflow。