C++ dual interface implement without ATL, IDL and DEF.

Fleµve Relentless.resærch.lab 81 Reputation points
2022-09-23T13:33:25.223+00:00

Hello last week, I take some time to optimize and understand Addins for Inventor. After I realize that it's just a simple DLL with a DllGetClassObject entry and some query interface. I decide to flush the entire actual ATL template, IDL, DEF and re-begin on a new form, for my part, are really more understandable and clear. Now I've a true question about C++ COM DLL, but before let me explain where I stuck. First, this Addins can be based on 2 class.

IRxApplicationAddInServer where is only a IUnknown based object (require queryinterface and addref)
or
ApplicationAddInServer this one was IUnknown and IDispatch based object (require additional GetTypeInfoCount, GetTypeInfo, GetIDsOfNames and Invoke)

I decide to implement the simplest version, do some research on COM and kick out ATL, compile and it's working... The addins trigger Activate, my ribbons appear in the program. Then, i continue and made some change in the code to convert IRxApplicationAddInServer to ApplicationAddInServer and also include the missing virtual function that IDispatch requiert. Launch it with no result. But I realize if I trim a part of my query interface to avoid main class creation this one give me strange behavior (calling twice same interface) call GetIDsOfNames with a trace of Activate function and also call Invoke after.. but not really a true Activate trigger.. no ribbon

			if (IsEqualGUID(riid, IID_IUnknown))   
				*ppv = (IUnknown*)this;  
			else if (IsEqualGUID(riid, IID_IDispatch))  
				*ppv = (IDispatch*)this;  
#ifndef _QueryPatch                                                                                    //Trimmed Part    
			else if (IsEqualGUID(riid, CLSID_InventorAddInServer))  
					*ppv = (TARGETSERVER*)this;  
#endif					  

Q: How relay information between GetIDsOfNames and Invoke?

I send you the simple 1 file code and an Image of code result.

#include <windows.h>  
#include "InventorUtils.h"  
  
#define _WithDispatch  
#define _QueryPatch  
  
#ifdef _WithDispatch  
	#define TARGETSERVER ApplicationAddInServer  
	#define TARGETSITE ApplicationAddInSite  
#else  
	#define TARGETSERVER IRxApplicationAddInServer  
	#define TARGETSITE IRxApplicationAddInSite  
#endif // _WithDispatch  
  
  
extern "C" __declspec(selectany) const _GUID CLSID_InventorAddInLite = { 0x0B047779, 0x4EFD, 0x4ADF, {0x99, 0x24, 0x76, 0x8B, 0xF9, 0x76, 0xA6, 0x48}};  
extern "C" __declspec(selectany) const _GUID CLSID_InventorAddInServer = { 0xE3571292, 0xDB40, 0x11D2, {0xB7, 0x83, 0x00, 0x60, 0xB0, 0xF1, 0x59, 0xEF }};  
  
unsigned long g_lockCount;  
unsigned long g_objCount;  
  
void GuidToObjectName(_GUID riid, wchar_t* StrOut)  
{  
	if (IsEqualGUID(riid, GUID_NULL))  
		wcscpy_s(StrOut, 2048, L"Null");  
	if (IsEqualGUID(riid, IID_IUnknown))  
		wcscpy_s(StrOut, 2048, L"IUnknown");  
	if (IsEqualGUID(riid, IID_IDispatch))  
		wcscpy_s(StrOut, 2048, L"IDispatch");  
	if (IsEqualGUID(riid, IID_IClassFactory))  
		wcscpy_s(StrOut, 2048, L"IClassFactory");  
	if (IsEqualGUID(riid, CLSID_InventorAddInLite))  
		wcscpy_s(StrOut, 2048, L"Inventor Addin");  
	if (IsEqualGUID(riid, CLSID_InventorAddInServer))  
		wcscpy_s(StrOut, 2048, L"Inventor Server");  
}  
  
class CInventorLite : public TARGETSERVER  
{  
	public :   
		CInventorLite()  
		{  
			m_cRef = 0;  
			g_objCount++;  
		}  
  
		~CInventorLite()  
		{  
			g_objCount--;  
		}  
  
