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?
private static extern long AccessibleObjectFromWindow(int windowHandle, int objectID, Guid refID, ref IntPtr accessibleObject);
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);
In your code the cleanup is completely missing.
But even if I add the three missing
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#:
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;
Then RefCount will contain the current reference count without modifying it.
You wil see that after calling
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.
Last edited by Elmue; August 22nd, 2006 at 09:12 AM.
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.