COM Property Registration

COM Property Registration

Kyudos
Advisor Advisor
1,137 Views
5 Replies
Message 1 of 6

COM Property Registration

Kyudos
Advisor
Advisor

I have my COM Property interfaces for my custom entities in my ARX file and I'm having problems with the registration. We try to register the ARX during installation of our app using regsvr32 - but of course this needs to 'run' the server, which means it needs to resolve all of its dependencies, including the AutoCAD ones.

 

To get this to work you need to add the AutoCAD installation path(s) to your path environment variable, then run regsvr32 as admin - relatively straightforward to do manually - a little trickier during an install.

 

(I think unresolved dependencies is also the reason my attempts at internal registration fail)

 

Another approach would be to script the reg entries, but then we need to get the installation path into there for the InProcServer entries.

 

Is reg-free COM specification via the manifest file an option? If so, is it enough to just have the entries in the manifest? Can you embed the manifest in that situation?

 

How do you handle this?

0 Likes
Accepted solutions (1)
1,138 Views
5 Replies
Replies (5)
Message 2 of 6

Alexander.Rivilis
Mentor
Mentor
Accepted solution

I use this method for registration, regardless of whether or not the user has administrator rights:

 

 

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//- DllRegisterServer - Adds entries to the system registry
//STDAPI DllRegisterServer (void) {
//  //- Registers object, typelib and all interfaces in typelib
//  return (_AtlModule.RegisterServer (TRUE)) ;
//}
typedef void (*OaEnablePerUserTLibRegistration)();
STDAPI DllRegisterServer(void)
{
  HINSTANCE hInstOle32=NULL;
  try
  {
    HRESULT hr = _AtlModule.RegisterServer(TRUE);
    if(FAILED(hr))
    {
      hInstOle32 = LoadLibrary(_T("Oleaut32.dll"));
      if(hInstOle32)
      {
        OaEnablePerUserTLibRegistration lr=(OaEnablePerUserTLibRegistration)GetProcAddress(hInstOle32,("OaEnablePerUserTLibRegistration"));

        if(lr!=NULL)
        {
          lr(); 
          hr = _AtlModule.RegisterServer(TRUE);
          if(SUCCEEDED(hr))
          {
            FreeLibrary(hInstOle32);
            return hr;
          }
        }       
      }   

      HKEY hKCr;
      hr=RegOpenKeyEx(HKEY_CURRENT_USER,_T("Software\\Classes"),0,KEY_READ,&hKCr);
      if(hr!=ERROR_SUCCESS)
      {
        return hr;
      }
      hr = RegOverridePredefKey(HKEY_CLASSES_ROOT,hKCr);
      RegCloseKey(hKCr);
      if(FAILED(hr))
      {
        return hr;
      }   
      hr = _AtlModule.RegisterServer(TRUE);
      RegOverridePredefKey(HKEY_CLASSES_ROOT,NULL);
      hr=S_OK;
    }
    if(hInstOle32)
      FreeLibrary(hInstOle32);
    return hr;
  }
  catch (...)
  {
    if(hInstOle32)
      FreeLibrary(hInstOle32);
    return E_FAIL;
  }
}

Note: The corresponding rgs-file must not contain HKLM sections.

 

Відповідь корисна? Клікніть на "ВПОДОБАЙКУ" цім повідомленням! | Do you find the posts helpful? "LIKE" these posts!
Находите сообщения полезными? Поставьте "НРАВИТСЯ" этим сообщениям!
На ваше запитання відповіли? Натисніть кнопку "ПРИЙНЯТИ РІШЕННЯ" | Have your question been answered successfully? Click "ACCEPT SOLUTION" button.
На ваш вопрос успешно ответили? Нажмите кнопку "УТВЕРДИТЬ РЕШЕНИЕ"


Alexander Rivilis / Александр Ривилис / Олександр Рівіліс
Programmer & Teacher & Helper / Программист - Учитель - Помощник / Програміст - вчитель - помічник
Facebook | Twitter | LinkedIn
Expert Elite Member

Message 3 of 6

Kyudos
Advisor
Advisor

Thanks Alexander - it is useful to have this code.

 