		virtual _declspec(nothrow) long _stdcall Activate(TARGETSITE* pAddInSite, char FirstTime)  
		{	  
			wchar_t Str[2048];  
			swprintf_s(Str, L"Begin\nFirst Time : %d", FirstTime);  
			MessageBox(NULL, Str, L"Inventor Addins - C++ Native - Activate", MB_OK);  
  
			if (pAddInSite == NULL)  
				return E_INVALIDARG;  
			  
			m_pAddInSite = pAddInSite;  
			  
			long hr;  
  
#ifdef _WithDispatch  
				if (FAILED(hr = m_pAddInSite->get_Application(&m_pApplication)))  
				return hr;  
#else  
			CComPtr<IUnknown> pAppUnk;  
			if (FAILED(hr = m_pAddInSite->get_Application(&pAppUnk)))  
				return hr;  
			if (FAILED(hr = pAppUnk->QueryInterface(&m_pApplication)))  
				return hr;  
#endif  
  
			/*  Ribbon */	  
			CComPtr<UserInterfaceManager> pUserInterfaceMgr;  
			hr = m_pApplication->get_UserInterfaceManager(&pUserInterfaceMgr);  
			if (FAILED(hr))	return hr;  
		  
			CComPtr<Ribbons> pRibbons;  
			hr = pUserInterfaceMgr->get_Ribbons(&pRibbons);  
			if (FAILED(hr)) return hr;  
  
			CComPtr<Ribbon> pPartRibbon;  
			hr = pRibbons->get_Item(CComVariant(_T("Assembly")), &pPartRibbon);  
			if (FAILED(hr)) return hr;  
  
			//get the tabs associated with part ribbon  
			CComPtr<RibbonTabs> pRibbonTabs;  
			hr = pPartRibbon->get_RibbonTabs(&pRibbonTabs);  
			if (FAILED(hr)) return hr;  
			  
			CComPtr<RibbonTab> pRibbonTab;  
			hr = pRibbonTabs->Add(CComBSTR("My Ribbon"), CComBSTR("id_Tab_MyRibbon"), CComBSTR("MyID"), CComBSTR(""), false, false, &pRibbonTab);  
			if (FAILED(hr)) return hr;  
  
			CComPtr<RibbonPanel> pCustomPanel;  
			pRibbonTab->GetRibbonPanels()->Add(CComBSTR("Sample"), CComBSTR("MYSample"), CComBSTR(""), CComBSTR(""), false, &pCustomPanel);  
			if (FAILED(hr)) return hr;  
  
			/* Combo */  
			CComPtr<CommandManager> pCommandManager;  
			hr = m_pApplication->get_CommandManager(&pCommandManager);  
			if (FAILED(hr)) return hr;  
  
			CComPtr<ControlDefinitions> pControlDefinitions;  
			hr = pCommandManager->get_ControlDefinitions(&pControlDefinitions);  
			if (FAILED(hr)) return hr;  
  
			CComPtr<ComboBoxDefinitionObject> m_pSlotWidthComboBoxDef;  
			hr = pControlDefinitions->AddComboBoxDefinition(CComBSTR(_T("Slot Width")),  
				CComBSTR(_T("Autodesk:SimpleAddIn:SlotWidthCboBox")),  
				kShapeEditCmdType,  
				50,  
				CComVariant(_T("{DB59D9A7-EE4C-434A-BB5A-F93E8866E872}")),  
				CComBSTR(_T("Specifies slot width")),  
				CComBSTR(_T("Slot width")),  
				vtMissing,  
				vtMissing,  
				kAlwaysDisplayText,  
				&m_pSlotWidthComboBoxDef);  
			  
  
			CComPtr<ButtonDefinitionObject> pAddSlotOptionCmdBtnDef;  
			hr = pControlDefinitions->AddButtonDefinition(CComBSTR(_T("Add Slot")),  
				CComBSTR(_T("Autodesk:SimpleAddIn:AddSlotOptionCmd")),  
				kShapeEditCmdType,  
				CComVariant(_T("{DB59D9A7-EE4C-434A-BB5A-F93E8866E872}")),  
				CComBSTR(_T("Adds option for slot width/height")),  
				CComBSTR(_T("Add slot option")),  
				vtMissing,  
				vtMissing,  
				kDisplayTextInLearningMode,  
				&pAddSlotOptionCmdBtnDef);  
			if (FAILED(hr))	return hr;  
  
			CComPtr<CommandControls> pCommandControls;  
			hr = pCustomPanel->get_CommandControls(&pCommandControls);  
			if (FAILED(hr)) return hr;  
  
			CComPtr<CommandControl> pSlotWidthCmdCboBoxCmdCtrl;  
			hr = pCommandControls->AddComboBox(m_pSlotWidthComboBoxDef, CComBSTR(""), true, &pSlotWidthCmdCboBoxCmdCtrl);  
			if (FAILED(hr)) return hr;  
			  
			CComPtr<CommandControl> pSlotWidthCmdButtonCmdCtrl;  
			hr = pCommandControls->AddButton(pAddSlotOptionCmdBtnDef,false,	true, CComBSTR(_T("")),	false, &pSlotWidthCmdButtonCmdCtrl);  
			if (FAILED(hr)) return hr;  
			  
			/* End Combo*/  
			//MessageBox(NULL, L"End", L"Inventor Addins - C++ Native - Activate", MB_OK);  
  
			return S_OK;  
		}  
  
