Recent

Author Topic: Skype protocol problem  (Read 16702 times)

Dibo

  • Hero Member
  • *****
  • Posts: 1048
Skype protocol problem
« on: July 22, 2010, 03:15:36 pm »
Hi,

I'm traying rewrite this code to lazarus:
http://developer.skype.com/delphi-examples/wintracer-pas

The first problem was a procedure Application.HookMainWindow which is not in Lazarus. I found solution here:
http://wiki.lazarus.freepascal.org/Win32/64_Interface#Processing_non-user_messages_in_your_window
But I had to comment out the first block (with WM_NCHITTEST) because I could not change the location of the main window of my plugin. Is this something harmful?
Now, my plugin connects to Skype and communicates with him, but I have problem with line:
Code: [Select]
RecvCommand(PChar(PCopyDataStruct(Msg.LParam).lpData));I do not know how to get to this content with the incoming parameters and I have doubt to this comment: "Setting the Msg.Result is important here, to notify Skype that the message has been processed"
This is my all code:
Code: [Select]
var
  PrevWndProc: WNDPROC;
  MsgAttach: LongWord;
  MsgDiscover: LongWord;
  SkypeWindowHandle: HWND;

implementation

Procedure RecvCommand(Cmd: string);

Begin
  MainForm.Memo1.Lines.Add('-> ' + Cmd);
End;

Procedure SendCommand(Cmd: string);

Var CopyData : CopyDataStruct;
    StrBuff  : Array [0..1023] of Char;
    I        : Integer;

Begin
  if SkypeWindowHandle = 0 Then Exit;

  CopyData.dwData := 0;
  CopyData.cbData := Length(Cmd) + 1;
  CopyData.lpData := @StrBuff;

  for I := 1 to CopyData.cbData do StrBuff[I-1] := Cmd[I];
  StrBuff[CopyData.cbData] := #00;

  SendMessage(SkypeWindowHandle, WM_COPYDATA, Application.MainForm.Handle, LPARAM(@CopyData));
End;

function SkypeProcessMessages(Ahwnd: HWND; uMsg: UINT; wParam: WParam; lParam: LParam):LRESULT; stdcall;
begin
  {if uMsg=WM_NCHITTEST then
  begin
    result:=Windows.DefWindowProc(Ahwnd, uMsg, WParam, LParam);  //not sure about this one
    if result=windows.HTCAPTION then result:=windows.HTCLIENT;
    exit;
  end; }

  // MsgAttach sort of message. This we will get as resoponse from Skype
  // to MsgDiscover broadcast. WParam will contain Skype API window handle
  // (which is not necessarily Skype's UI main window handle). That handle
  // we can use to send further messages directly to Skype, instead of
  // broadcasting. LParam will contain current handshake status code.
  if (uMsg = MsgAttach) Then
  Begin
    SkypeWindowHandle := wParam;
    Case lParam  of
      0 : Begin
            MainForm.Memo1.Lines.Add('** Attach success');
            SendCommand('protocol 999');
            SendCommand('get skypeversion');
          End;
      1 : MainForm.Memo1.Lines.Add('** Attach pending');
      2 : MainForm.Memo1.Lines.Add('** Attach refused');
      3 : MainForm.Memo1.Lines.Add('** Attach unavailable');
    End;
    //Result := True;
    Exit;
  End;

  // Here we have recieved a notification message from Skype.
  if (uMsg = WM_COPYDATA) and (HWND(wParam) = SkypeWindowHandle) Then
  Begin
    // The LParam contains a pointer to a TCopyDataStruct record.
    // lpData field of that record conatins pointer to a null-terminated string.
    // Through typecasting, we will pass that string to our RecvCommand procedure,
    // where further processing can take place.
    //RecvCommand(PChar(PCopyDataStruct(Msg.LParam).lpData));

    // Setting the Msg.Result is important here, to notify Skype that the
    // message has been processed.
    //Msg.Result := 1;
    //Result := true;
    Exit;
  End;

  result:=CallWindowProc(PrevWndProc,Ahwnd, uMsg, WParam, LParam);
end;


{ TMainForm }

