Is ther an "initialisation complete" function available for an ActiveX? - windows

I'm creating an ActiveX using VS and MFC. Initialisation is done in constructor of my control. There the m_hWND window handle is not valid, it is still NULL.
So: is there some kind of "initialisation complete" function available in COleControl() that is called as soon as m_hWnd is valid and additional controls can be added to it?
Thanks!

It's been a while since I've written an ActiveX control, but, I seem to remember using OnResetState, or, one of the other events shown in the link to handle initialization.

Remember that there are windowless ActiveX controls. For such controls you never get a window handle!
So normally after the creation a ActiveX Control is "initialized", and you can use it.
ActiveX controls usually reside in the same Thread so there is nothing that can run beside your code and do further initialization.
If this doesn't help you Need to refine your question.
See discussion here too about ActiveX controls without a window handle.

I think OnActivate is what you are looking for.

Related

Delphi XE2 assigning Application.MainForm.Handle to Application.Handle inside a DLL

I have a small issue with forms that are created from inside a DLL.
Basically what happens is when a form (Form1) from a dll is showing (I think it has to be stay on top) and you open another form (Form2) which is apart of the main application (i.e. does not live inside the dll). If you put your cursor over a control on Form2 so that the hint is displayed, Form2 will immediately go behind Form1.
This only happens with MainFormOnTaskBar is true. At the moment we are passing the main application's Application.Handle to the DLL and assigning that to Application.Handle of the DLL.
I have managed to resolve the issue by instead passing Application.MainForm.Handle to the DLL to be assigned to Application.Handle in the DLL.
Is this safe? does anyone know the proper way to fix this problem?
Your solution is perfectly reasonable. I have an Excel COM add-in that does something very similar. In that code I set Application.Handle in the DLL to be the window handle of the Excel main window. That's analagous to what you are doing.
The issue is that you need to get the window ownership set correctly. You need the chain of ownership to reach all the way back to your app's main form. Forms in a DLL have no knowledge of what the main form is, and so you have to provide that knowledge.
Note that I am talking about the concept of window owner as used by Windows and not the VCL concept of owner which is totally different. In VCL terminology this is known as popup parent and you could solve your problem by explicitly setting the DLL form's popup parent to be the main form. The relevant properties are PopupMode and PopupParent. For the forms that live in the main app, the VCL will naturally make their popup parent be the main form.
However, having talked about explicitly setting popup parent, I would stress that your current solution is simpler and more convenient.
What both of these solutions do is to make sure that all auxiliary forms are owned by the main form. That means that these forms are always on top of the main form. It means that the auxiliary forms will be minimized if the main form is minimized. Read about owned windows here: Window Features.
Incidentally, if you had been using runtime packages rather than a DLL, the code in the package would be connected to the same VCL as the main form. So the packaged code would be able to see the main form and set the window owner appropriately. This is certainly one advantage of using packages. Of course, there may very well be a good reason why you need to use DLLs rather than packages.

Detecting creation of a MessageBox

My application is loading 3rd party DLLs, and some of this DLLs open MessageBox windows.
Is there a way for me to detect when such a window was being opened?
You'll need a CBT hook to receive a notification when a MessageBox window is displayed. You install this by calling the SetWindowsHookEx() function and specifying WH_CBT for the hook ID parameter. The hook callback function will provide you a handle to the MessageBox window, which you can then use to close it.
If you know exactly when to expect the MessageBox is being created and shown, then you can adopt a lighter and simpler approach than a global hook. This would involve calling the FindWindowEx function to get a handle to the MessageBox window, which you can likewise use to close it.
Of course, to close it properly, you will need to know which type of MessageBox it is (that is, which of the standard button choices that it displays) so that you can simulate a click of the desired button. Simply managing to get the MessageBox to disappear off of the screen without providing a valid answer is highly likely to have unexpected results in terms of the library code.
It bears explicit mention that this is really bad behavior on the part of a DLL. Unless absolutely necessary, ditch whatever 3rd party that is foisting such poorly written code upon you. If it is absolutely necessary, well then that's a red flag: work hard to eliminate it as a necessity. You shouldn't have to write and maintain gobs of code to work around their inability to get the big obvious things right.

IsWindow(activeX.GetSafeHwnd()) always false after upgrade to VS2010

