ActiveX control default property discovery - vb6

Is it possible to determine which property of an ActiveX control is the default property? For example, what is the default property of the VB6 control CommandButton and how would I found out any other controls default!
/EDIT: Without having source to the object itself

I don't use VB, but here it goes.
I found Using the Value of a Control, but it's not a programmatic solution.
If you have access to the code, look for
Attribute Value.VB_UserMemId = 0
using Notepad.

It depends on when you want to determine this. You could print the "value" of, say, a label control (which has no "value" property) to the debugger like:
debug.print "Value for cmdTest is ["+format(cmdTest)+"]"
Which will give you something like:
Value for cmdTest is [False]
As it turns out, the default value for a command button is it's state (pressed or not), so if you put the code example above in the click event for the control, you will see "True", if you execute it somewhere else, you'll see "False".
For other results, this method will at least show you the sort of property you're looking for. You could use:
debug.print "cmdTest's value is of type ["+TypeName(oObject) +"]"
which tell you the actual type, namely:
cmdTest's value is of type [Boolean]
You could use various methods to narrow things down, such as setting the value and seeing what happens.

Use OLE/Com Object Viewer, which is distributed with Microsoft Visual Studio.
Go to type libraries and find the library the control is housed in, for example CommandButton is stored in Microsoft Forms 2.0 Object Library. Right click the library and select view. Find the coclass representing the control and select it:
As can be seen, the default interface for CommandButton is ICommandButton, when you inspect ICommandButton look for a property that has a dispid of 0. The IDL for the dispid 0 property of CommandButton is:
[id(00000000), propput, bindable, displaybind, hidden, helpcontext(0x001e8d04)]
void Value([in] VARIANT_BOOL rhs);
[id(00000000), propget, bindable, displaybind, hidden, helpcontext(0x001e8d04)]
VARIANT_BOOL Value();
Showing you the default property.

you have access to the code, look for
Unfortunetly I don't have access to the code for most of the controls. However the link is useful for the Microsoft Controls, but I still would like a way to know for other controls.

Related

What difference between control's window handle and controlID

I'm learning Win32 assembly. Have some question I search but not suitable result.
Anyone can explain for me What difference between control's window handle and controlID.
They have nothing in common. Every window has a handle, returned by CreateWindowEx(). Such a window can have a few extra properties attached, like a menu handle. The hMenu argument in CreateWindowEx(). If the window doesn't have a menu, a child window won't have one, then you can use that argument to pass an arbitrary other bit of data. It will be assigned to the GWLP_ID property (see GetWindowLongPtr). Also note the GWLP_USERDATA, an extra property that's entirely yours to use as you see fit.
Dialogs take advantage of this, a dialog template that you create in the resource editor gives you a way to number the child controls. With a helper function like GetDlgItem() to get the handle back for a control with a specific number. Which is pretty necessary for dialogs since it is Windows that create the child controls from the dialog template so you don't know the window handles for them yourself.

UI Automating a VB6 application from .NET

