From: Jozsef Bekes on
Hello All,

I have a tester appliaction that tests our MFC application by pushing
buttons and filling editboxes, etc. automatically. It identifies the
control windows by the control id, that can be retrieved by
GetWindowLongPtr(hwnd, GWL_ID);

Our application also has a complicated .net dialog written in vb.net. When I
tried to implement some testcases for this dialog, I found out (to my
amazement) that the control id for any control becomes different when the
dialog gets destroyed and created again. Now my question is:

Is there a reliable way how I could find the HWND of a .NET control using
win32 calls?

For buttons it is ok, they have unique windownames (that is the label on
them), so I do not strictly need the ctrl id. But the windowname of an
editbox is its content, that is not unique on this complicated dialog.

I do have access to the vb.net code, so I can do modifications if that can
help my situation, but I do not want a COM interface that returns the HWND
for the requested control, I hope there is a solution more elegant than
that.

Do you have any sugestions other than to find a control by its position?

Thank you!!

Best regards,
Jozsi


From: Peter Duniho on
On Wed, 20 Aug 2008 09:23:25 -0700, Jozsef Bekes <bjdodo(a)hotmail.com>
wrote:

> [...]
> Our application also has a complicated .net dialog written in vb.net.
> When I
> tried to implement some testcases for this dialog, I found out (to my
> amazement) that the control id for any control becomes different when the
> dialog gets destroyed and created again.

I don't find that too surprising. .NET Forms are created programmatically
instead of using a dialog template from a resource, and assuming an ID is
assigned at all, the Forms Designer code doesn't do that so it wouldn't be
persistent across instances.

> Now my question is:
>
> Is there a reliable way how I could find the HWND of a .NET control using
> win32 calls?

I'm confused. The first part of your question said that you can retrieve
the ID, but it's changing from instance to instance. To do that you'd
need the HWND so that you can use that in the call to GetWindowLongPtr().
Given that the first part of your question implies that you already have
the HWND, why are you now asking how to get the HWND?

Also, a minor point: if you're calling GetWindowLongPtr(), you should be
passing GWLP_ID as the index. GWL_ID is for GetWindowLong(). Of course,
given that you're just getting the control index and not an actual
pointer, maybe it's better to just go back to using GetWindowLong().

> For buttons it is ok, they have unique windownames (that is the label on
> them), so I do not strictly need the ctrl id. But the windowname of an
> editbox is its content, that is not unique on this complicated dialog.
>
> I do have access to the vb.net code, so I can do modifications if that
> can
> help my situation, but I do not want a COM interface that returns the
> HWND
> for the requested control, I hope there is a solution more elegant than
> that.
>
> Do you have any sugestions other than to find a control by its position?

Well, it seems to me that you could in fact add some code to the dialog
Form's constructor that explicitly sets the GWL_ID for each control. Just
use p/invoke to get at the SetWindowLong() function, and call that for
each control with whatever ID you want to set.

Pete
From: Jozsef Bekes on
Hi Peter,

Thanks for the answer!

> the Forms Designer code doesn't do that so it wouldn't be persistent
> across instances.
Ok, it makes sense :-)

> I'm confused. The first part of your question said that you can retrieve
> the ID, but it's changing from instance to instance. To do that you'd
> need the HWND so that you can use that in the call to GetWindowLongPtr().

I can enumerate the child windows (=controls) of the form. In theory, if one
of them has the control id I am looking for, that is the HWND I want. This
is what does not work.

> Also, a minor point: if you're calling GetWindowLongPtr(), you should be
> passing GWLP_ID as the index.

Good point :-) Thanks!

> Well, it seems to me that you could in fact add some code to the dialog
> Form's constructor that explicitly sets the GWL_ID for each control. Just
> use p/invoke to get at the SetWindowLong() function, and call that for
> each control with whatever ID you want to set.

Ok, this sounds like a solution, I am not too glad about it though. All in
all there is no easy way to find a control from a different process unless I
prepare my control so. I wonder if there is an automated tester software,
that can push buttons for you on a .net application. If there is I guess
there must be a way to achieve what I want.

Well anyway, it's better than nothing :-))

Thanks!!
Jozsi






"Peter Duniho" <NpOeStPeAdM(a)nnowslpianmk.com> wrote in message
news:op.uf62tato8jd0ej(a)petes-computer.local...
> On Wed, 20 Aug 2008 09:23:25 -0700, Jozsef Bekes <bjdodo(a)hotmail.com>
> wrote:
>
>> [...]
>> Our application also has a complicated .net dialog written in vb.net.
>> When I
>> tried to implement some testcases for this dialog, I found out (to my
>> amazement) that the control id for any control becomes different when the
>> dialog gets destroyed and created again.
>
> I don't find that too surprising. .NET Forms are created programmatically
> instead of using a dialog template from a resource, and assuming an ID is
> assigned at all, the Forms Designer code doesn't do that so it wouldn't be
> persistent across instances.
>
>> Now my question is:
>>
>> Is there a reliable way how I could find the HWND of a .NET control using
>> win32 calls?
>
> I'm confused. The first part of your question said that you can retrieve
> the ID, but it's changing from instance to instance. To do that you'd
> need the HWND so that you can use that in the call to GetWindowLongPtr().
> Given that the first part of your question implies that you already have
> the HWND, why are you now asking how to get the HWND?
>
> Also, a minor point: if you're calling GetWindowLongPtr(), you should be
> passing GWLP_ID as the index. GWL_ID is for GetWindowLong(). Of course,
> given that you're just getting the control index and not an actual
> pointer, maybe it's better to just go back to using GetWindowLong().
>
>> For buttons it is ok, they have unique windownames (that is the label on
>> them), so I do not strictly need the ctrl id. But the windowname of an
>> editbox is its content, that is not unique on this complicated dialog.
>>
>> I do have access to the vb.net code, so I can do modifications if that
>> can
>> help my situation, but I do not want a COM interface that returns the
>> HWND
>> for the requested control, I hope there is a solution more elegant than
>> that.
>>
>> Do you have any sugestions other than to find a control by its position?
>
> Well, it seems to me that you could in fact add some code to the dialog
> Form's constructor that explicitly sets the GWL_ID for each control. Just
> use p/invoke to get at the SetWindowLong() function, and call that for
> each control with whatever ID you want to set.
>
> Pete


