Lazarus

Programming => Operating Systems => Windows => Topic started by: Michael Collier on February 06, 2012, 08:33:45 pm

Title: Anyone know the protocol to connect to TSimpleIPCServer from c# client?
Post by: Michael Collier on February 06, 2012, 08:33:45 pm
I'd like to try to connect to a lazarus TSimpleIPCServer component from a C# client program but I don't know what the method/protocol would be for that.

I can do IPC client/server in lazarus, and I can do client/server in C# using named pipes but named pipes doesn't seem to be the way to connect to TSimpleIPCServer (or is it??)....

Has anyone here tried it with C# or know more about what TSimpleIPCServer is doing under the hood so maybe I can ask in a C# forum??..

TIA
Title: Re: Anyone know the protocol to connect to TSimpleIPCServer from c# client?
Post by: Leledumbo on February 07, 2012, 02:47:35 am
The documentation (http://www.freepascal.org/docs-html/fcl/simpleipc/index.html) doesn't mention the protocol used as well, so I guess this component aren't meant to be used from other languages. You have to dig in the source code to see it.
Title: Re: Anyone know the protocol to connect to TSimpleIPCServer from c# client?
Post by: BigChimp on February 07, 2012, 07:10:27 am
I seem to recall they use pipes on Windows... there were some troubles getting services/daemons and end user programs to communicate...

As Leledumbo said, you'd probably have to figure it out via code, but I think that if you have interprocess communication facilities, it would really help if they can be used by other languages  :D
Title: Re: Anyone know the protocol to connect to TSimpleIPCServer from c# client?
Post by: TurboRascal on February 07, 2012, 03:15:40 pm
It seems it also uses pipes for communication. You may replicate what the code does from the client source, or perhaps even simpler, just create a wrapper dll...
Title: Re: Anyone know the protocol to connect to TSimpleIPCServer from c# client?
Post by: BigChimp on October 06, 2012, 04:01:42 am
@richardalgor: so, if you have an sample C# program with a sample Lazarus TSimpleIPCServer program, that would be very nice.

Thanks,
BigChimp
Title: Re: Anyone know the protocol to connect to TSimpleIPCServer from c# client?
Post by: ludob on October 06, 2012, 10:04:42 am
SimpleIPC uses windows messaging to communicate (WM_COPYDATA). Here is a sample C# console program that writes to a FPC IPC server:
Code: [Select]
using System;
using System.Runtime.InteropServices;


namespace ConsoleApplication1
{

    class Program
    {
        [DllImport("user32.dll", SetLastError = true)]
        static extern int FindWindow(string lpClassName, string lpWindowName);
        [DllImport("user32.dll")]
        public static extern int SendMessage(int hWnd, int wMsg, int wParam, ref COPYDATASTRUCT lparam);
        public const int WM_COPYDATA = 0x4A;
        public struct COPYDATASTRUCT
        {
        public IntPtr dwData;
        public int cbData;
        [MarshalAs(UnmanagedType.LPStr)]
        public string lpData;
        }


        static int sendFPCIPCMessage(string ServerID, int MsgType, string msg)
        {
            int hWnd = FindWindow("FPCMsgWindowCls", ServerID);
            Console.WriteLine(hWnd);
            byte[] sarr = System.Text.Encoding.Default.GetBytes(msg);
            int len = sarr.Length;
            COPYDATASTRUCT cds;
            cds.dwData = (IntPtr)MsgType;
            cds.lpData = msg;
            cds.cbData = len + 1;
            return SendMessage(hWnd, WM_COPYDATA, 0, ref cds);
        }
        static void Main(string[] args)
        {
            Console.WriteLine(sendFPCIPCMessage("123", 3, "Hi from C#"));
        }
    }
}
The Console.WriteLine is just for debugging purposes. This is a test program and needs some better error checking to be useful.

To test, create a FPC program with a TSimpleIPCServer and set TSimpleIPCServer.ServerID to '123',  TSimpleIPCServer.Global to true, an OnMessage handler with
Code: [Select]
procedure TForm1.SimpleIPCServer1Message(Sender: TObject);
begin
  ShowMessage(SimpleIPCServer1.StringMessage);
end;
and start the server. Run the console app and enjoy the popup in the FPC program :)
Title: Re: Anyone know the protocol to connect to TSimpleIPCServer from c# client?
Post by: evoshroom on January 18, 2013, 02:37:24 pm
Amazingly useful.  Any chance you'd have some code receive to SimpleIPC commands for a non-console visual C# program?
Title: Re: Anyone know the protocol to connect to TSimpleIPCServer from c# client?
Post by: evoshroom on January 18, 2013, 06:06:39 pm
Going to try to implement this and hope it is compatible...*fingers crossed*

http://msdn.microsoft.com/en-us/library/system.runtime.remoting.channels.ipc.ipcserverchannel.aspx (http://msdn.microsoft.com/en-us/library/system.runtime.remoting.channels.ipc.ipcserverchannel.aspx)