procedure TMainForm.OnCreate;
begin
  SkypeWindowHandle := 0;

  // Here we will get back message type IDs
  MsgAttach   := RegisterWindowMessage('SkypeControlAPIAttach');
  MsgDiscover := RegisterWindowMessage('SkypeControlAPIDiscover');

  // ProcessMessage will handle incoming messages from Skype client
  //Application.HookMainWindow(ProcessMessages);
  PrevWndProc:=Windows.WNDPROC(SetWindowLong(Application.MainForm.Handle,GWL_WNDPROC,PtrInt(@SkypeProcessMessages)));

  // Broadcasting all over the system that this application wants to
  // attach itself to Skype public API. Response from Skype will be
  // handled in ProcessMessages.
  PostMessage(HWND_BROADCAST, MsgDiscover, Application.MainForm.Handle, 0);
end; 

Regards.

Marc

  • Administrator
  • Hero Member
  • *
  • Posts: 2582
Re: Skype protocol problem
« Reply #1 on: July 23, 2010, 12:49:48 am »
The members of the Msg struct are passed to SkypeProcessMessages(..)

So where you read Msg.lParam, use lParam so
Code: Pascal  [Select][+][-]
  1. RecvCommand(PChar(PCopyDataStruct(Msg.LParam).lpData));
will become
Code: Pascal  [Select][+][-]
  1. RecvCommand(PChar(PCopyDataStruct(LParam).lpData));

The result of SkypeProcessMessages(..) will become Msg.Result, so
Code: Pascal  [Select][+][-]
  1. Msg.Result := 1;
becomes
Code: Pascal  [Select][+][-]
  1. Result := 1;

About SendCommand: since Cmd and StrBuf are only valid in SendCommand and you are using SemdMessage(..) to send the data, there is no need to copy it. Use PChar(cmd) to cast it (pascal strings do have a null terminator by default so no need to append)

Code: Pascal  [Select][+][-]
  1. procedure SendCommand(const Cmd: string);
  2. var
  3.   CopyData : CopyDataStruct;
  4. begin
  5.   if SkypeWindowHandle = 0 Then Exit;
  6.  
  7.   CopyData.dwData := 0;
  8.   CopyData.cbData := Length(Cmd) + 1;
  9.   CopyData.lpData := PChar(Cmd);
  10.   SendMessage(SkypeWindowHandle, WM_COPYDATA, Application.MainForm.Handle, LPARAM(@CopyData));
  11. end;
  12.  
« Last Edit: July 23, 2010, 12:51:34 am by Marc »
//--
{$I stdsig.inc}
//-I still can't read someones mind
//-Bugs reported here will be forgotten. Use the bug tracker

Dibo

  • Hero Member
  • *****
  • Posts: 1048
Re: Skype protocol problem
« Reply #2 on: July 23, 2010, 01:48:56 pm »
Thanks! Now it works. I wonder if I can get the same thing for linux version of Skype :P

P.S. I must use this:
Code: Pascal  [Select][+][-]
  1. RecvCommand(PChar(PCopyDataStruct(LParam)^.lpData));
instead of:
Code: Pascal  [Select][+][-]
  1. RecvCommand(PChar(PCopyDataStruct(LParam).lpData));
Because they did not want to compile.

P.S.2: @Marc, how did you add pascal "CODE" formatting in yout post?
« Last Edit: July 23, 2010, 03:36:04 pm by Dibo »

theo

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1927
Re: Skype protocol problem
« Reply #3 on: July 23, 2010, 02:26:39 pm »
P.S.2: @Marc, how did you add pascal "CODE" formatting in yout post?

Click on "quote", then you see the source.
code=pascal
Imho, this should be set as default.

Dibo

  • Hero Member
  • *****
  • Posts: 1048
Re: Skype protocol problem
« Reply #4 on: July 23, 2010, 05:20:24 pm »
Thanks theo

I have other problem. Now I want to collect all functions in one object TSkypePlugin but I have AV SIGSEGV in SkypeProcessMessages procedure (this is not possible to debug - to much messages). Is the reason is that the procedure SkypeProcessMessages STDCALL is posted on the inside of the object? When I called her from the outside, then it works.

Marc

  • Administrator
  • Hero Member
  • *
  • Posts: 2582
Re: Skype protocol problem
« Reply #5 on: July 24, 2010, 03:31:10 am »
Is the reason is that the procedure SkypeProcessMessages STDCALL is posted on the inside of the object?

what do you mean by inside/outside ?
is SkypeProcessMessages part of an object ? This is not possible.
//--
{$I stdsig.inc}
//-I still can't read someones mind
//-Bugs reported here will be forgotten. Use the bug tracker

