Implement COM interface registered in system - c++

How can i implement and extend COM interface registered in system. Let's asume it is delivered with some software, not part of OS.
Should i write IDL first ?
I know Microsoft's ATL samples, but none of them shows what i'm looking for.
For example here is idl for Foxit Reader Control, generated with OleView
[odl,
uuid(62F8A765-322B-41E3-B767-2D057829D66D),
helpstring("IFoxitCtl Interface"),
dual,
oleautomation
]
interface IFoxitCtl : IDispatch {
[id(0x00000001), propget, helpstring("property src")]
HRESULT src([out, retval] BSTR* pVal);
[id(0x00000001), propput, helpstring("property src")]
HRESULT src([in] BSTR pVal);
[id(0x00000002), helpstring("method OpenFile")]
HRESULT OpenFile(BSTR strFilePath);
[id(0x00000003), helpstring("method PrintFile")]
HRESULT PrintFile();
[id(0x00000004), helpstring("method SetProgress")]
HRESULT SetProgress(
int nOffset,
int nSum);
[id(0x00000005), helpstring("method postMesage")]
HRESULT postMessage([in] VARIANT strArray);
[id(0x00000006), propget, helpstring("property messageHandler")]
HRESULT messageHandler([out, retval] VARIANT* pVal);
[id(0x00000006), propput, helpstring("property messageHandler")]
HRESULT messageHandler([in] VARIANT pVal);
};
What should i do to implement this interface?
Notice: i took random interface from registered in OS, if you have working example with any other COM interface please share it
I've tried to use "Implement Interface" feature in visual studio but many interfaces are not available there

Related

Using IManagedAddin in VC++ to load VSTO VBA add-ins