For the last few days i have been trying to figure out the best way to get AutomationElement for a specific control in a vb6 application.
My initial way of doing so was by doing a search with the following condition:
new PropertyCondition(AutomationElement.NameProperty, controlName)
I was under the assumption that this was working correctly for about a week in a little test VB6 application.
but i few days ago i realized something... when i dragged a vb6 textbox into the form, the 'Name' property and 'Text' property were both set to 'Text1'
So when i searched with:
new PropertyCondition(AutomationElement.NameProperty, 'Text1')
it return the correct element, but if i then went and set the 'Text' property to '' the same search would bring nothing back.
Question: Has anyone found a way to get a AutomationElement based on a the VB6 control name
What i have tried:
getting the MSAA equivalent interface and looking at the 'Name' property - Result: ''
http://msdn.microsoft.com/en-us/library/windows/desktop/dd318490%28v=vs.85%29.aspx
getting the control based on other properties (AutomationId, RuntimeId) - Result: AutomationId - not all controls seem to have this property available - RuntimeId - changes each time the app runs
I have looked at alot of different sites the main one is listed below - while some say they have manage to get it working - i don't believe i can see how they do it.. or i just dont understand it :$
http://blogs.msdn.com/b/brianmcm/archive/2006/01/17/getting-the-winforms-id-of-a-control.aspx
While i have access to the demo app, i will not access to the production app as that has been created by a third party.
What i plan on doing from here is to get the Automation element based on their position on the form..
Thank you
Can't comment due to low rep. Do you absolutely HAVE to have an AutomationElement?
You may want to look at invoking [user32.dll] (http://pinvoke.net/default.aspx/user32.EnumChildWindows). Look at FindWindowEx, GetWindow, EnumWindows, EnumChildWindows, GetWindowText, etc.
You need the handle of the parent window, so you can use this loop to get it. From there you can use the other functions to get the information you need about the control.
IntPtr hWnd = IntPtr.Zero;
foreach(var process in System.Diagnostics.Process.GetProcesses())
if(condition)
hWnd = process.Handle;
Comment with the exact information you need out of the VB6 window, and I'll give you better code.
You can use the relational position of the AutomationElement in a specific Window (or any other container for that matter), in order to detect it. For example, if you have 5 TextBox AutomationElements in your main window, and you're certain that the order will not be changing, you could create a PropertyCondition on the TextBox class name, and then use the FindAll method to return a collection of AutomationElements and iterate through it, querying the BoundingRectangle property to find out which is the lowest one (or middle, or any other position, for that matter).
I would create a helper method that would return a Dictionary<int,AutomationElement> with the key being the visual position of the AutomationElement, and the value being the AutomationElement itself.
This way you can avoid using a specific Point on your screen (any window size change or element positioning will easily break your code) while not being bound to the AutomationId property.

Tooltip only shows when running from source

I have a hierarchical flexgrid control with the ToolTipText property set, and when I run from source the tooltip displays as it should. But when I compile it and run that way, the tooltip doesn't display.
I've tried to remove anything listening to MouseMove in the hopes that that would fix it, and when I add some code to put the tooltip text into a message box, it appears to be set correctly. Can anyone think of why this would be happening?
Update: It appears that the problem arises when I host the grid inside another user control. E.g.: make container.ctl, which is just a blank control but with ControlContainer = True. Then make gridholder.ctl, which is a mshfg inside of a container.ctl. Lastly, embed gridholder.ctl into some form. Tooltips on the flexgrid don't appear to show up.
I'm interested to see how reproducible this is...
I haven't found a workaround for this issue yet, but I have a better idea of why it's happening after some testing and stepping through some of the VB6 runtime code in WinDBG.
The first interesting thing is that VB6 doesn't use the standard tooltip display mechanisms provided by Windows. For example, it doesn't use WM_NOTIFY messages to show/hide tooltips, or any of the other "standard" tooltip support described in the documentation explaining how tooltips work in Windows.
Instead, the VB6 runtime has its own way of managing and displaying tooltips. In principle, it's similar to in some ways to the standard Windows way of dealing with tooltips, but it's also different in a quite a few areas.
A breakdown of how VB6 does tooltips:
When a VB6 program starts, the runtime uses SetWindowsHookEx to install a mouse hook for the program's main thread.
The mouse hook intercepts all mouse messages sent to the program, in particular all WM_MOUSEMOUSE messages
Whenever the mouse hook runs, it calls an internal method in the VB6 runtime to get the object pointer (HCTL) of the control that the mouse is currently over top of. Note that this is an actual COM interface pointer, not a window handle.
It translates the HCTL to the corresponding window handle (HWND).
It checks to see if the mouse position is within that window's rectangle.
If so, it retrieves the ToolTipText property for the control. If this is not empty, it creates a tooltip window and displays the tooltip after a 700ms delay.
The problem with the MSHFlexGrid (and I imagine other controls that are not standard VB6 controls) is that this code doesn't retrieve the correct HCTL when you hover over the control and it's inside a custom container.
In that case, the code retrieves the HCTL of the custom container, not the HCTL of the MSHFlexGrid itself. Therefore, it retrieves the container's ToolTipText property (which is empty) and not the grid's ToolTipText, and therefore won't display a tooltip.
I'm not sure exactly why it does this, because as noted in the comments on your question, all of this works correctly if you use a PictureBox as your container.
I suspect the PictureBox has code to handle this correctly that is not included when you create your own container.
I'll update this answer with an actual workaround if I can find one. The only thing I can think right now is to somehow "sync" your container's ToolTipText property with the grid's ToolTipText property, so that when VB6 requests the container's ToolTipText, it will return the value of the grid's ToolTextTip property instead.
This is easier said than done, however, because ToolTipText is an extender property, and extender properties take precedence over properties that you write yourself that have the same name.
After a bit of research, I found what I think is the underlying problem. Your user control is not implementing any method for the controls to interact with. User Controls that are Container Controls need to implement the Extender functionality. These two links are the best I've found on the subject so far.
http://www.justvb.net/obook/ch7.htm#UsingtheExtenderObject
http://msdn.microsoft.com/en-us/library/aa733622(v=vs.60).aspx

How do I add a Label to a display method in Dynamics AX 2009?

I would think you should be able to define a label on a display method. However, I can't see it in the properties window. But there is a Best Practice Warning:
Control label is a copy of its display method label
So who can either tell me how to add the label or what this error message is really about?
The return type for the display method should be an Extended Data Type. On the EDT you should supply the label.
Each form control must have a label either inherited from EDT/Enum or explicitely set on the control. The label set on the control must not be the same as the EDT/Enum's label. I suppose in your scenario it is the same, and in order to get rid of this BP warning you should just clear the label in the control properties. If you want the label to be different you can change it in the control properties or in the Extended Data Type/Base Enum properties but then it will be changed everywhere througout the system.

Ultimate grid invisible

I am trying to use ultimate grid from Code Project in a dialog box but the grid is invisible.
m_Plist.AttachGrid(this, IDC_CREDENTIALS) returns true but the static text place holder where the grid should be shown cant be seen and the grid is never displayed.
I am using sample the code from here http://www.codeproject.com/KB/MFC/UltimateGrid_Start.aspx?display=PrintAll&fid=452565&df=90&mpp=25&noise=3&sort=Position&view=Quick&select=2629959&fr=51#Using_the_Grid_in_a_CDialog
I have installed the latest update UltimateGrid72_Src_Update03.zip and Im using VS2008 SP1.
Thanks...
BOOL CCredentials::OnInitDialog()
{
CDialog::OnInitDialog();
MyCug m_PList;
m_Plist.AttachGrid(this, IDC_CREDENTIALS);
}
I've not used Ultimate Grid myself. However, looking at the code you posted, I can see that there is likely to be a problem: you declare an instance of "MyCug" on the stack, then attach it, but that stack-based instance will be destroyed as soon as the OnInitDialog() method exists. What you must do is put the declaration of "MyCug m_PList;" as a member of the dialog class, so that the lifetime of the grid object is the same as the lifetime of the dialog.
I don't know why your grid is not displaying, things to look for are is it correctly loading from the dialog template, and is it visible? You can use spy++ (a tool distributed with visual studio) to see what windows are actually created in your dialog, where they are and the flags and styles set on them.
After you create and attach the grid, are you adding rows and columns as defined by the examples?
Otherwise, there isn't going to be anything to see.
You'll need the following code in MyCug::OnSetup():
void MyCug::OnSetup(){
//*******Set the Rows and Columns
SetNumberCols(10);
SetNumberRows(10);
}
That's from the tutorial in the 7.2 version. I used UG extensively, and have no problems with VS2008. But I create all my grid myself, I don't use dialog templates.

Resources