It seems to work fine on Windows 7, but not reliably on Win10 (it's Win10 giving me problems in general!)

 

I think we'll probably go with a reg file, for predicatability.

0 Likes
Message 4 of 6

furqananees2007
Contributor
Contributor

@Kyudos @Alexander.Rivilis @OysteinW 

I'm encountering the same issue with registering the COM server. I attempted to use the provided code, but I'm receiving some unusual syntax errors at compile time—even though IntelliSense doesn't highlight any problems. Any guidance on how to resolve these errors would be greatly appreciated.

furqananees2007_0-1740508828759.png

This is the main C++ file that is automatically generated when creating a COM wrapper project using the ObjectARX Wizard.

#include "StdAfx.h"

#if defined(_DEBUG) && !defined(AC_FULL_DEBUG)
#error _DEBUG should not be defined except in internal Adesk debug builds
#endif

#include "resource.h"
#include <initguid.h>
#include "COMSPPC_i.h"
#include "COMSPPC_i.c"
#include "acadi_i.c"

#include <oleauto.h>
#include <windows.h>
#include <tchar.h>

#include "SPPointCloud.h" // Include your custom entity header

#include "SPPointCloudCOM.h"

CComModule _Module;

BEGIN_OBJECT_MAP(ObjectMap)
    OBJECT_ENTRY(CLSID_SPPointCloudCOM, CSPPointCloudCOM) // Register your COM class
END_OBJECT_MAP()

/////////////////////////////////////////////////////////////////////////////
// DLL Entry Point
extern "C"
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
{
    if (dwReason == DLL_PROCESS_ATTACH)
    {
        _Module.Init(ObjectMap, hInstance);
        DisableThreadLibraryCalls(hInstance);

        // Check if the DBX module is loaded; if not, load it
        if (!::acrxAppIsLoaded(_T("SPPointCloud.dbx"))) // Replace with your DBX module name
        {
            if (!acrxLoadModule(_T("SPPointCloud.dbx"), false, true))
                return FALSE; // This will trigger a DLL_PROCESS_DETACH right away
        }

        // Bump the reference count
        acrxLoadModule(_T("SPPointCloud.dbx"), false, false);
    }
    else if (dwReason == DLL_PROCESS_DETACH)
    {
        _Module.Term();

        // Try to decrease the refcount on the DBX module
        acrxUnloadModule(_T("SPPointCloud.dbx"));
    }
    return TRUE;    // ok
}

/////////////////////////////////////////////////////////////////////////////
// Used to determine whether the DLL can be unloaded by OLE

STDAPI DllCanUnloadNow(void)
{
    return (_Module.GetLockCount() == 0) ? S_OK : S_FALSE;
}

/////////////////////////////////////////////////////////////////////////////
// Returns a class factory to create an object of the requested type

STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
    return _Module.GetClassObject(rclsid, riid, ppv);
}

/////////////////////////////////////////////////////////////////////////////
// DllRegisterServer - Adds entries to the system registry


typedef void (*OaEnablePerUserTLibRegistration)();
STDAPI DllRegisterServer(void)
{
    HINSTANCE hInstOle32 = NULL;
    try
    {
        HRESULT hr = _Module.RegisterServer(TRUE);
        if (FAILED(hr))
        {
            hInstOle32 = LoadLibrary(_T("Oleaut32.dll"));
            if (hInstOle32)
            {
                OaEnablePerUserTLibRegistration lr = (OaEnablePerUserTLibRegistration)GetProcAddress(hInstOle32, ("OaEnablePerUserTLibRegistration"));

                if (lr != NULL)
                {
                    lr();
                    hr = _Module.RegisterServer(TRUE);
                    if (SUCCEEDED(hr))
                    {
                        FreeLibrary(hInstOle32);
                        return hr;
                    }
                }
            }

            HKEY hKCr;
            hr = RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software\\Classes"), 0, KEY_READ, &hKCr);
            if (hr != ERROR_SUCCESS)
            {
                return hr;
            }
            hr = RegOverridePredefKey(HKEY_CLASSES_ROOT, hKCr);
            RegCloseKey(hKCr);
            if (FAILED(hr))
            {
                return hr;
            }
            hr = _Module.RegisterServer(TRUE);
            RegOverridePredefKey(HKEY_CLASSES_ROOT, NULL);
            hr = S_OK;
        }
        if (hInstOle32)
            FreeLibrary(hInstOle32);
        return hr;
    }
    catch (...)
    {
        if (hInstOle32)
            FreeLibrary(hInstOle32);
        return E_FAIL;
    }
}

/////////////////////////////////////////////////////////////////////////////
// DllUnregisterServer - Removes entries from the system registry

STDAPI DllUnregisterServer(void)
{
    _Module.UnregisterServer();
    return S_OK;
}

0 Likes
Message 5 of 6

Kyudos
Advisor
Advisor

Ultimately we created self-registering COM classes using RGS files in the resources. Based on this method by Michael Geddes:

 

https://www.codeproject.com/Articles/6319/Registry-Map-for-RGS-files

 

And then simply calling DllRegisterServer in DllMain

0 Likes
Message 6 of 6

Kyudos
Advisor
Advisor

To expand a bit more. Our module is an ATL::CAtlMfcModule that looks like this:

 

 

//------------------------------------------------------------------------------
class OurModule : public ATL::CAtlMfcModule
//------------------------------------------------------------------------------
{
public:
	DECLARE_LIBID(APPLIBID);
	#if defined (_M_X64)
		DECLARE_REGISTRY_APPID_RESOURCEID(IDR_A64_REG, "OUR ACAD 64bit CLSID");
	#else
		DECLARE_REGISTRY_APPID_RESOURCEID(IDR_A32_REG, "OUR ACAD 32bit CLSID");
	#endif
};

 

 

 

The IDRs are resource IDs for the RGS file in a "REGISTRY" section of the resources.

 

