【问题标题】:Is there a way to send messages from C#.NET assembly(ActiveX) to VB6 application?有没有办法将消息从 C#.NET 程序集(ActiveX)发送到 VB6 应用程序?
【发布时间】:2014-02-05 07:17:06
【问题描述】:

此Q&A 参考并可用于foll。目的:

  1. 通过 ActiveX dll 从 IE 浏览器向 vb6 应用发送消息
  2. 从 ActiveX dll 向 vb6 应用发送消息
  3. 从 C#.net (dll) 向 vb6 应用发送消息

我已经阅读了this article,但我的目的似乎不是很清楚......

我还提到了this article to create ActiveX object 并实现了一个 ActiveX dll,我从浏览器调用它以在客户端启动应用程序。该 dll 检查 VB6 exe(进程)是否正在运行,否则运行 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 此代码已在我的启动 VB6 应用程序的 activeX DLL 上实现。我是通过 .NET(进程)检查 exe 是否正在运行,如果没有,则启动它。如果 exe 正在运行,那么我使用上面的文章代码示例通过设置控件(mycase 中的文本框)向 vb6 应用程序发送消息......非常有用的代码.. 以下代码复制自:- c# 读写文本框在其他节目中

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(对我的要求没有用)。但是,我将其放入此答案中,以便可能需要的人从应用程序读取以及写入应用程序将在这里找到解决方案。以下代码来自:- 堆栈溢出

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;


  }
}

【问题讨论】:

    标签: c# .net vb6 activex ipc


    【解决方案1】:

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

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

    请参阅以下内容。 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 应用程序之间传递数据...

    【讨论】:

      【解决方案2】:

      一种快速而肮脏的方式:

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

      【讨论】:

      • 我试图在我的 C#.NET DLL 中使用 FindWindow,但是,我如何访问该窗口中的标签(窗口是 VB6 应用程序)
      • 你能给我提供这方面的任何参考例子吗?
      【解决方案3】:

      WM_COPYDATA 消息。看看this question

      基本思路是:

      1 - 在您的 activex dll 中使用要发送的所需数据初始化缓冲区

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

      3 - 您的 activex dll 向目标窗口发送一条 WM_COPYDATA 消息,其中包含指向缓冲区的指针。

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

      操作系统处理两个进程之间地址空间的必要转换,但您需要在应用程序中对接收窗口进行子类化才能接收消息。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-07-04
        • 2017-09-25
        • 1970-01-01
        • 1970-01-01
        • 2022-08-16
        • 2019-03-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多