I have an MFC application that uses an ancient (circa 1999) third-party ActiveX control.
Since upgrading the project from VS2008 to VS2010, I'm having problems...
In the OnSize handler of the parent dialog IsWindow always returns false for the handle returned by control.GetSafeHwnd(), even when GetSafeHwnd() returns a non-NULL value. The rest of the control's parent dialog is displayed fine, but it doesn't seem to respond to any input.
I've seen this article, but GetSafeHwnd() isn't returning NULL in this case (after the first time that it is called, which is before the control is instantiated).
The control does cause the trace message "Control wants to be windowless" to be output when it's loaded. However it also does this when compiled in VS2008, so this may be a red herring. Searching for this message points me to creating a class derived from COleControlSite, and denying the control windowless-ness, but it seems there are no good example of this available, and as I say, it's not clear that this is really the cause of the problem.
I've also found this issue mentioned on MSDN's VS2010 porting page:
"An ActiveX control compiled by using Visual C++ 6.0, when embedded in
a dialog box in a project developed by using Visual C++ 2010, may
cause your program to assert at run time. In this situation, open the
ATL or MFC project associated with the ActiveX control in Visual C++
2010, and recompile it.. The assert will be in the file occcont.cpp,
on this line in source: ASSERT(IsWindow(pTemp->m_hWnd))."
I assume that there's something about VS6-compiled ActiveX controls that causes the window handles to be treated as invalid by the current Win32 implementation of IsWindow. The suggested solution is of course unhelpful as it's a third-party control, and we can't recompile it.
Has anyone managed to get around this?
I've already found solutions for VS2010 projects not running on Windows 2000, and errors linking to ODBC, but don't seem to be able to find anything on this one.
Thanks,
Chris
I didn't find a solution to this in the end - upgraded the controls to a VS2010-compatible version.
For what it's worth: if you don't care whether the control will appear transparent or not, you may force the control to have a window anyway - even though it can operate without a window.
You see, the ActiveX control must first ask the container (the window which will host the control) if it's okay to be activated without a window. This is simply because not all containers support windowless activation.
If this interface (IOleInPlaceSiteWindowless) returns okay then it proceeds with this special windowless activation, if not a window will be created for the control as normal.
Disclaimer:
I don't know if this 'unnecessary' window will make the assertion failure go away. In other words: I don't know if the window handle is passed down 'deep' enough into the AX control.
More about the IOleInPlaceSiteWindowless interface:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms682300(v=vs.85).aspx

How can I get the name of a Visual Basic control given its HWND?

I'm working on a little macro record/replay tool which can automate a few very old Visual Basic 6 GUIs we have. To do so, I'm identifying the controls by their name (the value of the name property of a control, that is).
One part of this tool needs to determine the name of a control given its HWND. For newer Visual Basic applications which were done using VB.NET, I can use the WM_GETCONTROLNAME window message. This works nicely.
However, this message is not understood by older windows. Is there any way to do this for controls of Visual Basic 6 applications? A solution which does not require being in the process of the GUI would be preferrable, but if I had a solution which only works inside the GUI process then that would be acceptable as well (since I can do the injection myself).
UPDATE: One thing I just tried, this moderate success: I used the AccessibleObjectFromWindow to check for implementations of the IAccessible interface of the object which shows the given HWND. In case I get an implementation (it seems that many [all?] Visual Basic controls implement this interface), I use the accName property to read out the "accessible name". Sometimes this does yield a useful string, but usually it doesn't.
I believe the only way would be getting inside the process and obtaining a pointer to the Form object, yet I have no idea how to do it from outside.
Is it possible you add support for the WM_GETCONTROLNAME to those older applications?
Or maybe, you could identify the controls by some other, natively-available properties?
Other that that, as Raymond is saying, there isn't much you can do.
Can you modify the vb6 apps? if so in each form load event you could iterate me.controls and use the SetProp(ctrl.hwnd, "MYNAME:" & ctrl.name, 0) api to add the name to the window's own property list, then in your other app you can EnumProps(ctrl_HWND) looking for the one that begins with MYNAME: and parse out the value.

Getting screenshot of Child Window

If I have a handle to a window, how do I take a screenshot of any new child windows when they show up? Right now I have code that takes a screenshot every .1 seconds of a windows form. When I click on a drop down list box the subsequent screenshots do not include it. Using spy++ I can see that a new child window was created but not sure how to make sure it is included in my screenshots. Does anybody have any code that might include child windows?
Thanks in advance,
Bob
Yes, the dropdown of a ComboBox is a special window, a LISTBOX. .NET doesn't provide a built-in way to get the handle for it, you can P/Invoke SendMessage and send the CB_GETCOMBOBOXINFO message. COMBOBOXINFO.hwndList contains the handle.
Note that there are other controls that behave that way, DateTimePicker for example. Also note that the window can extend beyond the bounds of your form.
The code in this thread should be helpful to get the P/Invoke right.

Resources