有没有办法从C#.NET程序集(ActiveX)发送消息到VB6应用程序?

时间:2014-01-16 11:42:58

标签: c# .net vb6 activex ipc

此Q& A指的是并且可以用于foll。用途:

  1. 通过ActiveX dll从IE浏览器向vb6 app发送消息
  2. 从ActiveX dll发送消息到vb6 app
  3. 从C#.net(dll)发送消息到vb6 app
  4. 我已阅读this article但似乎并不十分明确我的目的......

    我还提到this article to create ActiveX object并实现了一个ActiveX dll,我从浏览器调用以在客户端启动应用程序..该DLL检查VB6 exe(进程)是否正在运行,否则运行可执行程序。如果exe已经运行,那么我想将参数/消息传递给exe应用程序。

    但我无法获得解决方案或参考示例来实现从此C#.NET程序集(ActiveX)向VB6应用程序发送消息的方法...我可以访问.NET的源代码和VB6应用程序......

    我尝试过使用: -

     Process[] processes = Process.GetProcessesByName("MyProgram");
        foreach (Process p in processes)
        {
            IntPtr pFoundWindow = p.MainWindowHandle;
            // how do I pass a value to MyProgram.exe ?
            //
    
        }
    

    我也试过这个:使用以下链接的帮助,但这不是我正在寻找的解决方案!: - e[C#] Reading/Writing textbox on other program此代码已在我的activeX DLL上实现,它启动了VB6应用程序..我正在通过.NET(进程)检查exe是否正在运行,如果没有,则启动它。如果exe正在运行,那么我使用上面的文章代码示例通过设置控件(mycase中的文本框)向vb6应用程序发送消息...非常有用的代码..以下代码复制自: - c#reading&在其他程序上编写文本框

    public class ExternalWriter 
    {
        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    
        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string className, string lpszWindow);
    
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
    private static extern int SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, string lParam);
    
    private const int WM_SETTEXT = 12;
    
    public void DoExternalWrite(string text) 
    {
        IntPtr parent = FindWindow("<window class name>", "<window title">);
        IntPtr child = GetchildHandle(parent, "<class name>");
    
        SendMessage(child, WM_SETTEXT, IntPtr.Zero, text);
    }
    
    private IntPtr GetChildHandle(IntPtr parent, string className) 
    {
        /* Here you need to perform some sort of function to obtain the child window handle, perhaps recursively
         */
    
        IntPtr child = FindWindowEx(parent, IntPtr.Zero, className, null);
        child = FindWnidowEx(parent, child, className, null);
    
        /* You can use a tool like Spy++ to discover the hierachy on the Remedy 7 form, to find how many levels you need to search
         * to get to the textbox you want */
    
        return child;
    }
    
    }
    

    堆栈溢出还有一个例子,但它是将数据从另一个应用程序读入.NET(对我的要求没有用)。但是,我把它归结为这个答案,以便有人可能想要从应用程序读取以及写入应用程序将在此处找到解决方案。以下代码从: - stack overflow

    获得
    public class GetWindowTextExample
    {
        // Example usage.
        public static void Main()
        {
            var allText = GetAllTextFromWindowByTitle("Untitled - Notepad");
            Console.WriteLine(allText);
            Console.ReadLine();
        }
    
        // Delegate we use to call methods when enumerating child windows.
        private delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);
    
        [DllImport("user32")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr i);
    
        [DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
        private static extern IntPtr FindWindowByCaption(IntPtr zeroOnly, string lpWindowName);
    
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, [Out] StringBuilder lParam);
    // Callback method used to collect a list of child windows we need to capture text from.
    private static bool EnumChildWindowsCallback(IntPtr handle, IntPtr pointer)
    {
        // Creates a managed GCHandle object from the pointer representing a handle to the list created in GetChildWindows.
        var gcHandle = GCHandle.FromIntPtr(pointer);
    
        // Casts the handle back back to a List<IntPtr>
        var list = gcHandle.Target as List<IntPtr>;
    
        if (list == null)
        {
            throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
        }
    
        // Adds the handle to the list.
        list.Add(handle);
    
        return true;
    }
    
    // Returns an IEnumerable<IntPtr> containing the handles of all child windows of the parent window.
    private static IEnumerable<IntPtr> GetChildWindows(IntPtr parent)
    {
        // Create list to store child window handles.
        var result = new List<IntPtr>();
    
        // Allocate list handle to pass to EnumChildWindows.
        var listHandle = GCHandle.Alloc(result);
    
        try
        {
            // Enumerates though all the child windows of the parent represented by IntPtr parent, executing EnumChildWindowsCallback for each. 
            EnumChildWindows(parent, EnumChildWindowsCallback, GCHandle.ToIntPtr(listHandle));
        }
        finally
        {
            // Free the list handle.
            if (listHandle.IsAllocated)
                listHandle.Free();
        }
    
        // Return the list of child window handles.
        return result;
    }
    
    // Gets text text from a control by it's handle.
    private static string GetText(IntPtr handle)
    {
        const uint WM_GETTEXTLENGTH = 0x000E;
        const uint WM_GETTEXT = 0x000D;
    
        // Gets the text length.
        var length = (int)SendMessage(handle, WM_GETTEXTLENGTH, IntPtr.Zero, null);
    
        // Init the string builder to hold the text.
        var sb = new StringBuilder(length + 1);
    
        // Writes the text from the handle into the StringBuilder
        SendMessage(handle, WM_GETTEXT, (IntPtr)sb.Capacity, sb);
    
        // Return the text as a string.
        return sb.ToString();
    }
    
    // Wraps everything together. Will accept a window title and return all text in the window that matches that window title.
    private static string GetAllTextFromWindowByTitle(string windowTitle)
    {
        var sb = new StringBuilder();
    
        try
        {
            // Find the main window's handle by the title.
            var windowHWnd = FindWindowByCaption(IntPtr.Zero, windowTitle);
    
            // Loop though the child windows, and execute the EnumChildWindowsCallback method
            var childWindows = GetChildWindows(windowHWnd);
    
            // For each child handle, run GetText
            foreach (var childWindowText in childWindows.Select(GetText))
            {
                // Append the text to the string builder.
                sb.Append(childWindowText);
            }
    
            // Return the windows full text.
            return sb.ToString();
        }
        catch (Exception e)
        {
            Console.Write(e.Message);
        }
    
        return string.Empty;
    
    
      }
    }
    

