CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 9 of 9
  1. #1
    Join Date
    Sep 2003
    Posts
    3

    Unhappy How to Marshal AccessibleObjectFromWindow

    Hi all,

    I've been trying to marshal AccessibileObjectFromWindow without luck. The code compiles but I get an exception at the line Marshal.Queryinterface which reads "System.NullReferenceException, Object reference not set to an instance of an object". What did I do wrong?

    Thanks.

    [DllImport("Oleacc.dll")]
    private static extern long AccessibleObjectFromWindow(int windowHandle, int objectID, Guid refID, ref IntPtr accessibleObject);

    //winable.h constants
    private int OBJID_WINDOW = 0x0;

    public void GetWindow(int handleWindow)
    {

    IAccessible iDialogWindow = null;

    //Guid obtained from OleAcc.idl from Platform SDK
    Guid iAccessibleGuid = new Guid("618736e0-3c3d-11cf-810c-00aa00389b71");
    IntPtr dialogWindow = Marshal.AllocCoTaskMem(4);
    IntPtr dialogWindowp = Marshal.AllocCoTaskMem(4);
    Marshal.StructureToPtr(dialogWindow, dialogWindowp, false);

    AccessibleObjectFromWindow(handleWindow, OBJID_WINDOW, iAccessibleGuid , ref dialogWindowp);

    dialogWindow = Marshal.ReadIntPtr(dialogWindowp);

    IntPtr iAccessiblePtr = IntPtr.Zero;
    Marshal.QueryInterface(dialogWindow, ref iAccessibleGuid, out iAccessiblePtr);
    ....
    }
    LTAN

  2. #2
    Join Date
    Jan 2004
    Posts
    2
    were you able to fix this problem.. I ma facing the same problem actually

  3. #3
    Join Date
    Sep 2003
    Posts
    3

    Solution

    Yes. I did.

    Here's the sample:

    [DllImport("Oleacc.dll")]
    private static extern int AccessibleObjectFromWindow(int windowHandle, int objectID, UUID refID, IntPtr accessibleObject);

    private IAccessible GetAccessibleInterfaceFromWindow(int handleWindow)
    {
    IAccessible iDialogWindow = null;

    //Allocate memory the size of IAccessible interface
    IntPtr dialogWindow = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(UUID)));

    //Add 1 level of indirection
    IntPtr dialogWindowp = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(IntPtr)));

    Marshal.StructureToPtr(dialogWindow, dialogWindowp, false);

    //Call function in Oleacc.dll
    AccessibleObjectFromWindow(handleWindow, objIDWindow, uuidAccessible, dialogWindowp);

    //Remove 1 level of indirection
    dialogWindow = Marshal.ReadIntPtr(dialogWindowp);

    //Allocate memory for the real IAccessible interface
    IntPtr iAccessiblePtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(UUID)));

    Marshal.QueryInterface(dialogWindow, ref iAccessibleGuid, out iAccessiblePtr);
    iDialogWindow = (IAccessible)Marshal.GetTypedObjectForIUnknown(iAccessiblePtr, typeof(IAccessible));
    LTAN

  4. #4
    Join Date
    Jan 2004
    Posts
    2
    How did you define your UUID Structure?

  5. #5
    Join Date
    Sep 2003
    Posts
    3
    [StructLayout(LayoutKind.Sequential)]
    private class UUID
    {
    public int data1;
    public short data2;
    public short data3;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
    public byte[] data4;
    }

    uuidAccessible = new UUID();
    uuidAccessible.data1 = 0x618736e0;
    uuidAccessible.data2 = 0x3c3d;
    uuidAccessible.data3 = 0x11cf;
    uuidAccessible.data4 = new byte[8];
    uuidAccessible.data4[0] = 0x81;
    uuidAccessible.data4[1] = 0xc;
    uuidAccessible.data4[2] = 0x0;
    uuidAccessible.data4[3] = 0xaa;
    uuidAccessible.data4[4] = 0x0;
    uuidAccessible.data4[5] = 0x38;
    uuidAccessible.data4[6] = 0x9b;
    uuidAccessible.data4[7] = 0x71;
    LTAN

  6. #6
    Join Date
    Aug 2006
    Posts
    3

    Re: How to Marshal AccessibleObjectFromWindow

    Hello

    In your code the cleanup is completely missing.
    But even if I add the three missing
    Marshal.FreeCoTaskMem(...);
    the code will have a strange behaviour :

    When I call it once, it returns the IAccessible interface.
    When I call it a second and a third time it still works.
    But at the fourth time AccessibleObjectFromWindow()
    will return error 0x80040002L (OLE_E_ENUM_NOMORE)
    I have no explanation for this really strange behaviour.

    I always put my navtive code into a Managed C++ DLL where programming all the Win32 stuff is much easier than in C#:

    #include <windows.h>
    #include <oleacc.h>
    #include <winable.h>
    #include <atlbase.h>

    using namespace System::Runtime::InteropServices; // Marshal

    Accessibility::IAccessible* UtilsLib::GetAccessibleFromWindow(int h_Wnd)
    {
    ::IAccessible* p_Acc = 0;
    HRESULT hr = AccessibleObjectFromWindow((HWND)h_Wnd, OBJID_WINDOW, IID_IAccessible, (void**)&p_Acc);
    if (!SUCCEEDED(hr) || !p_Acc)
    ThrowError(hr, "GetAccessibleFromWindow");

    Object* o_Acc = Marshal::GetTypedObjectForIUnknown(p_Acc, __typeof(Accessibility::IAccessible));
    p_Acc->Release();
    return static_cast<Accessibility::IAccessible*>(o_Acc);
    }

    Please note that ::IAccessible is unmanaged while Accessibility::IAccessible is managed!!!

    Even if I call this code in an endless loop, there is no error ever occurring
    ___________________

    If you do NOT call p_Acc->Release(); you will produce a memory leak !!!

    If you omit this line of code and call GetAccessibleFromWindow() in an endless loop from C#, you can see in Taskmanager that your process aquires more and more memory (500 MB and more) until your system will hang!!!

    On my PC Taskmanager shows that the above function called in an endless loop will not consume more than 80 MB total memory. (physical + virtual) This is the limit at which the garbage collector starts its work.

    But you don't have to worry that the COM object in p_Acc will be deleted after calling Release() so the caller of the function would work with a dead COM object :

    To check this insert these lines at different locations in the function:
    int RefCount = p_Acc->AddRef() - 1;
    p_Acc->Release();

    Then RefCount will contain the current reference count without modifying it.

    You wil see that after calling
    AccessibleObjectFromWindow()
    RefCount is = 1

    And that GetTypedObjectForIUnknown() will increase the refcount by 2, so afterwards it is = 3.

    So when the function GetAccessibleFromWindow() exits, RefCount will be = 2 and these 2 references will be decremented when the garbage collector destroys Accessibility::IAccessible

    ___________

    In ThrowError() I call
    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, hr, 0, s8_Buf, u32_BufLen, 0);
    and throw it then
    throw new Exception(s8_Buf);
    to display human readable errors.

    Elmü
    Last edited by Elmue; August 22nd, 2006 at 09:12 AM.

  7. #7
    Join Date
    Aug 2006
    Posts
    3

    Re: How to Marshal AccessibleObjectFromWindow

    Hello

    You will also get problems when you try to call the OleAcc.Dll functions
    AccessibleChildren() and AccessibleObjectFromPoint()

    If you try to do this in C# I promise that your code will produce a memory leak, because Marshal.GetObjectsForNativeVariants() which you will need for AccessibleChildren() does NOT work properly!

    So don't waste your time trying to write the code in C# !

    The following two functions in Managed C++ are checked to work 100% correctly without creating a memory leak:

    Elmü

    ______________________________

    void UtilsLib::GetAccessibleFromPoint(Point k_Pos, Accessibility::IAccessible** pp_iAcc, Int32* ps32_ChildId)
    {
    ::IAccessible* p_Acc = 0;
    VARIANT v_Child;
    POINT pt = { k_Pos.X, k_Pos.Y };

    HRESULT hr = AccessibleObjectFromPoint(pt, &p_Acc, &v_Child);
    if (!SUCCEEDED(hr) || !p_Acc)
    ThrowError(hr, "GetAccessibleFromPoint");

    Object *o_Acc = Marshal::GetTypedObjectForIUnknown(p_Acc, __typeof(Accessibility::IAccessible));
    *pp_iAcc = static_cast<Accessibility::IAccessible*>(o_Acc);
    p_Acc->Release(); // avoids memory leak!!!

    if (v_Child.vt == VT_I4) *ps32_ChildId = v_Child.lVal;
    else *ps32_ChildId = CHILDID_SELF;
    }

    _________________________________________

    ArrayList* UtilsLib::GetAccessibleChildren(Accessibility::IAccessible* i_Parent)
    {
    ArrayList* i_ChildList = 0;
    VARIANT* pv_Children = 0;
    ::IDispatch* p_ParDisp = 0;
    ::IAccessible* p_ParAcc = 0;

    if (!i_Parent)
    goto _CleanUp;

    int s32_Count = i_Parent->accChildCount;
    if (!s32_Count)
    goto _CleanUp;

    p_ParDisp = (::IDispatch*) Marshal::GetIDispatchForObject(i_Parent).ToPointer();
    if (!p_ParDisp)
    goto _CleanUp;

    p_ParDisp->QueryInterface(IID_IAccessible, (void**) &p_ParAcc);
    if (!p_ParAcc)
    goto _CleanUp;

    pv_Children = new VARIANT[s32_Count];

    long s32_Obtained = 0;
    if (AccessibleChildren(p_ParAcc, 0, s32_Count, pv_Children, &s32_Obtained))
    goto _CleanUp;

    i_ChildList = new ArrayList();

    // s32_Obtained may differ from s32_Count !!!!
    for (int i=0; i<s32_Obtained; i++)
    {
    VARIANT k_Var = pv_Children[i];
    if (k_Var.vt == VT_I4) // variant holds an integer
    {
    i_ChildList->Add(__box((Int32)k_Var.lVal));
    continue;
    }
    if (k_Var.vt == VT_DISPATCH) // variant holds an ::IAccessible interface
    {
    ::IDispatch* p_ChDisp = k_Var.pdispVal;
    if (p_ChDisp)
    {
    i_ChildList->Add(Marshal::GetTypedObjectForIUnknown(p_ChDisp, __typeof(Accessibility::IAccessible)));
    p_ChDisp->Release(); // avoids a memory leak !!!
    continue;
    }
    }

    i_ChildList->Add(0); // invalid type (e.g. VT_EMPTY) or error --> add "null"
    }

    _CleanUp:
    if (pv_Children) delete pv_Children;
    if (p_ParDisp) p_ParDisp->Release();
    if (p_ParAcc) p_ParAcc ->Release();

    return i_ChildList;
    }
    Last edited by Elmue; August 24th, 2006 at 10:14 AM.

  8. #8
    Join Date
    Jan 2010
    Posts
    1

    Re: How to Marshal AccessibleObjectFromWindow

    Hi,

    I want to access the IDispatch interface from an accessible object and I came across your code. Can you explain how to compile it? I am using Visual Studio 2008, creating a CLR Class Library. Thanks very much.

  9. #9
    Join Date
    Apr 2008
    Posts
    4

    Re: How to Marshal AccessibleObjectFromWindow

    hi Elmue can you provide me with a full source code of what you have mentioned before.
    Thank you

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured