Unable to get ATL Connection Points working - c++

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

Related

Changing button name MFC Visual Studio

I just started the GUI development, i had started on C++Builder but i switched to Visual Studio for differents reasons. But in Visual Studio, i've got a big problem :
In the GUI development interface (rc file) i can create buttons and place it, but i can't change there names. The name for all of MFC components i placed is initialize to a default name which i can't call and i can't change the property by the properties interface, i can change the Text, for change the Label of the Button, but not the name...
It's very incomfortable because by that i can't call my buttons for do anything, i have the same problem for Listboxs, so i can't modify my list because i can't call there
I just want to modify access my component by my c++ code for modifying this component
enter image description here
Thank for your help !
The MFC way of doing event handling is a bit more elaborate.
After the control is created on the form in the designer, an ID is generated ("IDC_BUTTON1" in the attached screenshot).
This is the ID that will be used for accessing this UI control from the code.
All this can be done via the designer also as shown in this article.
Basically, in the background this generated ID is put in a 'message map'
(more about message maps here).
In short 'message map' is used to specify what action needs to be performed when a certain type of action is done on the UI control by the user.
For, example if the button click is to be handled then in code:
the message map would look like:
BEGIN_MESSAGE_MAP(CSurface3DView, CView)
ON_BN_CLICKED(IDC_BUTTON1, CallMyFunction)
END_MESSAGE_MAP()
'ON_BN_CLICKED' is a predefined event macro.
The 'CallMyFunction()' function has to be declared with 'afx_msg' in the class. Besides please, have a look at data exchange mechanism as well. This know-how about data exchange will come in handy going forward.

Why is IExplorerCommand::Invoke() no longer being called?

I have created a File Explorer context menu extension that uses the IExplorerCommand interface to add menu commands to the Windows 11 context menu.
This has been working fine, but after the last Windows update, it no longer works properly.
Although the menu commands still appear, nothing happens when I click on any of them. I've added logging and I can see that IExplorerCommand::Invoke() is no longer being called.
Strangely, if I select the "Show more options" menu to get the legacy Windows 10 context menu, the commands work fine from that menu, it is only in the new Windows 11 context menu that they don't work.
I have tried running File Explorer in a debugger while selecting my menu commands, and I get lines like this in the output window when I click on the command:
onecore\com\combase\dcomrem\stdid.cxx(726)\combase.dll!00007FF9EB9947F5: (caller: 00007FF9C22E1E38) ReturnHr(2627) tid(67bc) 8001010E The application called an interface that was marshalled for a different thread.
I'm guessing this is the reason why my commands are not being called. Does anyone have any suggestions for what is causing this? Could it be a bug in File Explorer?
I've tried both STA and MTA threading models, and changing this made no difference.
Well, after wasting hours on this I finally have a solution!
My code was based on the PhotoStoreContextMenu sample code here:
https://github.com/microsoft/AppModelSamples/tree/master/Samples/SparsePackages/PhotoStoreContextMenu
This uses the Windows Runtime C++ Template Library (WRL), and defines the base classes used by the class like this:
class TestExplorerCommandBase : public RuntimeClass<RuntimeClassFlags<ClassicCom>, IExplorerCommand, IObjectWithSite>
The change that fixed it for my code was to use WinRtClassicComMix instead of ClassicCom, i.e.
class TestExplorerCommandBase : public RuntimeClass<RuntimeClassFlags<WinRtClassicComMix>, IExplorerCommand, IObjectWithSite>
I'm pretty sure this problem started when I installed KB5019509, which is the Windows update that changes File Explorer so that it now has tabs.
Note: this problem only happens for IExplorerCommands created in the plug-in for submenus, the top level commands that are defined in the APPX file work fine.
Also note that although this change does fix the problem with Invoke() not being called, it does introduce a new problem which is that IOleWindow::GetWindow() no longer works so it is not possible to get the parent HWND. (See Calling IOleWindow::GetWindow() from IExplorerCommand::Invoke() is giving error 8001010d (RPC_E_CANTCALLOUT_ININPUTSYNCCALL)).

How to get file type of selected item in CTreeCtrl? The file name extensions may be hidden, so GetItemText is not helpful

I'm taking over an old project built with MFC. I'm not familiar with MFC at all, but I need to add a few new features to this project.
There is a tree list in the program, showing files on your computer. Double-click an item and the corresponding file will be imported into the project. At first, I used the following code to get the selected file name:
HTREEITEM hSelectItem = m_wndTree.GetSelectedItem();
CString filename = m_wndTree.GetItemText(hSelectItem);
But later, the method failed on others' computers, because they may check hide file name extensions so a file named "Arial.ttf" will return "Arial".
What is the best way for me to the full path of a selected item? inherit CTreeCtrl and override some functions may be a choice, but not familiar with MFC can cost me a lot of time and will get hands dirty. Are there any APIs or third-party libraries I can use?
Besides, The actual class I'm using is CMFCShellTreeCtrl, which has a public method GetItemPath, but there is a bug in it so I can't use this method to get the full path.
Thanks!
If you are talking about this bug, it was fixed back in 2010, so it should be resolved starting with MSVC 2012, I guess. If you need to work with MSVC 2010, then you might consider overriding the original CMFCShellTreeCtrl and replacing the buggy GetItemPath with the current implementation which you can easily take from a current compiler version.
The control has SetItemData and GetItemData methods that it inherits from CTreeCtrl. So when the control is being populated you can put the full file name or path into a heap-allocated string (CString) and save the address of the string with SetItemData. Then you can get it back when an item is clicked.

Deleting / Editing ATL COM DLL properties / methods

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?

Creating a DialogBar with MFC with my own controls

I'm turning mad with a little problem with Visual Studio 2008 and MFC. I'm working on a project actually and I'm trying to create an SDI Application. Right, now I want to add a dockable DialogBar. Well, the first time I added it with the resource view, I could create the bar without problems.
But... I want to add some controls like a couple of ListBox, buttons and so on. The program doesn't allows me to create member variables for these controls. The option appears in grey.
Searching a little, I found that it's mandatory to create a new class derived from CDialogBar and "enhance" it with the Message handler and so on. I've been reading some tutorials and it didn't work for me.
Can you please help me? I'm starting to get nervous, the use of dialogbars is mandatory in my design and I've never implemented them before.
Thank you very much, and sorry for my poor english.
You can add a control member variable by hand instead of using the wizard. All it takes is a call to DDX_Control in the dialog bar's DoDataExchange function.
But CDialogBar-derived classes do not handle control clicks. The CDialogBar class forwards all of those messages to the dialog bar's parent window. So be prepared to add the message handlers to the parent (usually CMainFrame).
For learning purposes you might try creating your dialog bar as a CDialog first, to see the proper code lines and message map entries supplied by the wizard. Then you can copy/move these details as appropriate into your actual code project.