Dibo

  • Hero Member
  • *****
  • Posts: 1048
Re: Skype protocol problem
« Reply #6 on: July 24, 2010, 10:44:58 am »
Yes, it is in private section of object

Marc

  • Administrator
  • Hero Member
  • *
  • Posts: 2582
Re: Skype protocol problem
« Reply #7 on: July 26, 2010, 08:30:20 pm »
If it is used as a callback (what a messagehandler is), you cannot pass methods, only "plain" functions.
//--
{$I stdsig.inc}
//-I still can't read someones mind
//-Bugs reported here will be forgotten. Use the bug tracker

Dibo

  • Hero Member
  • *****
  • Posts: 1048
Re: Skype protocol problem
« Reply #8 on: July 26, 2010, 08:56:25 pm »
Ok. Too bad that Lazarus does not have any function HookMainWindow.

kenpem

  • New Member
  • *
  • Posts: 22
Re: Skype protocol problem
« Reply #9 on: June 21, 2012, 12:12:43 pm »
Old topic, I know, but hoping the OP has it on a watch-list!

Was there success on this project in the end? I have a small job coming up that would greatly benefit from a small amount of Skype integration (i.e. being able to post occasional messages to a group chat). I know that there are published APIs and interface units and libraries for Delphi, but Embarcadaro have done their very best to p**s me off recently, so I'm not inclined to go down that route, especially for what will essentially be a one-off - I'd far rather stick with Lazarus, which is doing everything else I need it to do, and has a much richer support community.

bigbo

  • New member
  • *
  • Posts: 8
Re: Skype protocol problem
« Reply #10 on: September 24, 2012, 09:24:17 pm »
It seems I was very careful to make same code as above.
The code is possible to compile but it's not working at all.
When I try to run it, I got the message "Exception External Class: SIGSEGV at address 774715DE" (Somehow like this because there different language)

Debugger shows this point in wincontrol.inc:

Code: Pascal  [Select][+][-]
  1. {------------------------------------------------------------------------------
  2.   function: TWinControl.HandleAllocated
  3.   Params:   None
  4.   Returns:  True is handle is allocated
  5.  
  6.   Checks if a handle is allocated. I.E. if the control is mapped
  7.  ------------------------------------------------------------------------------}
  8. function TWinControl.HandleAllocated : Boolean;
  9. begin
  10.  HandleAllocated := (FHandle <> 0); //HERE!!
  11. end;                                
  12.  

The fail going from procedure onCreate, this string -
PrevWndProc:=Windows.WNDPROC(SetWindowLong(Application.MainForm.Handle,GWL_WNDPROC,PtrInt(@SkypeProcessMessages)));

