Using C++/CLI, How to display a managed control (eg. System::Windows::Forms::Panel^) on a window created in native code?
An external program calls my native method where i can access it's window via
SubclassWindow(hNativeWindow, MyNativeWindowProc);
Then I create control with something similar to:
MyNameSpace::MyControl^ ctrl = osozKomunikator = gcnew MyControl("SomeText", hNativeWindow);
ctrl->Show();
MyControl is derived from System::Windows::Forms::UserControl and has overriden CreateParams to set Parent to hNativeWindow.
As the result the control flashes and dissapears, does not show at all or shows only after I slow down the execution with the debugger.
Please help.
Windows Forms supports being hosted like ActiveX in native windows since .Net 1.1. The host needs to implement some interfaces, though. MFC 8.0 wrapped around the necessary code in CWinFormsDialog and CWinFormsView. Use MFC's support classes if you can. If you can not, install MFC from Visual C++ 2005 or higher and check the source code of MFC's OLE support classes, like COleControlContainer, COleControlSite, etc.
Related
We have an application built against MFC9 (VC2008).
The application is an SDI application, and shows a file open dialog during InitInstance(). Showing that dialog causes comdlg32.dll to be loaded. Some minutes later, the comdlg32.dll is unloaded automatically. After this, the next function depending on the DLL will crash.
How can this be avoided? What governs the automatic unloading/loading of the DLL?
Further info:
We don't see this problem on WinXP with the same application.
On Win7, this behavior only occurred since the beginning of this year - maybe some MFC update is related to this?
A small test application does not exhibit the problematic behavior - the comdlg32.dll is re-loaded when needed.
We’ve found a statement by Microsoft that it isn’t recommended to use modal dialogs in InitInstance() of MDI applications (http://support.microsoft.com/kb/173261) - we have an SDI application, though.
We don't directly use comdlg32.dll in any way, only indirectly through the MFC.
You have to call InitCommonControlsEx in your application on startup.
This will initialize the comdlg32.dll and also increase the reference count of the dll, so it won't get unloaded after closing a file-open/save dialog.
You don't say whether you customize your dialog or it is just a straight up file dialog. I think starting with Vista, the common file dialog was changed some. I know if you compare older MFC code with newer, you will see that the MFC code has been changed to take advantage of those changes. For instance, the IFileDialogEvents and IFileDialogControlEvents were implemented in MFC to support the way Vista and later versions of the OS customize file dialogs.
I don't know if I have an answer, but just for grins I would probably make sure I call AfxOleInitialize() sometime in InitInstance() before I tried to call the file dialog.
The other thing I would try for sure (since it works under XP) would be in the constructor of your CFileDialog would be to make sure to set bVistaStyle to FALSE. This ensures m_bVistaStyle is set to FALSE which it is set at when running under XP.
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
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.
I have an ActiveX control (created using C#) that I am adding to a form in Visual FoxPro using late binding. It works without problems when I register the control.
I want to use reg free COM and created necessary manifest files. Now it load and displays in an inactive state until I double click or grammatically activate it. I don't think it has anything to do with the reg free com manifest files. However is there something I need to do to set it up before/after making the late binding call AddObject()?
this.AddObject('OleControl1', 'oleControl', 'SomeCompany.SomeOleControl')
When I check the OleTypeAllowed Property of the OleControl created by AddObject() it is 1 (Embedded OLE object) instead of -2 (ActiveX object). So the OleControl got instantiated to the wrong type.
I also tried the following:
DEFINE a subclass of OleControl and set the property OleTypeAllowed = -2. Used late binding to load the control. It did not work as required. The OleTypeAllowed came back as 1
Registered the ActiveX control. Added the ActiveX control to the project as a subclass using the visual editor. Unregistered the control. Used late binding to load the control. It did not work as required. The OleTypeAllowed came back as 1.
Is it possible to load the OleControl as a ActiveX control?
Any input from VB that I can convert to FoxPro would also be appreciated.
You probably have the miscStatusContent attribute wrong. This a snippet from a VB6 app manifest we deploy:
<file name="External\COMCTL32.OCX">
<typelib tlbid="{6B7E6392-850A-101B-AFC0-4210102A8DA7}" version="1.3" flags="control,hasdiskimage" helpdir="" />
<comClass clsid="{9ED94440-E5E8-101B-B9B5-444553540000}" tlbid="{6B7E6392-850A-101B-AFC0-4210102A8DA7}" progid="COMCTL.TabStrip.1" threadingModel="Apartment" miscStatus="" miscStatusContent="recomposeonresize,cantlinkinside,insideout,activatewhenvisible,setclientsitefirst">
<progid>COMCTL.TabStrip</progid>
</comClass>
....
</file>
Notice that miscStatus has to be explicitly cleared.
We are using UMMM for manifest creation in our automated builds.
In VB6, ActiveX DLL is listed as a project template but in VS 2005+ there is no such thing. Where is my good old ActiveX DLL template? Many thanks in advance.
A couple of concepts; .NET Assemblies are the functional equivalent to ActiveX DLLs in the .NET langauges. .NET Classes and method can be decorated with attribute that have various meaning in different context. A .NET Assembly can be turned into a ActiveX/COM DLL (or OCX) by using various attributes to assign the correct GUIDs.
A basic overview of setting a .NET assembly use COM is here.
Note that do google searches you should include VB6 .NET and COM (not ActiveX). COM generates more hits as it is the underlying technology behind the ActiveX term.
The MSDN article I linked shows a basic COM setup for a .NET Class. The attribute here is the ComClass Attribute.
<ComClass(ComClass1.ClassId, ComClass1.InterfaceId, ComClass1.EventsId)> _
Public Class ComClass1
#Region "COM GUIDs"
' These GUIDs provide the COM identity for this class
' and its COM interfaces. If you change them, existing
' clients will no longer be able to access the class.
Public Const ClassId As String = "6DB79AF2-F661-44AC-8458-62B06BFDD9E4"
Public Const InterfaceId As String = "EDED909C-9271-4670-BA32-109AE917B1D7"
Public Const EventsId As String = "17C731B8-CE61-4B5F-B114-10F3E46153AC"
#End Region
' A creatable COM class must have a Public Sub New()
' without parameters. Otherwise, the class will not be
' registered in the COM registry and cannot be created
' through CreateObject.
Public Sub New()
MyBase.New()
End Sub
End Class
There are other Attributes as well that are especially useful if you trying to subsitute a .NET assembly for an existing COM DLL or OCX. Finally .NET has a lot of different wizards that help you with the tedious details.
Try this: http://msmvps.com/blogs/pauldomag/archive/2006/08/16/107758.aspx
It outlines how to create an activex control and use it in a web page. As far as I know there's really no 'ActiveX' project template since .NET does it differently. However you can make your .Net controls visible to the COM world, which the article above illustrates.
It's not quite clear from you question, but if you want to be able to consume in VB6 (or some other com environment) something created in VS2005, you want to look at the Interop Forms Toolkit. This greatly simplifies interop between VB6 and VS2005. Now if you actually want to distribute those applications, installing what you created becomes a lot more fun (Hints: Don't use the GAC, install the .Net dll in the same directory as your application executable, and learn to use RegAsm.)
If you give a little description what you want to use the ActiveX.dll for (project library or User Control) and what environment you want to use it, more advice can be given.
I don’t know if this is what you are trying to do or not. But if you right click on the Toolbox in Visual Studio, in the popup menu select Choose Item…
When you get the “Choose Toolbox Item” dialog box come up, select the “COM Components” tab and check the COM Component(s) you want to add to the toolbox. I have done this to added the “Windows Media Player” to the toolbox and used it in a C# Winform.
From this dialog you can access any COM, OCX or ActiveX control loaded on you system.