		virtual _declspec(nothrow) long _stdcall Deactivate()  
		{  
			MessageBox(NULL, L"End", L"Inventor Addins - C++ Native - Desactivate", MB_OK);  
			return S_OK;  
		}  
  
		/*** Never Trigged *****/  
		virtual _declspec(nothrow) long _stdcall ExecuteCommand(LONG CommandID)  
		{  
			MessageBox(NULL, L"End", L"Inventor Addins - C++ Native - ExecuteCommand", MB_OK);  
			return S_OK;  
		}  
	  
		/*** Never Trigged *****/  
		virtual _declspec(nothrow) long _stdcall get_Automation(IUnknown** ppResult)  
		{  
			MessageBox(NULL, L"End", L"Inventor Addins - C++ Native - get_Automation", MB_OK);  
			return S_OK;  
		}  
  
		virtual _declspec(nothrow) long _stdcall QueryInterface(const _GUID& riid, void** ppv)   
		{  
			*ppv = NULL;  
			long Result = E_NOINTERFACE;  
  
			OLECHAR* guidString;  
			StringFromCLSID(riid, &guidString);  
			wchar_t Str[2048];  
			wchar_t typName[2048];  
			GuidToObjectName(riid, typName);  
			swprintf_s(Str, L"Begin\nriid : %s - %s", guidString, typName);  
			MessageBox(NULL, Str, L"Inventor Addins - C++ Native - Query Interface", MB_OK);  
			::CoTaskMemFree(guidString);  
  
			if (IsEqualGUID(riid, IID_IUnknown))   
				*ppv = (IUnknown*)this;  
			else if (IsEqualGUID(riid, IID_IDispatch))  
				*ppv = (IDispatch*)this;  
#ifndef _QueryPatch  
			else if (IsEqualGUID(riid, CLSID_InventorAddInServer))  
					*ppv = (TARGETSERVER*)this;  
#endif					  
			if (*ppv)  
			{  
				AddRef();  
				Result = S_OK;  
			}  
			  
			return Result;  
		}  
	  
		virtual _declspec(nothrow) unsigned long _stdcall AddRef()  
		{  
			//MessageBox(NULL, L"End", L"Inventor Addins - C++ Native - AddRef", MB_OK);  
			return ++m_cRef;  
		}  
		  
		virtual _declspec(nothrow) unsigned long _stdcall Release()  
		{  
			if (--m_cRef == 0)  
			{  
				delete this;  
				return 0;  
			}  
			  
			//MessageBox(NULL, L"End", L"Inventor Addins - C++ Native - Release", MB_OK);  
			return m_cRef;  
		}  
		  
		virtual _declspec(nothrow) long _stdcall GetTypeInfoCount(UINT* pctinfo)   
		{  
			wchar_t Str[2048];  
			swprintf_s(Str, L"Begin\npctinfo : %d", *pctinfo);  
			MessageBox(NULL, Str, L"Inventor Addins - C++ Native - GetTypeInfoCount", MB_OK);  
			  
			if (pctinfo == NULL)   
			{  
				return E_INVALIDARG;  
			}  
			  
			*pctinfo = 1;  
			MessageBox(NULL, L"End", L"Inventor Addins - C++ Native - GetTypeInfoCount", MB_OK);  
			return NOERROR;  
		}  
		  