I not so strong with this kind of programming, just I need to rewrite one of my project from Delphi to Lazarus.
This is the code, which I wrote.

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. Uses
  8.    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  9.    Dialogs, StdCtrls;
  10.  
  11. Type
  12.  
  13.    { TMainForm }
  14.  
  15.    TMainForm = Class(TForm)
  16.      Memo1: TMemo;
  17.      Edit1: TEdit;
  18.      Procedure Edit1KeyPress(Sender: TObject; var Key: Char);
  19.      procedure onCreate(Sender: TObject);
  20.    Private
  21.      //Function  SkypeProcessMessages(Ahwnd: HWND; uMsg: UINT; wParam: WParam; lParam: LParam):LRESULT; stdcall;
  22.      //Procedure SendCommand (Cmd : String);
  23.      //Procedure RecvCommand (Cmd : String);
  24.    End;
  25.  
  26. var
  27.   MainForm: TMainForm;
  28.  
  29. var
  30.   PrevWndProc: WNDPROC;
  31.   MsgAttach: LongWord;
  32.   MsgDiscover: LongWord;
  33.   SkypeWindowHandle: HWND;
  34.  
  35. implementation
  36.  
  37. {$R *.lfm}
  38.  
  39. { TMainForm }
  40. Procedure RecvCommand(Cmd: string);
  41.  
  42. Begin
  43.   MainForm.Memo1.Lines.Add('-> ' + Cmd);
  44. End;
  45.  
  46. Procedure SendCommand(Cmd: string);
  47.  
  48. var
  49.   CopyData : CopyDataStruct;
  50. begin
  51.   if SkypeWindowHandle = 0 Then Exit;
  52.  
  53.   CopyData.dwData := 0;
  54.   CopyData.cbData := Length(Cmd) + 1;
  55.   CopyData.lpData := PChar(Cmd);
  56.   SendMessage(SkypeWindowHandle, WM_COPYDATA, Application.MainForm.Handle, LPARAM(@CopyData));
  57. End;
  58.  
  59. function SkypeProcessMessages(Ahwnd: HWND; uMsg: UINT; wParam: WParam; lParam: LParam):LRESULT; stdcall;
  60. begin
  61.   //if uMsg=WM_NCHITTEST then
  62.   //begin
  63.   //  result:=Windows.DefWindowProc(Ahwnd, uMsg, WParam, LParam);  //not sure about this one
  64.   //  if result=windows.HTCAPTION then result:=windows.HTCLIENT;
  65.   //  exit;
  66.   //end;
  67.  
  68.   // MsgAttach sort of message. This we will get as resoponse from Skype
  69.   // to MsgDiscover broadcast. WParam will contain Skype API window handle
  70.   // (which is not necessarily Skype's UI main window handle). That handle
  71.   // we can use to send further messages directly to Skype, instead of
  72.   // broadcasting. LParam will contain current handshake status code.
  73.   if (uMsg = MsgAttach) Then
  74.   Begin
  75.     SkypeWindowHandle := wParam;
  76.     Case lParam  of
  77.       0 : Begin
  78.             MainForm.Memo1.Lines.Add('** Attach success');
  79.             SendCommand('protocol 999');
  80.             SendCommand('get skypeversion');
  81.           End;
  82.       1 : MainForm.Memo1.Lines.Add('** Attach pending');
  83.       2 : MainForm.Memo1.Lines.Add('** Attach refused');
  84.       3 : MainForm.Memo1.Lines.Add('** Attach unavailable');
  85.     End;
  86.     Result := 1;
  87.     Exit;
  88.   End;
  89.  
  90.   // Here we have recieved a notification message from Skype.
  91.   if (uMsg = WM_COPYDATA) and (HWND(wParam) = SkypeWindowHandle) Then
  92.   Begin
  93.     // The LParam contains a pointer to a TCopyDataStruct record.
  94.     // lpData field of that record conatins pointer to a null-terminated string.
  95.     // Through typecasting, we will pass that string to our RecvCommand procedure,
  96.     // where further processing can take place.
  97.     RecvCommand(PChar(PCopyDataStruct(LParam)^.lpData));
  98.  
  99.     // Setting the Msg.Result is important here, to notify Skype that the
  100.     // message has been processed.
  101.     //Msg.Result := 1;
  102.     Result := 1;
  103.     Exit;
  104.   End;
  105.  
  106.   result:=CallWindowProc(PrevWndProc,Ahwnd, uMsg, WParam, LParam);
  107. end;
  108.  
  109. { TMainForm }
  110.  
  111.  
  112. procedure TMainForm.Edit1KeyPress(Sender: TObject; var Key: char);
  113. begin
  114.   if Key = #13 then
  115.     Begin
  116.       Memo1.Lines.Add('<- ' + Edit1.Text);
  117.       SendCommand(Edit1.Text);
  118.       Edit1.Clear;
  119.     End;
  120. end;
  121.  
  122. procedure TMainForm.onCreate(Sender: TObject);
  123. begin
  124.     SkypeWindowHandle := 0;
  125.  
  126.   // Here we will get back message type IDs
  127.   MsgAttach   := RegisterWindowMessage('SkypeControlAPIAttach');
  128.   MsgDiscover := RegisterWindowMessage('SkypeControlAPIDiscover');
  129.  
  130.   // ProcessMessage will handle incoming messages from Skype client
  131.   //Application.HookMainWindow(ProcessMessages);
  132.   PrevWndProc:=Windows.WNDPROC(SetWindowLong(Application.MainForm.Handle,GWL_WNDPROC,PtrInt(@SkypeProcessMessages)));
  133.  
  134.   // Broadcasting all over the system that this application wants to
  135.   // attach itself to Skype public API. Response from Skype will be
  136.   // handled in ProcessMessages.
  137.   PostMessage(HWND_BROADCAST, MsgDiscover, Application.MainForm.Handle, 0);
  138. end;
  139. end.
  140.  
  141.  

I asking for help. Why the code is not working?

I use:
Lazarus 1.0 x32
FPC 2.6.0
Win7 (x64)

PS Excuse me for my English. :)

 

TinyPortal © 2005-2018