From: Jozsef Bekes on
Hi Peter,

I have got a response in another forum. This looks better, although not
perfect:

"You can fill "AccessibleName" property with unique ID string for a given
control. Then, from the tester application call `AccessibleObjectFromWindow'
in order to obtain `IAccessible' interface for the control. Use the
`IAccessible::get_accName' method to identify your control."

BR,
Jozsi

"Jozsef Bekes" <bjdodo(a)hotmail.com> wrote in message
news:%23LgwyiuAJHA.1184(a)TK2MSFTNGP04.phx.gbl...
> Hi Peter,
>
> Thanks for the answer!
>
>> the Forms Designer code doesn't do that so it wouldn't be persistent
>> across instances.
> Ok, it makes sense :-)
>
>> I'm confused. The first part of your question said that you can retrieve
>> the ID, but it's changing from instance to instance. To do that you'd
>> need the HWND so that you can use that in the call to GetWindowLongPtr().
>
> I can enumerate the child windows (=controls) of the form. In theory, if
> one of them has the control id I am looking for, that is the HWND I want.
> This is what does not work.
>
>> Also, a minor point: if you're calling GetWindowLongPtr(), you should be
>> passing GWLP_ID as the index.
>
> Good point :-) Thanks!
>
>> Well, it seems to me that you could in fact add some code to the dialog
>> Form's constructor that explicitly sets the GWL_ID for each control.
>> Just use p/invoke to get at the SetWindowLong() function, and call that
>> for each control with whatever ID you want to set.
>
> Ok, this sounds like a solution, I am not too glad about it though. All in
> all there is no easy way to find a control from a different process unless
> I prepare my control so. I wonder if there is an automated tester
> software, that can push buttons for you on a .net application. If there is
> I guess there must be a way to achieve what I want.
>
> Well anyway, it's better than nothing :-))
>
> Thanks!!
> Jozsi
>
>
>
>
>
>
> "Peter Duniho" <NpOeStPeAdM(a)nnowslpianmk.com> wrote in message
> news:op.uf62tato8jd0ej(a)petes-computer.local...
>> On Wed, 20 Aug 2008 09:23:25 -0700, Jozsef Bekes <bjdodo(a)hotmail.com>
>> wrote:
>>
>>> [...]
>>> Our application also has a complicated .net dialog written in vb.net.
>>> When I
>>> tried to implement some testcases for this dialog, I found out (to my
>>> amazement) that the control id for any control becomes different when
>>> the
>>> dialog gets destroyed and created again.
>>
>> I don't find that too surprising. .NET Forms are created
>> programmatically instead of using a dialog template from a resource, and
>> assuming an ID is assigned at all, the Forms Designer code doesn't do
>> that so it wouldn't be persistent across instances.
>>
>>> Now my question is:
>>>
>>> Is there a reliable way how I could find the HWND of a .NET control
>>> using
>>> win32 calls?
>>
>> I'm confused. The first part of your question said that you can retrieve
>> the ID, but it's changing from instance to instance. To do that you'd
>> need the HWND so that you can use that in the call to GetWindowLongPtr().
>> Given that the first part of your question implies that you already have
>> the HWND, why are you now asking how to get the HWND?
>>
>> Also, a minor point: if you're calling GetWindowLongPtr(), you should be
>> passing GWLP_ID as the index. GWL_ID is for GetWindowLong(). Of course,
>> given that you're just getting the control index and not an actual
>> pointer, maybe it's better to just go back to using GetWindowLong().
>>
>>> For buttons it is ok, they have unique windownames (that is the label on
>>> them), so I do not strictly need the ctrl id. But the windowname of an
>>> editbox is its content, that is not unique on this complicated dialog.
>>>
>>> I do have access to the vb.net code, so I can do modifications if that
>>> can
>>> help my situation, but I do not want a COM interface that returns the
>>> HWND
>>> for the requested control, I hope there is a solution more elegant than
>>> that.
>>>
>>> Do you have any sugestions other than to find a control by its position?
>>
>> Well, it seems to me that you could in fact add some code to the dialog
>> Form's constructor that explicitly sets the GWL_ID for each control.
>> Just use p/invoke to get at the SetWindowLong() function, and call that
>> for each control with whatever ID you want to set.
>>
>> Pete
>
>


From: Peter Duniho on
On Thu, 21 Aug 2008 06:27:52 -0700, Jozsef Bekes <bjdodo(a)hotmail.com>
wrote:

> Hi Peter,
>
> I have got a response in another forum. This looks better, although not
> perfect:
>
> "You can fill "AccessibleName" property with unique ID string for a given
> control. Then, from the tester application call
> `AccessibleObjectFromWindow'
> in order to obtain `IAccessible' interface for the control. Use the
> `IAccessible::get_accName' method to identify your control."

The IAccessible interface is part of the larger accessibility support in
Windows. I would not personally use it to accomplish some other unrelated
task. YMMV.

I also don't see how using that is significantly better than setting the
GWL_ID value explicitly in code. The only significant difference between
the two is in how the ID information is entered. Maybe it's marginally
easier to enter that ID in the VS Designer, but it's not that hard to just
write the code to assign it either.

Pete