		virtual _declspec(nothrow) long _stdcall GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)  
		{  
			wchar_t Str[2048];  
			swprintf_s(Str, L"Begin\niT Info : %d, lcid : %d", iTInfo, lcid);  
			MessageBox(NULL, Str, L"Inventor Addins - C++ Native - GetTypeInfo", MB_OK);  
			if (0 != iTInfo)  
				return E_INVALIDARG;  
			(*ppTInfo = m_pTypeInfo)->AddRef();  
			return S_OK;  
		}  
  
		virtual _declspec(nothrow) long _stdcall GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId)  
		{  
			OLECHAR* guidString;  
			StringFromCLSID(riid, &guidString);  
			  
			wchar_t Str[2048];  
			wchar_t typName[2048];  
			GuidToObjectName(riid, typName);  
	  
			swprintf_s(Str, L"Begin\nriid : %s - %s\nregName : %s\ncNames : %d\nlcid : %d\nrgDispId : %d\n", guidString, typName, rgszNames[0], cNames, lcid, *rgDispId);  
			MessageBox(NULL, Str, L"Inventor Addins - C++ Native - GetIDsOfNames", MB_OK);  
			::CoTaskMemFree(guidString);			  
			return S_OK;  
		}  
  
		virtual _declspec(nothrow) long _stdcall Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)   
		{  
			OLECHAR* guidString;  
			StringFromCLSID(riid, &guidString);  
  
			wchar_t Str[2048];  
			wchar_t typName[2048];  
			GuidToObjectName(riid, typName);  
  
			swprintf_s(Str, L"Begin\nrgDispId : %d\nriid : %s - %s\nlcid : %d\n", dispIdMember, guidString, typName, lcid);  
			MessageBox(NULL, Str, L"Inventor Addins - C++ Native - Invoke", MB_OK);  
			::CoTaskMemFree(guidString);  
  
			return S_OK;  
		}  
  
  
	private:  
			ITypeInfo* m_pTypeInfo;  
			unsigned long m_cRef;  
			CComPtr<Application> m_pApplication;  
			CComPtr<TARGETSITE> m_pAddInSite;  
};  
  
class CInventorLiteFactory : public IClassFactory  
{  
	public:  
		CInventorLiteFactory()  
		{  
			m_cRef = 0;  
			g_objCount++;  
		}  
  
		~CInventorLiteFactory()  
		{  
			g_objCount--;  
		}  
  
		virtual _declspec(nothrow) long _stdcall QueryInterface(const _GUID& riid, void** ppv)  
		{  
			OLECHAR* guidString;  
			StringFromCLSID(riid, &guidString);  
			wchar_t typName[2048];  
			GuidToObjectName(riid, typName);  
			wchar_t Str[2048];  
			swprintf_s(Str, L"Begin\nriid : %s - %s", guidString, typName);  
			MessageBox(NULL, Str, L"Inventor Addins - C++ Native - IClassFactory Query Interface", MB_OK);  
			::CoTaskMemFree(guidString);  
  
			long Result = E_NOINTERFACE;  
			*ppv = NULL;  
  
			if (IsEqualGUID(riid, IID_IClassFactory))  
			{  
				*ppv = (IClassFactory*)this;  
				AddRef();  
				Result = NOERROR;  
			}  
			  
			//MessageBox(NULL, L"End", L"Inventor Addins - C++ Native - IClassFactory QueryInterface", MB_OK);  
			return Result;  
		}  
  
		virtual _declspec(nothrow) unsigned long _stdcall AddRef()  
		{  
			//MessageBox(NULL, L"End", L"Inventor Addins - C++ Native - IClassFactory Add Ref", MB_OK);  
			return ++m_cRef;  
		}  
  
		/***  NEVER TRIG **************/  
		virtual _declspec(nothrow) unsigned long _stdcall Release()  
		{  
			if (--m_cRef == 0)  
			{  
				delete this;  
				return 0;  
			}  
  
			MessageBox(NULL, L"End", L"Inventor Addins - C++ Native - IClassFactory Release", MB_OK);  
			return m_cRef;  
		}  
  
		virtual _declspec(nothrow) long _stdcall CreateInstance(IUnknown* pUnkOuter, const _GUID &riid, void** ppvObject)  
		{  
			OLECHAR* guidString;  
			StringFromCLSID(riid, &guidString);  
			wchar_t typName[2048];  
			GuidToObjectName(riid, typName);  
			wchar_t Str[2048];  
			swprintf_s(Str, L"Begin\nriid : %s - %s", guidString, typName);  
			MessageBox(NULL, Str, L"Inventor Addins - C++ Native - IClassFactory CreateInstance", MB_OK);  
			::CoTaskMemFree(guidString);  
  
			long hr;  
		  
			CInventorLite* pInvLite = new CInventorLite();  
			if (FAILED(hr = pInvLite->QueryInterface(riid, ppvObject)))   
				delete pInvLite;  
  
			return hr;  
		}  
  
		/***  NEVER TRIG **************/  
		virtual _declspec(nothrow) long _stdcall LockServer(int fLock)  
		{  
			MessageBox(NULL, L"End", L"Inventor Addins - C++ Native - IClassFactory LockServer", MB_OK);  
			fLock ? g_lockCount++ : g_lockCount--;  
			return S_OK;  
		}  
  
