tags:

views:

349

answers:

1

I am having to write an application that communicates with a third party program (AOL, I'm sorry. :()

Doing a lot of research I found some ways to do this with PInvoke, and for the most part it works okay, but it crashes upon subsequent trials. Specifically with SendMessage. I'm outlining the crashing code below - I can post more if anyone is at all interested in helping.

all of this was ported to .net from old, old visual basic files. It's archaic as can be and I understand if it's not doable - was just hoping there was a better way than VB4 to get this done.

    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool CloseHandle(IntPtr hObject);

    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, IntPtr windowTitle);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr SendMessage(HandleRef hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

    [DllImport("user32.dll", EntryPoint="SendMessageW")]
    public static extern IntPtr SendMessageByString(HandleRef hWnd, UInt32 Msg, IntPtr wParam, StringBuilder lParam);

    [DllImport("user32.dll", CharSet = CharSet.Unicode , EntryPoint = "SendMessageW")]
    public static extern IntPtr SendMessageByString(HandleRef hWnd, UInt32 Msg, IntPtr wParam, String lParam);

    public IntPtr FindClientWindow()
    {
        IntPtr aol = IntPtr.Zero; 
        IntPtr mdi = IntPtr.Zero;
        IntPtr child = IntPtr.Zero;
        IntPtr rich = IntPtr.Zero;
        IntPtr aollist = IntPtr.Zero;
        IntPtr aolicon = IntPtr.Zero;
        IntPtr aolstatic = IntPtr.Zero;

        aol = Invoke.FindWindow("AOL Frame25", null);
        mdi = Invoke.FindWindowEx(aol, IntPtr.Zero, "MDIClient", null);
        child = Invoke.FindWindowEx(mdi, IntPtr.Zero, "AOL Child", null);
        rich = Invoke.FindWindowEx(child, IntPtr.Zero, "RICHCNTL", null);
        aollist = Invoke.FindWindowEx(child, IntPtr.Zero, "_AOL_Listbox", null);
        aolicon = Invoke.FindWindowEx(child, IntPtr.Zero, "_AOL_Icon", null);
        aolstatic = Invoke.FindWindowEx(child, IntPtr.Zero, "_AOL_Static", null);

        if (rich != IntPtr.Zero && aollist != IntPtr.Zero && aolicon != IntPtr.Zero && aolstatic != IntPtr.Zero)
            return child;
        do
        {
            child = Invoke.FindWindowEx(mdi, child, "AOL Child", null);
            rich = Invoke.FindWindowEx(child, IntPtr.Zero, "RICHCNTL", null);
            aollist = Invoke.FindWindowEx(child, IntPtr.Zero, "_AOL_Listbox", null);
            aolicon = Invoke.FindWindowEx(child, IntPtr.Zero, "_AOL_Icon", null);
            aolstatic = Invoke.FindWindowEx(child, IntPtr.Zero, "_AOL_Static", null);

            if (rich != IntPtr.Zero && aollist != IntPtr.Zero && aolicon != IntPtr.Zero && aolstatic != IntPtr.Zero)
                return child;
        }
        while (child != IntPtr.Zero);

        return child;
    }

        IntPtr room = IntPtr.Zero;
        IntPtr child = IntPtr.Zero;
        IntPtr length = IntPtr.Zero;
        IntPtr roomHandle = IntPtr.Zero;

        child = FindClientWindow();
        room = FindChildByClass(child, "RICHCNTLREADONLY");

        HandleRef n = new HandleRef(IntPtr.Zero, room);

        length = SendMessage(n, 0x000E, IntPtr.Zero, IntPtr.Zero);
        SendMessageByString(n, 0x000D, new IntPtr( length.ToInt32() + 1 ), str); // this is the line that keeps crashing on me.

    public IntPtr FindChildByClass(IntPtr parent, string child)
    {
        return Invoke.FindWindowEx(parent, IntPtr.Zero, child, null);
    }
+1  A: 

You are using the Wide byte SendMessage..ie for Wide Characters, have you tried the normal Sendmessage.. public static extern int SendMessage(IntPtr hWnd, UInt32 Msg, Int32 wParam, Int32 lParam);

I also notice it's like as if you are trying to change the value based on the handle of the richtextbox's control hence the looking around for the AOL's client window in another process...is that correct?

That could be the source of the problem, directly modifying a control that belongs to a window that is not yours (your program is managed, modifying a unmanaged process's window)...that could explain why it crashed. Can you clarify what is the hex constants for?

Edit: When you use the WM_GETTEXTLENGTH and WM_GETTEXT, they are part of the Windows Messages to retrieve the text length and the actual text from the control. If you look here and see what pinvoke.net has to say about them..When you issue a 'SendMessage', with WM_GETTEXTLENGTH and WM_GETTEXT, you are telling Windows - 'Hey, get me the length of the text in that associated handle which I've given you in the parameter n. Just occurred to me, worth trying out...I would get rid of those SendMessage pinvokes and use just this one..

[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, StringBuilder lParam);
//If you use '[Out] StringBuilder', initialize the string builder with proper length first.

child = FindClientWindow();
room = FindChildByClass(child, "RICHCNTLREADONLY");

length = SendMessage(n, 0x000E, IntPtr.Zero, IntPtr.Zero);

StringBuilder sbBuf = new StringBuilder(length);

SendMessageByString(room, 0x000D, new IntPtr( length.ToInt32() + 1 ), out sbBuf); // this is the line that keeps crashing on me.

Try that and get back here ... :)

Hope this helps, Best regards, Tom.

tommieb75
The hex constants existed in the previous code I am emulating - it is old visual basic 4 code - so there is a good chance it does not work. They stood for WM_GETTEXTLENGTH (0x000E) and WM_GETTEXT (0x000D). I do not entirely know what these are for - I am very new at this.
Stacey
Yes, I have tried the non-wide one. I get the same result.
Stacey
I'm sorry for the weak data, I am very poor at pinvoke in general.
Stacey
That gives me the error "Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
Stacey
Hmmm....Can you run spy++ on the actual window to see what is the handle and compare it to what your routine `FindClientWindow` returned in the context of the handle? Another thing...maybe AOL has locked down the protection on the process itself to prevent it from being hacked? Also, the string "RICHCNTLREADONLY" is presumably the control you're trying to access is read-only or locked...
tommieb75
The handles match - and I don't think it is locked. The method *does* work. It just only works once or twice, THEN it crashes.
Stacey
Maybe you need to dispose of the handles, by using 'CloseHandle' and pass in the handles which are of type IntPtr after invoking SendMessage to obtain the text...that could explain why it works once or twice....? See pinvoke for CloseHandle here http://pinvoke.net/default.aspx/kernel32/CloseHandle.html
tommieb75
Yeah, I've tried that too - on both of them. I still encounter the same problem. =/
Stacey
Hrnm. Now that I try again, the handles are not the same. But it still gets all of the information once or twice before it crashes. I just plain don't understand why it would do that...
Stacey
Can you tell me what is the application you are running it against... is it a customized AOL application or generic AOL app that you can download?
tommieb75
It's the normal AOL 9.5 software for Windows.
Stacey
I can investigate this and check...and will get back to you - that ok?
tommieb75
Absolutely! Thank you so, so much for all of your time.
Stacey
It's past bedtime for me...will investigate this tomorrow evening at some stage...I will post updates here..
tommieb75
Am installing AOL - Whereabouts on the AOL screen is the intended target you want to run the code against?
tommieb75
By the way, where's the code for 'FindChildByClass'?
tommieb75
Updated to add the method requested. And yes, AOL is the client it will be ran against.
Stacey
In there, when debugging, I have noticed that rich = FindWindowEx(child, IntPtr.Zero, "RICHCNTL", null); rich always returns IntPtr.Zero. Can you verify you have the right class name?
tommieb75
RICHCNTL is the right class name, yes.
Stacey
The intention is that it reads the contents of the chatroom and brings it back to the application - if that wasn't clear.
Stacey
So you need to have the chat mini-app within AOL open?
tommieb75
Something like that, yes. It's supposed to find the AOL window, then find the chatroom, then find the display box, get the text, and return it.
Stacey
I am in AOL Chat, "A Crowded Room", and notice that the handle of the window is tied to Internet Explorer Server (Class name that is...) unless I'm in the wrong spot, it has a tab page...can you show me the screenshot of whereabouts in AOL that is...I think I'm in the wrong spot!
tommieb75
On the AOL client?
Stacey
Yes.. I downloaded the full AOL setup package version 9.5, which installed the email, chat, browser the full works...am on it as t0mm13b..
tommieb75