Deleting / Editing ATL COM DLL properties / methods - c++

I have created a COM ATL DLL in VS2012.
Adding events and properties is very easy.
However, I see no easy way to edit or delete an event or a property.
VS2012 automatically creates a lot of code for the event or property when I use the Add Wizard, and I am not sure if I should really delete or change this automatically created code manually when I made a mistake and want to replace or delete something.
Is there a way to edit and delete them in a clean way?
Perhaps there is a property / event manager somewhere in VS2012, but I did not find it.
Thank you!

You edit declaration of the methods/properties of your interest on IDL, and then the project stops building until you respectively fix it by reflecting changes on your C++ implementation - that's it.
IDL changes along with implementation updated respectively builds you updated DLL.
Be aware that applications which are already built against earlier method/property set might be in trouble after the update. Related earlier questions you might be interested in (you might, however be not - which I sense is the case at the moment, if your question is about updates while you are developing, and not updates on released module):
COM: If I change the parent of an Interface do I need to create a new Interface?
Would adding a new function to the existing COM interface break its binary compatibility?
Why is it necessary to add new events to the *end* of an IDL interface?

Related

How to save layout settings of MFC application?

I understand there are functions that can easily write windows registry, however I found out that in new MFC project created with wizard, some information (like split bar position, visibility of controls) gets stored automatically (or at least I found no CWinApp::Write* calls in the project). Since I have also older projects that don't have this behaviour I need to figure out how to make this without help of project wizard. Would anyone please know how does this work?
The MFC control state saving magic happens in the 'New' MFC Feature Pack, specifically in the SaveState methods, for example CMFCToolBar::SaveState.
To take advantage of this you'll therefore need to upgrade your Toolbars and Menus to use the newer controls and upgrade your application to inherit from CWinAppEx. I recommend that you use a New MFC Wizard based app as a guide on how to upgrade your old MFC app.
Most of the information is saved in CPane::SaveState(), thus if you want state of some component saved, you need to use classes derived from CPane. (for more info here is the class hierarchy).
The process of saving window states is initiated through CFrameImpl::OnClosingMainFrame(). This function in turn calls CWinAppEx::SaveState() which saves some application settings and then ALL instances of CMFCToolBar (they add themselves to global list of CMFCToolBars in call to OnCreate). In a similar way all dockable panes are saved but the list belongs to your main frame. Then positioin and size of your main frame is saved.
CViews and CFrameWnds are somewhat less favored, for what I found and tried out, the only information saved was visibility.
I used that loooong time ago. If I correctly reminds it, you should save the informations you want in a overridden CWinApp::ExitInstance() before calling base class method, and you load them in CWinApp::InitInstance. Be sure to allow for default values, because at first run, there will be nothing to load, and do not forget to call (or copy) base class.

ActiveX Property Persistance