I was given a VSTO Outlook add-in written in VBA, and have been tasked to reduce the start-up time. I'm rather new to the whole add-in and COM objects thing so I need some help.
The add-in takes anywhere from 0.2s to 2.0s to startup, and Outlook disables the plugin if the average startup time is >1000ms. Using the registry hack to force enable the add-in is unfortunately not an option. I've also tested it with an empty add-in, which also can take up to 1.8s to startup. I've searched SO and other such sites for a solution, and across one involving writing a "stub" in an un-managed language such as Delphi or C++, which does nothing but load the actual add-in. The interface that's supposed to do this is IManagedAddin.
My issue is with implementing this interface. I've created a simple add-in in VC++ The class that implements _IDTExtensibility2 is in Connect.h, shown below. However, I don't have a clue how to implement IManagedAddin::Load to load my add-in into Outlook, and there doesn't seem to be a lot of documentation on this. Any help would be much appreciated!
EDIT: Updated code below
// Connect.h : Declaration of the CConnect
#pragma once
#include "resource.h" // main symbols
#include "NativeAddin_i.h"
#include "IManagedAddin.h"
#include <Windows.h>
#include <iostream>
#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms."
#endif
using namespace ATL;
// CConnect
class ATL_NO_VTABLE CConnect :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CConnect, &CLSID_Connect>,
public IDispatchImpl<IConnect, &IID_IConnect, &LIBID_PixelLLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
public IDispatchImpl<_IDTExtensibility2, &__uuidof(_IDTExtensibility2), &LIBID_AddInDesignerObjects, /* wMajor = */ 1, /* wMinor = */ 0>
{
public:
static Outlook::_Application* outlookApp;
static ext_ConnectMode connectMode;
static LPDISPATCH addInInst;
static SAFEARRAY** customArr;
static UINT_PTR timerId;
CConnect()
{
}
DECLARE_REGISTRY_RESOURCEID(106)
BEGIN_COM_MAP(CConnect)
COM_INTERFACE_ENTRY(IConnect)
COM_INTERFACE_ENTRY2(IDispatch, _IDTExtensibility2)
COM_INTERFACE_ENTRY(_IDTExtensibility2)
END_COM_MAP()
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct()
{
return S_OK;
}
void FinalRelease()
{
}
static VOID CALLBACK TimerCallback(HWND hWnd, UINT nMsg, UINT timerId, DWORD dwTime)
{
KillTimer(NULL, timerId);
HRESULT hr;
BSTR manifestUrl = SysAllocString(L"file://path/to/manifest.vsto");
// load add-in
IID clsid;
hr = IIDFromString(OLESTR("{99D651D7-5F7C-470E-8A3B-774D5D9536AC}"), &clsid); // VSTOAddinLoader CLSID
IID iid;
hr = IIDFromString(OLESTR("{B9CEAB65-331C-4713-8410-DDDAF8EC191A}"), &iid);
IManagedAddin* loader;
hr = CoCreateInstance(clsid, NULL, CLSCTX_ALL, iid, (void**)&loader);
hr = loader->Load(manifestUrl, outlookApp);
_IDTExtensibility2* ext;
hr = loader->QueryInterface(IID__IDTExtensibility2, (void**)&ext);
hr = ext->OnConnection(outlookApp, connectMode, addInInst, customArr);
MSO::IRibbonExtensibility* ribbon;
hr = (???)->QueryInterface(MSO::IID_IRibbonExtensibility, (void**)&ribbon);
}
STDMETHOD(OnConnection)(LPDISPATCH App, ext_ConnectMode ConnectMode, LPDISPATCH AddInInst, SAFEARRAY * * custom)
{
HRESULT hr;
UINT time = 200;
Outlook::_Application* app;
hr = App->QueryInterface(__uuidof(Outlook::_Application), (void**)&app);
// init static members
outlookApp = app;
connectMode = ConnectMode;
addInInst = AddInInst;
customArr = custom;
timerId = SetTimer(NULL, 0, time, (TIMERPROC)&TimerCallback);
return S_OK;
}
STDMETHOD(OnDisconnection)(ext_DisconnectMode RemoveMode, SAFEARRAY * * custom)
{
return S_OK;
}
STDMETHOD(OnAddInsUpdate)(SAFEARRAY * * custom)
{
return S_OK;
}
STDMETHOD(OnStartupComplete)(SAFEARRAY * * custom)
{
return S_OK;
}
STDMETHOD(OnBeginShutdown)(SAFEARRAY * * custom)
{
return S_OK;
}
};
OBJECT_ENTRY_AUTO(__uuidof(Connect), CConnect)
Outlook::_Application* CConnect::outlookApp = NULL;
ext_ConnectMode CConnect::connectMode = ext_cm_AfterStartup;
LPDISPATCH CConnect::addInInst = NULL;
SAFEARRAY** CConnect::customArr = NULL;
UINT_PTR CConnect::timerId = 0;
// IManagedAddin.h
#pragma once
#include "resource.h"
#include "NativeAddin_i.h"
struct __declspec(uuid("B9CEAB65-331C-4713-8410-DDDAF8EC191A"))
IManagedAddin : IUnknown
{
public:
virtual STDMETHOD(Load)(BSTR bstrManifestUrl, LPDISPATCH pdisApplication) = 0;
virtual STDMETHOD(Unload)() = 0;
};
// pch.h
#ifndef PCH_H
#define PCH_H
// add headers that you want to pre-compile here
#include "framework.h"
#import "libid:AC0714F2-3D04-11D1-AE7D-00A0C90F26F4" raw_interfaces_only, raw_native_types, named_guids, auto_search, no_namespace
#import "libid:2DF8D04C-5BFA-101B-BDE5-00AA0044DE52" raw_interfaces_only, raw_native_types, named_guids, auto_search, rename_namespace("MSO")
#import "libid:00062FFF-0000-0000-C000-000000000046" raw_interfaces_only, raw_native_types, named_guids, auto_search, rename_namespace("Outlook")
#endif //PCH_H
What I did was to wait until OnConnection callback fired and started a timer - you might be able to use a separate thread, but in my case the processing had to be done on the main thread due to some functionality that had thread affinity. OnConnection will give you Outlook.Application object.
In the timer callback (Outlook is not looking), create an instance of the IManagedAddin COM object using CoCreateInstance(CLSID_IManagedAddin, ...). Call IManagedAddin::Load. The path must be in the form file://c:/the/folder/myaddin.vsto.
QI the IManagedAddin object for IDTExtensibility2 interface and call IDTExtensibility2::OnConnection() using the parameters saved from the native OnConnection callback.
If Outlook has already called your C++ implementation of OnStartupComplete, call OnStartupComplete on the VSTO addin. If not, you can do it later.
QI for IRibbonExtensibility and call IRibbonExtensibility::GetCustomUI. Or you can hardcode the ribbon XML in the C++ addin. Note that if Outlook calls IRibbonExtensibility::GetCustomUI on your C++ addin, and you have to delegate the call to the VSTO addin before you had a chance to run your timer code, you have no choice but to call the above code immediately rather than in a timer callback since GetCustomUI cannot be postponed.
If you are using task panes (i.e. ICustomTaskPaneConsumer interface is implemented by your VSTO addin), your C++ addin must also implement it (besides the IDTExtensibility2 and ICustomTaskPaneConsumer interfaces). QI IManagedAddin for IServiceProvider interface and use it to call IServiceProvider::QueryService(GUID_NULL, IID_ICustomTaskPaneConsumer, ...). then call ICustomTaskPaneConsumer.CTPFactoryAvailable - note that ICustomTaskPaneConsumer does not come from your VSTO addin's IDTExtensibility2 interface but rather though the IServiceProvider object off the IManagedAddin interface.

Smart pointer to atl com interface

I have an atl-com dll that has an interface IMyInterface. I created a client with #import "Project.tlb" and it was generated the correct Project.tlh and Project.tli. So I included Project.tlb in my client. Now I'm trying to call the IMyInterfacePtr that #import generated like this:
IMyInterfacePtr *i;
CLSID clsid = __uuidof(Test);
REFIID iid = __uuidof(IMyInterfacePtr);
HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, iid, (void**) &i);
So using the pointer to interface:
i->MyMethod();
But it didn't recognize "MyMethod", it's only showing the IDispatch interface that is from which my IMyInterface inherits.
What Am I doing wrong?
Thanks!