We also needed this in our app class:

 

 

// DllCanUnloadNow - Allows COM to unload DLL
#if !defined(_WIN32_WCE) && !defined(_AMD64_) && !defined(_IA64_)
	#pragma comment(linker, "/EXPORT:DllCanUnloadNow=_DllCanUnloadNow@0,PRIVATE")
	#pragma comment(linker, "/EXPORT:DllGetClassObject=_DllGetClassObject@12,PRIVATE")
	#pragma comment(linker, "/EXPORT:DllRegisterServer=_DllRegisterServer@0,PRIVATE")
	#pragma comment(linker, "/EXPORT:DllUnregisterServer=_DllUnregisterServer@0,PRIVATE")
#else
	#if defined(_X86_) || defined(_SHX_)
		#pragma comment(linker, "/EXPORT:DllCanUnloadNow=_DllCanUnloadNow,PRIVATE")
		#pragma comment(linker, "/EXPORT:DllGetClassObject=_DllGetClassObject,PRIVATE")
		#pragma comment(linker, "/EXPORT:DllRegisterServer=_DllRegisterServer,PRIVATE")
		#pragma comment(linker, "/EXPORT:DllUnregisterServer=_DllUnregisterServer,PRIVATE")
	#else
		#pragma comment(linker, "/EXPORT:DllCanUnloadNow,PRIVATE")
		#pragma comment(linker, "/EXPORT:DllGetClassObject,PRIVATE")
		#pragma comment(linker, "/EXPORT:DllRegisterServer,PRIVATE")
		#pragma comment(linker, "/EXPORT:DllUnregisterServer,PRIVATE")
	#endif // (_X86_)||(_SHX_)
#endif // !_WIN32_WCE && !_AMD64_ && !_IA64_

 

 

And our registration functions look like this:

 

extern OurModule _AtlModule; // <-- extern this in the .h file

OurModule _AtlModule;

//------------------------------------------------------------------------------
STDAPI DllCanUnloadNow()
//------------------------------------------------------------------------------
{
	if (_AtlModule.GetLockCount() > 0)
	{
		return S_FALSE;
	}
	return S_OK;
}

//------------------------------------------------------------------------------
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
//------------------------------------------------------------------------------
{
	// DllGetClassObject - Returns class factory
	if (S_OK == _AtlModule.GetClassObject(rclsid, riid, ppv))
	{
		return S_OK;
	}
	return AfxDllGetClassObject(rclsid, riid, ppv);
}

//typedef void (*OaEnablePerUserTLibRegistration)();

//------------------------------------------------------------------------------
STDAPI DllRegisterServer()
//------------------------------------------------------------------------------
{
	// DllRegisterServer - Adds entries to the system registry
	//HRESULT hr = ATL::AtlSetPerUserRegistration(true);
	HRESULT hRes1 = _AtlModule.UpdateRegistryAppId(TRUE);
	HINSTANCE hInstOle32 = NULL;
	try
	{
		HRESULT hr = _AtlModule.RegisterServer(TRUE);
		if (FAILED(hr))
		{
			hInstOle32 = LoadLibrary(_T("Oleaut32.dll"));
			if (hInstOle32 != NULL)
			{
				//OaEnablePerUserTLibRegistration lr = (OaEnablePerUserTLibRegistration)GetProcAddress(hInstOle32, ("OaEnablePerUserTLibRegistration"));
				ULONG (PASCAL *lr)();
				(FARPROC&)lr = GetProcAddress(hInstOle32, ("OaEnablePerUserTLibRegistration"));

				if (lr != NULL)
				{
					lr();
					hr = _AtlModule.RegisterServer(TRUE);
					if (SUCCEEDED(hr))
					{
						FreeLibrary(hInstOle32);
						return hr;
					}
				}

				HKEY hKCr;
				hr = RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software\\Classes"), 0, KEY_READ, &hKCr);
				if (hr != ERROR_SUCCESS)
				{
					return hr;
				}
				hr = RegOverridePredefKey(HKEY_CLASSES_ROOT, hKCr);
				if (FAILED(hr))
				{
					RegCloseKey(hKCr);
					return hr;
				}
				hr = _AtlModule.RegisterServer(TRUE);

				RegCloseKey(hKCr);

				RegOverridePredefKey(HKEY_CLASSES_ROOT, NULL);
				hr = S_OK;
			}
		}
		if (hInstOle32 != NULL)
		{
			FreeLibrary(hInstOle32);
		}
		return hr;
	}
	catch (...)
	{
		if (hInstOle32)
		{
			FreeLibrary(hInstOle32);
		}
		return E_FAIL;
	}
}

//------------------------------------------------------------------------------
STDAPI DllUnregisterServer()
//------------------------------------------------------------------------------
{
	// DllUnregisterServer - Removes entries from the system registry
	_AtlModule.UpdateRegistryAppId(FALSE);
	HRESULT hRes2 = _AtlModule.UnregisterServer(TRUE);
	return hRes2;
}

 

 

 

 

0 Likes