3 个答案:

答案 0 :(得分:2)

可以使用WM_COPYDATA和SENDMESSAGE编程实现此目的的示例代码。

从.NET应用程序中,您可以发送消息。在VB6端,您将不得不创建一个消息钩子。这个钩子将使用WNDPROC函数循环并捕获发送给它的消息。

参考foll。 2个示例代码链接: -

对于C#.NET:C# Windows app uses WM_COPYDATA for IPC (CSSendWM_COPYDATA)

对于VB6:How To Pass String Data Between Applications Using SendMessage

以上两者都可以这样组合,即您可以在C#.NET和VB6 applciaiton之间传递数据......

答案 1 :(得分:0)

快速而肮脏的方式:

  1. 当exe运行时,它将文本框的hwnd存储在注册表中(或使用来自dll的FindWindow)
  2. 让dll读取hwnd并使用SendMessage + WM_SETTEXT设置其文本
  3. 这将引发VB6 exe中的文本框更改事件,然后可以简单地读取它的.text

答案 2 :(得分:0)

WM_COPYDATA消息。看看this question

基本理念是:

1 - 在您的activex dll中初始化一个缓冲区,其中包含要发送的所需数据

2 - 您的activex dll找到(FindWindow)目标应用程序窗口

3 - 您的activex dll使用指向缓冲区的指针向目标窗口发送WM_COPYDATA消息。

4 - 您的vb6应用程序收到消息并读取已发送的数据。

操作系统在两个进程之间的地址空间中处理必要的转换,但是您需要在应用程序中继承接收窗口以便能够接收消息。