	private:  
		unsigned long m_cRef;  
};  
  
extern "C" long _stdcall DllGetClassObject(const _GUID & rclsid, const _GUID & riid, void** ppv)  
{  
	OLECHAR* guidString1;  
	OLECHAR* guidString2;  
	StringFromCLSID(rclsid, &guidString1);  
	StringFromCLSID(riid, &guidString2);  
	wchar_t Str[2048];  
	wchar_t typName1[2048];  
	GuidToObjectName(rclsid, typName1);  
	wchar_t typName2[2048];  
	GuidToObjectName(riid, typName2);  
	swprintf_s(Str, L"Begin\nclsid : %s - %s\nriid : %s - %s", guidString1, typName1, guidString2, typName2);  
	MessageBox(NULL, Str, L"Inventor Addins - C++ Native - DllGetClassObject", MB_OK);  
	::CoTaskMemFree(guidString1);  
	::CoTaskMemFree(guidString2);  
  
	long Result = NOERROR;  
	*ppv = NULL;  
  
	if (!IsEqualGUID(riid, IID_IUnknown) && !IsEqualGUID(riid, IID_IClassFactory))  
		Result = E_NOINTERFACE;  
	else if (IsEqualGUID(rclsid, CLSID_InventorAddInLite))  
	{  
		if (*ppv = new CInventorLiteFactory())  
			((IUnknown*)*ppv)->QueryInterface(riid, ppv);  
		else  
			return E_OUTOFMEMORY;  
	}	  
	else  
		Result = E_FAIL;  
	  
	//MessageBox(NULL, L"End", L"Inventor Addins - C++ Native - DllGetClassObject", MB_OK);  
	return Result;  
}  
  
/***  NEVER TRIG **************/  
extern "C" long _stdcall DllCanUnloadNow()  
{  
	MessageBox(NULL, L"End", L"Inventor Addins - C++ Native - DllCanUnloadNow", MB_OK);  
	return g_lockCount == 0 && g_objCount == 0 ? S_OK : S_FALSE;  
}  
  
#pragma comment(linker, "/EXPORT:DllCanUnloadNow=DllCanUnloadNow,PRIVATE")  
#pragma comment(linker, "/EXPORT:DllGetClassObject=DllGetClassObject,PRIVATE")  
  

244335-irxapplication.png

Windows API - Win32
Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,422 questions
C++
C++
A high-level, general-purpose programming language, created as an extension of the C programming language, that has object-oriented, generic, and functional features in addition to facilities for low-level memory manipulation.
3,526 questions
{count} votes

Accepted answer
  1. RLWA32 40,286 Reputation points
    2022-09-23T14:16:58.65+00:00

    Well, since you don't seem to be creating a type library you'll have to code your implementation of IDispatch::GetIDsOfNames to return the DISPIDs that your object expects to be passed to IDispatch::Invoke. And the implementation of IDispatch::Invoke has to know about the various properties and methods and their DISPIDS as well as coerce parameters to their needed types when required. If you're not dealing with trivial cases its going to be a lot of work.

    Since you're not using a type library IDispatch::GetTypeInfoCount should probably store 0 instead of 1 to pctinfo. You should review the documentation for IDispatch for the other type library related functions.

    I know you don't want to use IDL, but one easy way to implement a dual interface without ATL is to create a type library and aggregate the object created by the CreateStdDispatch function. If you don't want to use aggregation you can delegate calls to IDispatch methods to ITypeInfo. You can also use the CreateDispTypeInfo function to manually create type information without using IDL. This type information can be used with the system provided functions described here to simplify implementing IDispatch. dispatch-functions


1 additional answer