I got your demo working like a dream in my C# project and this is the first time I've even seen C# code.  I'm an OS X developer!
Title: Re: Anyone know the protocol to connect to TSimpleIPCServer from c# client?
Post by: evoshroom on January 18, 2013, 06:55:51 pm
Actually, looking more into it IpcServerChannel Class is both wrong and overkill.  It receives messages using SOAP.  The Windows version of SimpleIPC uses WM_COPYDATA so something like this http://stackoverflow.com/questions/1633501/receive-wm-copydata-struct-in-wpf-or-console-c-sharp-app (http://stackoverflow.com/questions/1633501/receive-wm-copydata-struct-in-wpf-or-console-c-sharp-app) or this http://forums.devshed.com/c-programming-42/using-wm-copydata-to-send-message-from-c-to-c-553567.html (http://forums.devshed.com/c-programming-42/using-wm-copydata-to-send-message-from-c-to-c-553567.html) is more on-track.
Title: Re: Anyone know the protocol to connect to TSimpleIPCServer from c# client?
Post by: evoshroom on January 18, 2013, 10:17:22 pm
So I tried taking the code here:

http://msdn.microsoft.com/en-us/library/system.windows.forms.nativewindow.aspx

And then I changed:

Code: [Select]
cp.Caption = "Click here";
cp.ClassName = "Button";

to

Code: [Select]
cp.Caption = "321";
cp.ClassName = "FPCMsgWindowCls";

The above class name I gathered both from the working C# code above and from: https://github.com/graemeg/freepascal/blob/master/packages/fcl-process/src/win/simpleipc.inc (https://github.com/graemeg/freepascal/blob/master/packages/fcl-process/src/win/simpleipc.inc)

Then I replaced the included "protected override void WndProc(ref Message m)" with

Code: [Select]
  public const int WM_COPYDATA = 0x4A;
        public struct COPYDATASTRUCT
        {
            public IntPtr dwData;
            public int cbData;
            [MarshalAs(UnmanagedType.LPStr)]
            public string lpData;
        }
        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
            case WM_COPYDATA:
                COPYDATASTRUCT mystr = new COPYDATASTRUCT();
                Type mytype = mystr.GetType();
                mystr = (COPYDATASTRUCT)m.GetLParam(mytype);
                MessageBox.Show(mystr.lpData);
                break;
            }
            base.WndProc(ref m);
        }

I also set my SimpleIPCClient in my Lazarus program to ServerID 321 and set it up to connect like normal.  It never connected though.  I'm completely new at C#, so I'm not sure if that is because of my day one C#'s skills or something I missed.  Anyone a bilingual Object Pascal/C# speaker?
Title: Re: Anyone know the protocol to connect to TSimpleIPCServer from c# client?
Post by: evoshroom on January 18, 2013, 11:31:52 pm
Well back to the path of least resistance.  If any C# guru's out there code a SimpleIPCClient-compatible C# implementation toss it in this thread in the future.  In the meantime, a SimpleIPCServer and this code to act as a substitute for a client will work:

Lazarus:
Code: [Select]
var
  aCopyData: TCopyDataStruct;
  hTargetWnd: HWND;
begin
  with aCopyData do
  begin
    dwData := 0;
    cbData := StrLen(PChar('test')) + 1;
    lpData := PChar('test')
  end;
  // Search window by the window title
  hTargetWnd := FindWindowEx(0, 0, nil, PChar('AppTitleBar'));
  if hTargetWnd <> 0 then
    SendMessage(hTargetWnd, WM_COPYDATA, Longint(Handle), Longint(@aCopyData))
  else
    ShowMessage('No Recipient found!');

C#:
Code: [Select]
        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case WM_COPYDATA:
                    COPYDATASTRUCT mystr = new COPYDATASTRUCT();
                    Type mytype = mystr.GetType();
                    mystr = (COPYDATASTRUCT)m.GetLParam(mytype);
                    MessageBox.Show(mystr.lpData);
                    break;
            }
            base.WndProc(ref m);
Title: Re: Anyone know the protocol to connect to TSimpleIPCServer from c# client?
Post by: BigChimp on January 19, 2013, 11:07:55 am
Looks like you've been busy, evoshroom!

If you're just looking for a GUI version of ludob's console example, I've tried to come up with one (not a C# coder but have some VB.Net experience).
Haven't tested it with a server, but it compiles and runs...
Title: Re: Anyone know the protocol to connect to TSimpleIPCServer from c# client?
Post by: evoshroom on January 19, 2013, 02:44:11 pm
Looks like you've been busy, evoshroom!

If you're just looking for a GUI version of ludob's console example, I've tried to come up with one (not a C# coder but have some VB.Net experience).
Haven't tested it with a server, but it compiles and runs...

Oh, no, I'm not looking for a GUI version of ludob's console example.  I have his console example working in my GUI C# program already.  That only took a few minutes.  However, his example only goes in one direction:

C# program to Lazarus program (TSimpleIPCServer)

I was looking for the other way as well:

Lazarus program (TSimpleIPCClient) to C# program

