Announcement

Collapse
No announcement yet.

sendMessage from a .Net App

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • sendMessage from a .Net App

    OK, I am stuck . I am trying to talk to RR from a C# application. I want to use sendMessage but I am stuck. sendMessage uses stuff that is unsafe in .Net and also has some pointer data which is a nightmare for me to code. I've looked at the Delphi & VB6 examples and this is as close as I can get the code in C#. So my questions are:

    1. Has anyone written sendMessage for RR in a .Net language?

    2. Guino, is it possible to create a new method that is easier for me to use than sendMesssage.


    Code:
    ...
    
    [StructLayout(LayoutKind.Sequential)]
    	public class COPYDATASTRUCT
    	{
    		public int dwData = 0;//32 bit int to passed. Not used.
    		public int cbData = 0;//length of string. Will be one greater because of null termination.
    		public IntPtr lpData;//string to be passed.
    
    		public COPYDATASTRUCT()
    		{
    		}
    
    		public COPYDATASTRUCT(string Data)
    		{
    			lpData = Data + "/0";   //add null termination
    			cbData = lpData.Length; //length includes null chr so will be one greater
    		}
    	}
    ...
    
    
    [DllImport("User32.dll")] public static extern IntPtr SendMessage( int hwnd, int uMsg, int wParam, COPYDATASTRUCT lParam);
    		
    [DllImport("user32.dll") ]	static extern int FindWindow (string lpClassName,string WindowName);
    
    private static int _messageID = 1163005939;
    		public const int WM_COPYDATA = 0x4A;
    
    		public void PluginSendMessage(string windowname, string className, string message)
    		{
    			
    			int hWnd;
    
    				
    			hWnd = FindWindow ("ThunderRT6FormDC","RoadRunner");
    
    
    			SendMessage(hWnd, WM_COPYDATA, 0, new COPYDATASTRUCT(message));
    			
    	
    		}

    One solution I thought of was to write a DLL in Delphi or VB6 using the slightly modified example code. Then I can add this DLL to the .Net app ad call the DLL to make the sendMessage code. But I don't have Delphi or VB6 tools to create the DLL. Can someone thrash together a small DLL with two public methods:

    int winHandler = FindWindow(string lpClassName,string WindowName)
    SendMessage(int winHandler, string message)

    With this DLL I can call RR or any other App that uses sendMessage.

    All help on this is greatly appreciated! I'm stuck

  • #2
    Updated.

    Comment


    • #3
      dwdata Must be 1 (one=string) for it to work... when you can't declare a simple struct type in a language, I truly believe things have blown up to hell ..

      optionally, you can send any command to RR by finding the active (displayed) window and simulating keypresses into it like: "PLAY" or "NEXT" (including quotes). but if you're not detailed enough to select RR's window, it may end up sending keypresses to other applications you don't want to..

      PS: It's not possible to make a DLL to perform what you want because in VB you must compile the application with the appropriate window name or it won't be effective to receive any incomming messages.
      Ride Runner RR's Myspace

      "Being happy is not about having what you want, it's about wanting what you have."
      "The best things in life are always free - but that doesn't mean money can't buy you good things."

      Comment


      • #4
        Yesssss! Guino you are a star! Changing it to a 1 fixed it.

        C# is an OK language it just likes to make native Windows stuff really nasty to code. It gives little joy when needing Win32 APIs, like sendMessage. If anyone want the stub code I've written in C# use sendMessage with RR PM me.

        -Ruairi

        Comment


        • #5
          If you can make a simple example code (like the SDK example) to send/receive messages, I'd like to add it to RR sources (as example).
          Ride Runner RR's Myspace

          "Being happy is not about having what you want, it's about wanting what you have."
          "The best things in life are always free - but that doesn't mean money can't buy you good things."

          Comment


          • #6
            I'll tidy up that class, it has lost of junk in there right now. I'll PM it to you and add a simple Visual Studio solution test app. It will be Monday before I get it done.

            Cheers again!

            Comment


            • #7
              Does anyone want to help me debug this? I'm doing something similar.. My problem is i see a few examples where lpData is an Int and some where it is an IntPtr. I don't know what to send to SendMessage. When i use IntPtr and change the datatype of VarPtr from Int to IntPtr, the message is sent but doesn't do anything. When i change everything to an Int, i don't force any datatypes, but i get the error:

              A call to PInvoke function 'WindowsApplication2!WindowsApplication2.Form1::Se ndMessage' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
              Code:
              public partial class Form1 : Form
                  {
                      String data = "EXIT";
                      public const int WM_COPYDATA = 0x4A;
                      int iHandle;
                      COPYDATASTRUCT cds;
              
                      [StructLayout(LayoutKind.Sequential)]
                      struct COPYDATASTRUCT 
                      {
                          public int dwData;
                          public int cbData;
                          public int lpData;
                      }
              
                      [DllImport("user32.dll")]
                      public static extern int FindWindow(string lpClassName, string lpWindowName);
              
                      [DllImport("user32.dll",CharSet=CharSet.Auto)]
                      private static extern int SendMessage(int hWnd, int wMsg, int wParam, COPYDATASTRUCT lParam);
              
                      [DllImport("kernel32.dll")]
                      public static extern void CopyMemory(byte dst, string src, int len);
              
                      public Form1()
                      {
                          InitializeComponent();
                      }
              
                      private void Form1_Load(object sender, EventArgs e)
                      {
                          iHandle = FindWindow("ThunderRT6FormDC", "RoadRunner");
                          COPYDATASTRUCT cds;
                          //Byte[] buf;
                          
                          //buf = StrToByteArray(data);
                          cds.dwData = 1;
                          cds.cbData = data.Length;
                          cds.lpData = VarPtr(data);
                      }
              
                      public static byte[] StrToByteArray(string str)
                      {
                          System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
                          return encoding.GetBytes(str);
                      }
              
                      public int VarPtr(object e)
                      {
                          GCHandle GC = GCHandle.Alloc(e, GCHandleType.Pinned);
                          //int gc = GC.AddrOfPinnedObject().ToInt32();
                          int gc = GC.AddrOfPinnedObject().ToInt32();
                          GC.Free();
                          return gc;
                      }
              
                      private void button1_Click(object sender, EventArgs e)
                      {
                          SendMessage(iHandle, WM_COPYDATA, 0, cds);
                      }
                  }
              Progress - VIA EPIA SP8000 | 120 Opus Power Supply & Case | 1GB Ram | 120GB 2.5" Hard Drive | Bluetooth 2.0 | GPRS/3G | Wifi | Road Runner/LSX 2.0 (waiting for a day skin for 3.0) | iGuidance 4.0 | Lilliput 7"

              Comment


              • #8
                My best guess is that you can't Alloc the space for the data you're referencing (with .Alloc) then free the memory before using it on the SendMessage call... you'd probably have to do the .free call AFTER the sendmessage...

                My real question is: is there any particular reason you're not using the COM interface ? It's a lot simpler and just as efficient.. check out this FAQ's section 3 on the RoadRunner.SDK object:
                http://www.mp3car.com/vbulletin/rr-f...cation-rr.html
                Ride Runner RR's Myspace

                "Being happy is not about having what you want, it's about wanting what you have."
                "The best things in life are always free - but that doesn't mean money can't buy you good things."

                Comment


                • #9
                  2 reasons. i haven't seen an examples of it in c# and i haven't seen how to receive messages, just receive values in RR.
                  Progress - VIA EPIA SP8000 | 120 Opus Power Supply & Case | 1GB Ram | 120GB 2.5" Hard Drive | Bluetooth 2.0 | GPRS/3G | Wifi | Road Runner/LSX 2.0 (waiting for a day skin for 3.0) | iGuidance 4.0 | Lilliput 7"

                  Comment


                  • #10
                    I am puzzled as to what difference you're making from receiving 'messages' or 'values' from RR.. the only 'messages' you'd receive from RR are those containing 'values' you've requested from it (i.e. using request).. are you trying to use the 'sendmsg' command from the skin to control your application ? is that it ? because if so, there are ways of not needing that and using actually simpler commands for you to execute from your application using the COM SDK... here's a generic example of the COM interface in C# compared to the VB6 interface:

                    Code:
                    The following VB code:
                    
                    Public Sub TestSDKVB6()
                            Dim SDK As Object 
                            Dim RRSCR as String
                            Set SDK = CreateObject("RoadRunner.SDK")
                            RRSCR = SDK.GetInfo("TRACKNAME")
                            SDK.Execute "EXIT"
                    End Sub
                    
                    Converts to the following C# code, using this approach:
                    
                    public void TestSDKDOTNET()
                    {
                            System.Type SDKType = System.Type.GetTypeFromProgID("RoadRunned.SDK");
                            object SDK = System.Activator.CreateInstance(SDKType);
                            RRSCR = SDK.InvokeMember("GetInfo", System.Reflection.BindingFlags.InvokeMethod, null, o, new object[] {"TRACKNAME"});
                            SDK.InvokeMember("Execute", System.Reflection.BindingFlags.InvokeMethod, null, o, new object[] {"EXIT"});
                    }
                    You can probably make procedures to call those functions (.Execute, .GetInfo and .GetInd) just so you avoid typing all that useless stuff.. once you created the SDK object, you can keep it until your program is finished with it.

                    in regards to the sendmessage version of this all, here's a supposedly "working" example of how to use the WM_COPYDATA message from C#:

                    Code:
                    Win32.COPYDATASTRUCT cds;
                    
                    cds.dwData = new System.IntPtr(sig);
                    str = str + '\0';
                    cds.cbData = str.Length + 1;
                    cds.lpData =
                    System.Runtime.InteropServices.Marshal.AllocCoTask Mem(str.Length);
                    
                    cds.lpData =
                    System.Runtime.InteropServices.Marshal.StringToCoT askMemAnsi(str);
                    
                    System.IntPtr iPtr =
                    System.Runtime.InteropServices.Marshal.AllocCoTask Mem(System.Runtime.InteropServices.Marshal.SizeOf( cds));
                    System.Runtime.InteropServices.Marshal.StructureTo Ptr(cds,
                    iPtr, true);
                    
                    Win32.SendMessage(handle, Win32.WM_COPYDATA, iHandle,
                    iPtr);
                    
                    System.Runtime.InteropServices.Marshal.FreeCoTaskM em(cds.lpData);
                    System.Runtime.InteropServices.Marshal.FreeCoTaskM em(iPtr);
                    Note how the Calls to Free the pointers/data are done AFTER the sendmessage.
                    Ride Runner RR's Myspace

                    "Being happy is not about having what you want, it's about wanting what you have."
                    "The best things in life are always free - but that doesn't mean money can't buy you good things."

                    Comment


                    • #11
                      I guess i think of a value being: a message(request) sent and that value received. a message received, to me, would be a button pressed, like my custom orb buttons. Am i looking at it wrong?
                      Progress - VIA EPIA SP8000 | 120 Opus Power Supply & Case | 1GB Ram | 120GB 2.5" Hard Drive | Bluetooth 2.0 | GPRS/3G | Wifi | Road Runner/LSX 2.0 (waiting for a day skin for 3.0) | iGuidance 4.0 | Lilliput 7"

                      Comment


                      • #12
                        No no, you're looking at it right.. and you can use sendmsg to trigger commands on your app.. but you could do that slightly different from the SDK.. for instance, instead of using "SENDMSG" you could use setvar.. and a single variable with your "command".. something like:

                        "SETVAR;ORBCMD;<COMMAND>" from RR ... then in your c# app you could have a loop/check every so often (i.e. 2-5 times per second for faster response) where you'd do this (VB6/Pseudo Code):

                        Code:
                        IF SDK.GetInfo("=$ORBCMD$") <> "" then
                           ORBCMD = SDK.GetInfo("=$ORBCMD$")
                           SDK.Execute("SETVAR;ORBCMD;")
                        
                           Select Case ORBCMD
                                case "PLAY"
                                       ...
                                case "AUDIO"
                                       ...
                           End Select
                        End If
                        Also, nothing prevents you from using both interfaces at once (for whatever reason).
                        Ride Runner RR's Myspace

                        "Being happy is not about having what you want, it's about wanting what you have."
                        "The best things in life are always free - but that doesn't mean money can't buy you good things."

                        Comment


                        • #13
                          THAT helps a lot. I wasn't sure if there was an event that triggered on a message received, or if it was something i had to check for. I'll press on...
                          Progress - VIA EPIA SP8000 | 120 Opus Power Supply & Case | 1GB Ram | 120GB 2.5" Hard Drive | Bluetooth 2.0 | GPRS/3G | Wifi | Road Runner/LSX 2.0 (waiting for a day skin for 3.0) | iGuidance 4.0 | Lilliput 7"

                          Comment


                          • #14
                            Originally posted by guino View Post
                            Code:
                            public void TestSDKDOTNET()
                            {
                                    System.Type SDKType = System.Type.GetTypeFromProgID("RoadRunned.SDK");
                                    object SDK = System.Activator.CreateInstance(SDKType);
                                    RRSCR = SDK.InvokeMember("GetInfo", System.Reflection.BindingFlags.InvokeMethod, null, o, new object[] {"TRACKNAME"});
                                    SDK.InvokeMember("Execute", System.Reflection.BindingFlags.InvokeMethod, null, o, new object[] {"EXIT"});
                            }
                            I'm not sure how this works... InvokeMember is a method of System.Type (i.e., SDKType), not Object. Type.InvokeMember returns an Object. is that what RRSCR is? if so, what is the object "o" in InvokeMember?
                            Progress - VIA EPIA SP8000 | 120 Opus Power Supply & Case | 1GB Ram | 120GB 2.5" Hard Drive | Bluetooth 2.0 | GPRS/3G | Wifi | Road Runner/LSX 2.0 (waiting for a day skin for 3.0) | iGuidance 4.0 | Lilliput 7"

                            Comment


                            • #15
                              Yes sorry, you're right, when I 'translated' the code I got that wrong.. this is the updated code:

                              Code:
                              public void TestSDKDOTNET()
                              {
                                      System.Type SDKType = System.Type.GetTypeFromProgID("RoadRunned.SDK");
                                      object SDK = System.Activator.CreateInstance(SDKType);
                                      RRSCR = SDKType.InvokeMember("GetInfo", System.Reflection.BindingFlags.InvokeMethod, null, SDK, new object[] {"TRACKNAME"});
                                      SDKType.InvokeMember("Execute", System.Reflection.BindingFlags.InvokeMethod, null, SDK, new object[] {"EXIT"});
                              }
                              Please note the SDK object passed as a parameter to InvokeMember.
                              Ride Runner RR's Myspace

                              "Being happy is not about having what you want, it's about wanting what you have."
                              "The best things in life are always free - but that doesn't mean money can't buy you good things."

                              Comment

                              Working...
                              X