Sort by: Most helpful
  1. Fleµve Relentless.resærch.lab 81 Reputation points
    2022-10-04T01:46:45.277+00:00

    Thanks!

    After, I realize a little error, everything come back in place and the logic was reveal. I was lucky in this DLL situation and manage invoke manually was easier and more logic that we think.

    First, I mention about (calling twice same interface)... but it's where the error come. Look the number

    247170-guiderror.png

    There are two different interface and what happens in reality:

    IRxApplicationAddInServer was called first.. if failed //Working and trigger Activate because I create on first call
    ApplicationAddInServer was called in second... if failed //Never try it before ask question
    IDispatch was called. //Not working, and call GetIDsOfNames with empty Invoke.

    That mean if you want create an ApplicationAddInServer, you must skip the first queryinterface and create with the second. Like this, calling path become clear and only invoke was called and it's seem to appear that DISPID was now filled.

    247177-irxapplication-simple.png

    Now, how match DISPID with the good function... Simple... Inside the IDL file (provided by the plugins manufacture)

     [  
     object,  
     uuid(DE427D97-C402-4CE2-B961-FB8445A557D3),  
     dual,  
     helpstring("IInventorAddIn6AddInServer Interface"),  
     pointer_default(unique)  
     ]  
     interface IInventorAddIn6AddInServer : IDispatch  
     {  
     [id(0x03001201)] HRESULT Activate([in] IDispatch * pDisp, [in] VARIANT_BOOL FirstTime);  
     [id(0x03001202)] HRESULT Deactivate();  
     [id(0x03001203)] HRESULT ExecuteCommand([in] long CommandID);  
     [propget, id(0x03001204)] HRESULT Automation([out, retval] IDispatch * * Result);  
     };  
      
    

    After all invoke was easy, because if you take 50336257 and you convert into hexa, you got. 0x03001201. That's mean activate. And the parameter was inside DISPPARAMS where index was ordered in reverse (Max param to Zero).

    There is the final code:

    #include "Pch.h"  
      
    #define _WithDispatch  
      
    #ifdef _WithDispatch  
       #define TARGETSERVER ApplicationAddInServer  
       #define TARGETSITE ApplicationAddInSite  
       #define TARGETIID IID_InventorAddInServer  
    #else  
       #define TARGETSERVER IRxApplicationAddInServer  
       #define TARGETSITE IRxApplicationAddInSite  
       #define TARGETIID IID_IRxInventorAddInServer  
    #endif // _WithDispatch  
      
    extern "C" __declspec(selectany) const _GUID CLSID_InventorAddInLite = { 0x0B047779, 0x4EFD, 0x4ADF, {0x99, 0x24, 0x76, 0x8B, 0xF9, 0x76, 0xA6, 0x48} };  
    extern "C" __declspec(selectany) const _GUID IID_IRxInventorAddInServer = { 0xE3571292, 0xDB40, 0x11D2, {0xB7, 0x83, 0x00, 0x60, 0xB0, 0xF1, 0x59, 0xEF } };  
    extern "C" __declspec(selectany) const _GUID IID_InventorAddInServer = { 0xE3571293, 0xDB40, 0x11D2, {0xB7, 0x83, 0x00, 0x60, 0xB0, 0xF1, 0x59, 0xEF } };  
      
    class CInventorLite : public TARGETSERVER  
    {  
       public:  
          CInventorLite()  
          {  
             m_cRef = 0;  
          }  
      
          virtual _declspec(nothrow) long _stdcall Activate(TARGETSITE* pAddInSite, char FirstTime)  
          {           
             if (pAddInSite == NULL)  
                return E_INVALIDARG;  
      
             m_pAddInSite = pAddInSite;  
      
             long hr;  
      
    #ifdef _WithDispatch  
             if (FAILED(hr = m_pAddInSite->get_Application(&m_pApplication)))  
                return hr;  
    #else  
             CComPtr<IUnknown> pAppUnk;  
             if (FAILED(hr = m_pAddInSite->get_Application(&pAppUnk)))  
                return hr;  
             if (FAILED(hr = pAppUnk->QueryInterface(&m_pApplication)))  
                return hr;  
    #endif  
      
             //*** Ribbon ***  
             CComPtr<UserInterfaceManager> pUserInterfaceMgr;  
             hr = m_pApplication->get_UserInterfaceManager(&pUserInterfaceMgr);  
             if (FAILED(hr)) return hr;  
      
             CComPtr<Ribbons> pRibbons;  
             hr = pUserInterfaceMgr->get_Ribbons(&pRibbons);  
             if (FAILED(hr)) return hr;  
      
             CComPtr<Ribbon> pPartRibbon;  
             hr = pRibbons->get_Item(CComVariant(_T("Assembly")), &pPartRibbon);  
             if (FAILED(hr)) return hr;  
      
             //get the tabs associated with part ribbon  
             CComPtr<RibbonTabs> pRibbonTabs;  
             hr = pPartRibbon->get_RibbonTabs(&pRibbonTabs);  
             if (FAILED(hr)) return hr;  
      
             CComPtr<RibbonTab> pRibbonTab;  
             hr = pRibbonTabs->Add(CComBSTR("My Ribbon"), CComBSTR("id_Tab_MyRibbon"), CComBSTR("MyID"), CComBSTR(""), false, false, &pRibbonTab);  
             if (FAILED(hr)) return hr;  
      
             CComPtr<RibbonPanel> pCustomPanel;  
             pRibbonTab->GetRibbonPanels()->Add(CComBSTR("Sample"), CComBSTR("MYSample"), CComBSTR(""), CComBSTR(""), false, &pCustomPanel);  
             if (FAILED(hr)) return hr;  
      
             //*** Combo ***  
             CComPtr<CommandManager> pCommandManager;  
             hr = m_pApplication->get_CommandManager(&pCommandManager);  
             if (FAILED(hr)) return hr;  
      
             CComPtr<ControlDefinitions> pControlDefinitions;  
             hr = pCommandManager->get_ControlDefinitions(&pControlDefinitions);  
             if (FAILED(hr)) return hr;  
      
             CComPtr<ComboBoxDefinitionObject> m_pSlotWidthComboBoxDef;  
             hr = pControlDefinitions->AddComboBoxDefinition(CComBSTR(_T("Slot Width")),  
                CComBSTR(_T("Autodesk:SimpleAddIn:SlotWidthCboBox")),  
                kShapeEditCmdType,  
                50,  
                CComVariant(_T("{DB59D9A7-EE4C-434A-BB5A-F93E8866E872}")),  
                CComBSTR(_T("Specifies slot width")),  
                CComBSTR(_T("Slot width")),  
                vtMissing,  
                vtMissing,  
                kAlwaysDisplayText,  
                &m_pSlotWidthComboBoxDef);  
      
      
             CComPtr<ButtonDefinitionObject> pAddSlotOptionCmdBtnDef;  
             hr = pControlDefinitions->AddButtonDefinition(CComBSTR(_T("Add Slot")),  
                CComBSTR(_T("Autodesk:SimpleAddIn:AddSlotOptionCmd")),  
                kShapeEditCmdType,  
                CComVariant(_T("{DB59D9A7-EE4C-434A-BB5A-F93E8866E872}")),  
                CComBSTR(_T("Adds option for slot width/height")),  
                CComBSTR(_T("Add slot option")),  
                vtMissing,  
                vtMissing,  
                kDisplayTextInLearningMode,  
                &pAddSlotOptionCmdBtnDef);  
             if (FAILED(hr))    return hr;  
      
             CComPtr<CommandControls> pCommandControls;  
             hr = pCustomPanel->get_CommandControls(&pCommandControls);  
             if (FAILED(hr)) return hr;  
               
             CComPtr<CommandControl> pSlotWidthCmdCboBoxCmdCtrl;  
             hr = pCommandControls->AddComboBox(m_pSlotWidthComboBoxDef, CComBSTR(""), true, (CommandControl**) & pSlotWidthCmdCboBoxCmdCtrl);  
             if (FAILED(hr)) return hr;  
      
             CComPtr<CommandControl> pSlotWidthCmdButtonCmdCtrl;  
             hr = pCommandControls->AddButton(pAddSlotOptionCmdBtnDef, false, true, CComBSTR(_T("")), false, &pSlotWidthCmdButtonCmdCtrl);  
             if (FAILED(hr)) return hr;  
      
             return S_OK;  
          }  
            
          virtual _declspec(nothrow) long _stdcall Deactivate() { return S_OK;}  
      
          virtual _declspec(nothrow) long _stdcall QueryInterface(const _GUID& riid, void** ppv)  
          {  
             *ppv = NULL;  
             long Result = E_NOINTERFACE;  
      
             if (IsEqualGUID(riid, TARGETIID))  
                *ppv = (TARGETSERVER*)this;  
             else if (IsEqualGUID(riid, IID_IUnknown))  
                *ppv = (IUnknown*)this;  
                  
             if (*ppv)  
             {  
                   AddRef();  
                   Result = S_OK;  
             }  
      
             return Result;  
          }  
      
          virtual _declspec(nothrow) unsigned long _stdcall AddRef() { return ++m_cRef; }  
      
          virtual _declspec(nothrow) unsigned long _stdcall Release()  
          {  
             if (--m_cRef == 0)  
             {  
                delete this;  
                return 0;  
             }  
      
             return m_cRef;  
          }  
    #ifdef _WithDispatch  
          virtual _declspec(nothrow) long _stdcall Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)  
          {  
             long Result = S_OK;  
      
             switch (dispIdMember)  
             {  
                case 0x03001201:  
                   Activate((TARGETSITE*)pDispParams->rgvarg[1].pdispVal, (VARIANT_BOOL)pDispParams->rgvarg[0].pboolVal);  
                   break;  
                case 0x03001202:  
                   Deactivate();  
                   break;  
                case 0x03001203:  
                   ExecuteCommand((LONG)pDispParams->rgvarg[0].lVal);  
                   break;  
                case 0x03001204:  
                   get_Automation((IDispatch**)pDispParams->rgvarg[0].pdispVal);  
                   break;  
                default:  
                   Result = E_FAIL;  
                   break;  
             }  
               
             return Result;  
          }  
    #endif  
          /*** Never Trigged ***/  
          virtual _declspec(nothrow) long _stdcall ExecuteCommand(LONG CommandID) { return S_OK; }  
        
    #ifdef _WithDispatch  
          virtual _declspec(nothrow) long _stdcall GetTypeInfoCount(UINT* pctinfo) { return E_NOTIMPL; }  
          virtual _declspec(nothrow) long _stdcall GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) { return E_NOTIMPL; }  
          virtual _declspec(nothrow) long _stdcall GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) { return E_NOTIMPL; }  
          virtual _declspec(nothrow) long _stdcall get_Automation(IDispatch** ppResult) { return S_OK; }  
    #else  
          virtual _declspec(nothrow) long _stdcall get_Automation(IUnknown** ppResult) { return S_OK; }  
    #endif  
      
      
       private:  
          unsigned long m_cRef;  
          CComPtr<Application> m_pApplication;  
          CComPtr<TARGETSITE> m_pAddInSite;  
    };  
      
    class CInventorLiteFactory  : public IClassFactory  
    {  
       public:  
          CInventorLiteFactory()  
          {  
             m_cRef = 0;  
          }  
             
          virtual _declspec(nothrow) long _stdcall QueryInterface(const _GUID& riid, void** ppv)  
          {  
             long Result = S_OK;  
      
             if (!IsEqualGUID(riid, IID_IUnknown) && !IsEqualGUID(riid, IID_IClassFactory))  
                Result = E_NOINTERFACE;  
             else  
             {  
                *ppv = (IClassFactory*)this;  
                  
                if (*ppv)  
                   AddRef();  
                else  
                   Result = E_OUTOFMEMORY;  
             }  
               
             return Result;  
          }  
        
          virtual _declspec(nothrow) unsigned long _stdcall AddRef() { return ++m_cRef; }  
      
          virtual _declspec(nothrow) unsigned long _stdcall Release()  
          {  
             if (--m_cRef == 0)  
             {  
                delete this;  
                return 0;  
             }  
      
             return m_cRef;  
          }  
      
          virtual _declspec(nothrow) long _stdcall CreateInstance(IUnknown* pUnkOuter, const _GUID& riid, void** ppv)  
          {  
             if (pUnkOuter != NULL)  
                return CLASS_E_NOAGGREGATION;  
      
             long Result = S_OK;  
      
             if (!IsEqualGUID(riid, IID_IUnknown) && !IsEqualGUID(riid, IID_IDispatch))  
                Result = E_NOINTERFACE;  
             else   
             {  
                *ppv = new CInventorLite();  
      
                if (*ppv)  
                   ((IUnknown*)*ppv)->AddRef();  
                else  
                   Result = E_OUTOFMEMORY;  
             }  
      
             return Result;  
          }  
      
          /*** Never Trigged ***/  
          virtual _declspec(nothrow) long _stdcall LockServer(int fLock) { return S_OK; }  
      
       private:  
          unsigned long m_cRef;  
    };  
      
    extern "C" long _stdcall DllGetClassObject(const _GUID & rclsid, const _GUID & riid, void** ppv)  
    {  
       long Result = S_OK;  
       
       if (!IsEqualGUID(riid, IID_IUnknown) && !IsEqualGUID(riid, IID_IClassFactory))  
          Result = E_NOINTERFACE;  
       else if (IsEqualGUID(rclsid, CLSID_InventorAddInLite))  
       {  
          *ppv = new CInventorLiteFactory();  
      
          if (*ppv)  
             ((IUnknown*)*ppv)->QueryInterface(riid, ppv);  
          else  
             Result = E_OUTOFMEMORY;  
       }  
       else  
          Result = E_FAIL;  
      
       return Result;  
    }  
      
    #pragma comment(linker, "/EXPORT:DllGetClassObject=DllGetClassObject,PRIVATE")  
      
    

    Take note that some function was never trigged but must be declared because of abstract class. Now missing one last question, How Event Sink manualy my object inside the ribbons. But it's gonna be an another question. Let's close this one.