If you go in the other direction it seemed to me that you need to override the classname of a C# form to be called "FPCMsgWindowCls" and that was where most of the difficulty was.
Title: Re: Anyone know the protocol to connect to TSimpleIPCServer from c# client?
Post by: BigChimp on January 19, 2013, 02:46:48 pm
Seems I misunderstood you then.

Having to modify a form (GUI!) class name seems weird though.
Title: Re: Anyone know the protocol to connect to TSimpleIPCServer from c# client?
Post by: evoshroom on January 19, 2013, 03:11:01 pm
Seems I misunderstood you then.

Having to modify a form (GUI!) class name seems weird though.

From my understanding that's because on Windows TSimpleIPCClient carries an assumption that it is talking to a TSimpleIPCServer.  The ServerID is the Form Title for the FindWindowEx(hwndParent, hwndChildAfter, lpszClass, lpszWindow) and the form class is FPCMsgWindowCls, but I should do some searches in that source I linked for FindWindowEx, as I didn't confirm all of that, it just seemed naturally to follow from some of the assumptions made elsewhere and Windows API calls.
Title: Re: Anyone know the protocol to connect to TSimpleIPCServer from c# client?
Post by: evoshroom on January 19, 2013, 07:03:54 pm
Was out for most of the morning and just had a chance to review the source.  Yeah, so TSimpleIPCClient just uses standard API calls on Windows but it has some hardcoded assumptions that make having it communicate cross-language a little annoying.

Namely it connects through this procedure:

Code: [Select]
procedure TWinMsgClientComm.Connect;
begin
  FHWND:=FindWindow(MsgWndClassName,PChar(FWindowName));
  If (FHWND=0) then
    Owner.DoError(SErrServerNotActive,[Owner.ServerID]);
end;

You see FindWindow only has two parameters: The Window Class and the Window Name.  The window name is easy to modify in any language, including C#.  However, the Window Class is hard to modify in many languages.  From reading elsewhere, I believe the Window Name ends up corresponding to the TSimpleIPCClient.ServerID.  However there is no corresponding property for the Window Class.  It is hardcoded in simpleipc.inc as:

Code: [Select]
Const
  MsgWndClassName : pchar = 'FPCMsgWindowCls';

So most of the challenge is coding a window in another language with a custom class name which is then set to 'FPCMsgWindowCls'. 

Really, it sort of almost makes more sense long term to change the SimpleIPCClient to add a new property for 'LanguageID' or something and set it to FPCMsgWindowCls by default, so it can be more easily adapted to talking to other languages.
Title: Re: Anyone know the protocol to connect to TSimpleIPCServer from c# client?
Post by: BigChimp on January 19, 2013, 08:47:16 pm
So most of the challenge is coding a window in another language with a custom class name which is then set to 'FPCMsgWindowCls'. 

Really, it sort of almost makes more sense long term to change the SimpleIPCClient to add a new property for 'LanguageID' or something and set it to FPCMsgWindowCls by default, so it can be more easily adapted to talking to other languages.
Ok, thanks.

Haven't looked at the source code - but:
1. I wonder if manipulating a form class name in .Net maps to the class name the FPC client wants (presumably some kind of Windows API construct).
2. Are you talking about the FPC version, not a Lazarus version of the simple IPC client? I'm wondering whether Lazarus adds some Windows API sauce to look up the server etc.

As I said, I haven't looked at the ipc server source, which I really should if I was to give more definitive answers but perhaps this is food for thought...
Title: Re: Anyone know the protocol to connect to TSimpleIPCServer from c# client?
Post by: evoshroom on January 19, 2013, 08:54:54 pm
Code: [Select]
2. Are you talking about the FPC version, not a Lazarus version of the simple IPC client? I'm wondering whether Lazarus adds some Windows API sauce to look up the server etc.
Again, source is here: http://code.google.com/p/upas/source/browse/trunk/3rd/fpc/fcl-process/src/simpleipc.inc?r=11 (http://code.google.com/p/upas/source/browse/trunk/3rd/fpc/fcl-process/src/simpleipc.inc?r=11)

Lazarus is looking up the window handle using FindWindow().  FindWindow() *is* WinAPI.
Title: Re: Anyone know the protocol to connect to TSimpleIPCServer from c# client?
Post by: BigChimp on January 20, 2013, 09:52:31 am
Yes, or here:
http://svn.freepascal.org/svn/fpc/trunk/packages/fcl-process/src/win/simpleipc.inc (http://svn.freepascal.org/svn/fpc/trunk/packages/fcl-process/src/win/simpleipc.inc)

"Lazarus is looking up the window handle using FindWindow().  FindWindow() *is* WinAPI."
Yes, I was wondering whether this usage of windows handles was in the FPC part or in the Lazarus wrapper. Having looked it's in the FPC part (as you already know).

Don't know if you've found/linked this already but the second answer in this page looks promising:
http://stackoverflow.com/questions/128561/registering-a-custom-win32-window-class-from-c-sharp
(Note: there might be a much easier way, perhaps your attempt at specifying a custom class name would be enough perhaps not)

I'll leave others to help here, my .Net knowledge has run out.
TinyPortal © 2005-2018