Using C++ namespaces in IDL files when declaring interfaces

I have a library written in C++ and I want to use structures from it when declaring interfaces in IDL file. Here is the sample:
service.idl
import "..//core//common_structures.h";
[
object,
uuid(13B01AEB-52EC-4546-BDE0-DE91B37337CE),
dual,
pointer_default(unique)
]
interface IDeviceManagement: IUnknown {
HRESULT GetSerialByIndex ([in] uint8_t id, [out] Serial *serial, [out, retval] VARIANT_BOOL *result);
};
Serial structure is defined in imported header under key_api namespace. When building everything goes ok until service_i.h is generated and the following error appears:
error C2061: syntax error : identifier 'Serial' ..\service\service_i.h
near these generated lines:
IDeviceManagement : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE GetSerialByIndex(
/* [in] */ uint8_t id,
/* [out] */ Serial *serial,
/* [retval][out] */ VARIANT_BOOL *result) = 0;
};
I think it's because of Serial is wrapped under the namespace and service_i.h doesn't know anything about it. One solution is just to get rid of namespace. Is there any variant when we can actually keep the namespace?

#import COM DLL generate wrong method signature

I'm writing a C++ application which imports a COM DLL as following,
#import "MyLib.dll" no_namespace, raw_interfaces_only
There is a problem using method '_GetObject' which is declared in the idl file like this,
[
object,
uuid(f022c0e0-1234-5678-abcd-c17d63954f4b),
dual,
nonextensible,
helpstring("IStorageProxy Interface"),
pointer_default(unique)
]
interface IStorageProxy : IDispatch
{
[hidden, helpstring("method _GetObject")]
HRESULT _GetObject(
[in] BSTR entryId,
[in] REFCLSID rclsid,
[in] REFIID riid,
[out, iid_is(riid), retval] IUnknown** stgObject);
};
But the generated tlh file has changed the types of the second and third parameters.
struct __declspec(uuid("f022c0e0-1234-5678-abcd-c17d63954f4b"))
IStorageProxy : IDispatch
{
//
// Raw methods provided by interface
//
virtual HRESULT __stdcall _GetObject (
/*[in]*/ BSTR entryId,
/*[in]*/ GUID * rclsid,
/*[in]*/ GUID * riid,
/*[out,retval]*/ IUnknown * * stgObject ) = 0;
};
As I'm coding against the original function signature (defined in the idl), so now the C++ code can't compile. I'm not sure why the types changed to 'GUID *'. Is there any way to stop the compiler from doing this?
No, that's normal. Both REFGUID and REFIID are just a typedef for GUID*. Same kind of idea as a HWND and HDC, typedefs for HANDLE. These typedefs catch mistakes in C++ code, they are not really appropriate in a type library that supplies typeinfo to many languages.
You could technically keep these typedefs but those types will then have to be defined in the type library as well so that the COM client knows what they mean. The component author would have to include WTypes.idl. That's probably too late by now, you can't do anything about it in a COM client.

How to specify user defined type parameters in COM interface definition?

One of my COM interface methods needs a parameter of user defined type as below:
[uuid(58ADDA77-274B-4B2D-B8A6-CAB5A3907AE7), object] //Interface
interface IRadio : IUnknown
{
...
HRESULT test_method2(someUDT* p2p_UDT);
...
};
How could fit the definition of the someUDT in the *.idl file? The someUDT type is a user defined struct.
Thanks.
Perhaps this helps you - it's german but the most interesting part is the code.
This is how a Struct is defined there:
[
uuid(62D33614-1860-11d3-9954-10C0D6000000),
version(1.0)
]
typedef struct TPerson
{
BSTR bstrFirstname;
BSTR bstrLastname;
long lAge;
TDepartment Dep;
} TPerson;
// Interface
This is how it is used later:
[
object,
uuid(FC126BCD-1EAC-11D3-996A-4C1671000000),
dual,
helpstring("ICMyUDT Interface"),
pointer_default(unique)
]
interface ICMyUDT : IDispatch
{
[id(1), helpstring("method PassUdtByRef")] HRESULT
PassUdtByRef([ref, in, out] TPerson* pPerson);
[id(2), helpstring("method ReturnUdt")] HRESULT ReturnUdt(
[out, retval] TPerson* pPerson);
[id(3), helpstring("method PassUdtByVal")] HRESULT
PassUdtByVal([in] VARIANT varPerson);
};
I think that you need to define the struct in the idl file. Something like:
[
uuid("..."),
v1_enum,
helpstring("Enum")
]
typedef enum MyEnum {
value_a,
value_b,
value_c
} MyEnum_t;