I have a question about an ActiveX Control I am developing. I have hashed my way through most problems but I am stuck at a real road block. This ActiveX is being imorted into other software so I have to have a good implementation of the Property Pages. I have managed to get some persistant properties working with one issue. When I make a change in the property page it is updated and persists as long as the application that is development app that is using it is open but it reverts back when I reload the app. I have narrowed this down to the fact that the development app doesnt realize the ActiveX has changed and therfore doesnt save. If i make a unrelated change and save the program all is good and the values persist as expected. I have tried everything and cant seem t get the application that imports my ActiveX to realize when it has changed via the property page. I am wondering if anyone has some work arounds for this type of problem. It seems to me if I could force the DoPropExchange() it would work but I dont know how to call this explicitly.
Thanks in advance
Matt
Thanks for the input. I did have the SetModifiedFlag() but it wasnt working. After poking at it I solved that problem but now I am redirecting my question. I had removed the property above in question from the idl files dispinterface in order to prevent the application that loads the activex from displaying the property in its "Connection List"(3rd party application specific"). It appears that the app loads all the interface into this list but this is not good as some properties should be persistant and only modifiable through the proppages. I tried all the flags like hidden and local but still were displayed in the list. When I removed it from the dispinterface it was how I wanted it but would not signal the IsModified. My new question is in there another way to define properties for an instance like this or is it possible to have a secondary interface(I have not tested if the application would see this interface because I am not sure how I would go about defining this inteface)or to have a property only between the proppage and control. Or is there another way to signal the dirty. The OnMemberVariable of the control was properly executing I know from testing it just seems SetModifiedFlag() doesnt do anything if the property is not in the dispinterface
Thanks Again
You need to mark your control as "modified", so that its host could detect it and re-save persistent properties. In this case IPersistXxx::IsDirty implemented by your control would indicate dirty state.
MFC based control has COleControl::SetModifiedFlag for this purpose:
Call this function whenever a change occurs that would affect your control's persistent state. For example, if the value of a persistent property changes, call this function with bModified TRUE.
Update: To hide a property from property browser you can use nonbrowsable attribute.
Use the [nonbrowsable] attribute to tag an interface or dispinterface member that should not be displayed in a properties browser.

Using CDockingManager with CMDIFrameWnd

I was able to make a simple docking window in a proof of concept project using CFrameWndEx but in my main project, we use CMDIFrameWnd which you apparently have to use CDockingManager.
I plan on taking the already existing windows in the large program I am working on dockable so i plan on making a class that extends CDockablePane and have the existing windows extend the custom class.
How do I use CDockingManager with the CMDIFrameWnd (any examples out there)? And am I going about this the right way?
I came to the conclusion that it is practically impossible to have a docking view unless you use a 3rd party library called BCG. Here is the link to the library BCGSoft.
The project in particular to look at is called "DockingView". When you install the trial you can run and view the project. You will see that they had to rewrite a lot of the core MFC code in order to allow for docking views. It works great but it literally costs an arm and a leg to buy the license for it. So If you REALLY need to rework your MFC project its worth it.

How to replace/update an ActiveX control in a MFC dialog

I have an older MFC project build in VS 2003 that I want to port to VS 2010. The project uses an ActiveX control for grids, namely, VSFlexGrid7 from Component One. The problem is, that this version of the ActiveX control does not work in Windows 7 (which is what I have). There is a newer version of the grid, namely, VSFlexGrid8 which should be compatible with Windows 7.
The solution would be to replace all the older controls with the newer ones.
My question is, what would be the steps in replacing the controls, without touching other parts of the project. What is the simplest method to accomplish this? Do I have to modify classes, resource IDs, etc.?
[Solution: Replace CLSIDs in the .RC file]
The ActiveX control is bound to the resource file via the guid that represents the control. If you were to look inside the .rc file you will see the control with the associated guid. In your case, it's probably best to completely remove the control from the dialog (using the resource editor) assuming that you can drag the newer version onto the same dialog. Once you've done that, you'll need to generate a new class wrapper for the control. The class wizard should be able to handle that for you. Once you've got a new class wrapper that represents the control, you'll need to replace the prior wrapper class in your source code.
Usually the control is created somewhere in your dialog code with CreateInstance.
If the interface is compatible (I assume it is) , you just have to change the name or GUID that is used in the CreateInstance Code.

Unable to get ATL Connection Points working

I am trying to create a COM component using ATL, and I'd like to raise events for my VB client. I've found numerous tutorials, all of which seem to vary in details, and none of them appear to generate a working solution. Here is what I am doing:
(Using Visual Studio 2008):
Create a new ATL DLL Project. I've called it ATLEventTest.
Class View: Right clicked on ATLEventTest, Added a new ATL Simple Object class.
I called this MyObject, which generated CMyObject, IMyObject, etc...
This object was created with:
a) Apartment Threading
b) Aggregation
c) Dual Interface
d) ISupportErrorInfo
e) Connection points
Right clicked on CProxy_IMyObjectEvents<T>, clicked 'Add Function'
Function is of void return type, named someEvent, and takes an int testParam.
Rebuild.
(At this point, I should be able to see an 'Implement Connection Point' somewhere. I do not...)
Right clicked on CMyObject. 'Add Connection Point'
Moved '_IMyObjectEvents' over into the list.
Did a code search in my solution. Can't find someEvent anywhere!
Added the someEvent function again. Now, it is found in ATLEventTest_i.h
Should be able to call fire_someEvent(...) in my code, but can't.
This has been driving me insane trying to get this to work. If anyone can see what I'm doing wrong, I'd appreciate any corrections, tips, hacks, etc.
At this point, I'm tempted to say screw the wizards, and just try to modify the c++ and idl directly, but I've got a feeling that might not fair much better :(
Try using the method outlined at this location:
Adding an Event (ATL) # MSDN
With the example names you have given above, in your MyObject.idl file, you should see a declaration for your outbound even under the section for dispinterface _IMyObjectEvents. Since you right clicked on CProxy_IMyObjectEvents<T> and not on _IMyObjectEvents under the library, your IDL is probably missing the definition. The auto-generated file _IMyObjectEvents_CP.h file should be present in your project header files and should contain the Fire_someEvent() method as a result of adding the method correctly. If not, you may find that it just created a method named someEvent() instead.
Here is an outline you can try in a test project.
Create a new ATL DLL Project. I've called it ATLEventTest1.
Build Project.
Class View: Right clicked on ATLEventTest1, Add a new ATL Simple Object class. Call it MyObject.
Create the definition with a) Apartment Threading b) Dual Interface c) Connection points and whatever else you need.
Rebuild Project.
Class View: Locate the ATLEventTest1Lib library, right click on _MyObjectEvents, and "Add Method".
Method is of void return type, named someEvent, and takes an int testParam with parameter attribute [in].
You should see "[in] int testParam" as a result of adding the parameter.
On the IDL Attributes tab, change the id if necessary. Click Finish.
Class View: Right click on CMyObject, go to Add... , go to Implement Connection Point.
Select _IMyObjectEvents and click ">" to move it to the implemented connection points list. Click Finish.
Rebuild.
Now, in your CMyObject class, you should be able to call Fire_someEvent(). You will see a new method in your ATLEventTest1.idl file under the dispinterface _IMyObjectEvents; the header file _IMyObjectEvents_CP.h file will be created and will create the broadcast code for Fire_someEvent().
Does you class have an implementation of IProvideClassInfo/IProvideClassInfo2? If I recall for non-control objects, VB requires this to locate the event source interface.
Try this:
public IProvideClassInfo2Impl<&CLSID_MyClass NULL, &LIBID_ATLEventTest, 1, 0>,
and then in the interface map
COM_INTERFACE_ENTRY(IProvideClassInfo)
COM_INTERFACE_ENTRY(IProvideClassInfo2)
Maybe you have a problem with apartment threading.
Do you write console application on VB?
It requires a classic message pump to work properly (for example classic windows application).
Try different apartment mode on your COM object (MTA).
Ok. So after a new system rebuild, I have installed both Visual Studio 2005 and Visual Studio 2008. I can get this working in 2005 perfectly. Still can't get the thing working in 2008. Looks like I'm just going to have to work on VS2005 for my ATL stuff...
Thanks again to all who helped.
I was having the same issue. Kept reading the MSDN documents and searched online. Finally, I figured it out.
The main thing that the wizard isn't doing is putting the declaration in the IDL file. I manually added it, and in my class, theres a "Fire_".
Hope this helps you.
I was able to fix similar issue by deleting all _I***Events references from control's .h file