2
votes

This Q&A refers to and can be used for foll. purposes:

  1. Send message from IE browser to vb6 app via ActiveX dll
  2. Send message from ActiveX dll to vb6 app
  3. Send message from C#.net (dll) to vb6 app

I have read this article but doesn't seem to be very clear for my purpose...

I have also referred to this article to create ActiveX object and have implemented an ActiveX dll that I am calling from browser to launch an application on client side.. The dll checks whether the VB6 exe (process) is running, else runs the exe. If the exe is already running then I want to pass a parameter/message to the exe application.

But I am not able to get a solution or reference samples to implement a way to send message from this C#.NET assembly (ActiveX) to an VB6 application... I do have access to source codes of the .NET and VB6 application...

I have tried using:-

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

    }

I have also tried this: using help from following links, however this is not exactly the solution I am looking for!:- e[C#] Reading/Writing textbox on other program This code has been implemented on my activeX DLL which launches a VB6 App.. I am checking via .NET (process) whether the exe is running and if not, then launching it. If the exe is running then I am using the above article code example to send a message to the vb6 application by setting a control (textbox in mycase)... Very helpfull code.. Following code copied from:- c# reading & writing textbox on other program

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;
}

}

There is one more example in stack overflow, however it is to read data from another application into the .NET (not usefull for my requirement).. However, I am putting it down into this answer so that someone who may want to read from an app as well as write to an app will find solution here.. Following code obtained from:- 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

3 Answers

2
votes

The sample code to achieve this can be programmed using WM_COPYDATA and SENDMESSAGE.

From the .NET app you can send a message. On VB6 side you will have to create a message hook. This hook will loop using the WNDPROC function and catch messages sent to it.

Refer foll. 2 links with sample code:-

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

For VB6: How To Pass String Data Between Applications Using SendMessage

Both above can be combined in such way that you can pass data between C#.NET and VB6 applciaiton...

0
votes

A quick and dirty way:

  1. When the exe runs have it store the hwnd of a textbox in the registry (or use FindWindow from the dll)
  2. Have the dll read the hwnd and use SendMessage + WM_SETTEXT to set its text
  3. This will raise the textbox change event in the VB6 exe which can then simply read its .text
0
votes

WM_COPYDATA message. Take a look at this question

The basic idea is :

1 - In your activex dll initialize a buffer with the required data to send

2 - Your activex dll finds (FindWindow) the target application window

3 - Your activex dll sends a WM_COPYDATA message to the target window with a pointer to the buffer.

4 - Your vb6 application receives the message and reads the sended data.

OS handles the necessary conversion in address spaces between the two processes, but you will need to subclass the receiving window in your application to be able to receive the message.