 |
|
 |
This excellent source code has worked well until VC2005. However, VC2010 has no success with it. Please someone make this work under VC2010. Firstly, it didn't compile, so I managed to modify a few lines and finally succeeded in compile/link. The main change was return /*_Module.*/ATL::_pAtlModule->UpdateRegistryFromResource((UINT)x, bRegister, _GetRegistryMap() );\ The real problem was that registering always failed with 0x80020009 from DllRegisterServer call. I don't know where to go any more. If someone can fix this to work, that'd be great. thx HR thx HR
-- modified 5 Mar '12.
|
|
|
|
 |
|
|
 |
|
 |
Please explain how we should go about replacing our existing wizard-generated RGS files with your special RGS + class combo. Personally I would like to know HOW the content of the RGS files ends up in the registry and WHY your modified technique also works. Most of all I'd like to know a bunch of map macros in a C++ header file can affect the way that a resource file is interpreted.
|
|
|
|
 |
|
 |
The author isn't very talkative.... the good news is, you don't have to replace all your existing RGS files at once. You might want to replace just one to start with, to prove that the new system works for you. I will explain how to do this.
So let's say you have a class Foo in library BarLib, with an ATL class called CFoo and a threading model of Both.
To use the registry map, add RegistryMap.hpp and objects.rgs to your project, then add #include "RegistryMap.hpp" to the top of the header file that contains CFoo. Or better yet, put #include "RegistryMap.hpp" in StdAfx.h so that you don't have to do this step for every class.
Originally your header file for CFoo contains something like...
class ATL_NO_VTABLE CFoo :
public CComObjectRoot,
public CComCoClass<CFoo, &CLSID_Foo>,
public ISupportErrorInfo,
public IDispatchImpl<IFoo, &IID_IFoo, &LIBID_FooLib, 1, 0>
{
public:
DECLARE_REGISTRY_RESOURCEID(IDR_FOO)
Change this too
class ATL_NO_VTABLE CFoo :
public CComObjectRoot,
public CComCoClass<CFoo, &CLSID_Foo>,
public ISupportErrorInfo,
public IDispatchImpl<IFoo, &IID_IFoo, &LIBID_FooLib, 1, 0>
{
public:
DECLARE_REGISTRY_RESOURCEID_EX(IDR_OBJECT)
BEGIN_REGISTRY_MAP(CFoo)
REGMAP_ENTRY("PROGID", "Bar.Foo")
REGMAP_ENTRY("VERSION", "1")
REGMAP_ENTRY("DESCRIPTION", "Foo Class")
REGMAP_UUID("CLSID", CLSID_Foo)
REGMAP_UUID("LIBID", LIBID_BarLib)
REGMAP_ENTRY("THREADING", "Both")
END_REGISTRY_MAP()
Note: if you forget one of the variables in your registry map, an error will occur when registering your COM DLL with regsvr32. ATL will produce error 0x80020009 (the result of CRegParser::PreProcessBuffer() in statreg.h calling GenerateError(E_ATL_NOT_IN_MAP)).
You also need to change your resource file to point to objects.rgs instead of Foo.rgs, and to use just one IDR constant for all classes that use objects.rgs.
For example, change the line in Foo.rc from
IDR_FOO REGISTRY "Foo.rgs"
to
IDR_OBJECT REGISTRY "objects.rgs"
Finally, you can delete Foo.rgs.
When I used this code, I got an error in DECLARE_REGISTRY_RESOURCEID_EX, which is defined as
#define DECLARE_REGISTRY_RESOURCEID_EX(x)\
static HRESULT WINAPI UpdateRegistry(BOOL bRegister)\
{\
return _Module.UpdateRegistryFromResource((UINT)x, bRegister, _GetRegistryMap() );\
}
To fix this error, I changed it to
#define DECLARE_REGISTRY_RESOURCEID_EX(x)\
static HRESULT WINAPI UpdateRegistry(BOOL bRegister)\
{\
return ATL::_pAtlModule->UpdateRegistryFromResource
((UINT)x, bRegister, _GetRegistryMap() );\
}modified on Friday, February 19, 2010 1:52 PM
|
|
|
|
 |
|
 |
Thanks for this update. I have not been programming in C++/ATL land for a while, so apologies for being quite slow to comment. Presumably there have been changes to ATL that required some modifications, so thanks for posting the changes. //.ichael
|
|
|
|
 |
|
 |
Have you tried this for VC2010 too? I am getting some errors and this needs some fix for VC2010. If you can figure it out please let me know. thx
|
|
|
|
 |
|
 |
No, I can't help; I am still on VC2008 (because I program for WinCE and MS dropped support for CE in VS2010.)
|
|
|
|
 |
|
 |
BTW, what does Objects.rgs look like?
|
|
|
|
 |
|
 |
It's in the article:
HKCR
{
%PROGID%.%VERSION% = s '%DESCRIPTION%'
{
CLSID = s '%CLSID%'
}
%PROGID% = s '%DESCRIPTION%'
{
CLSID = s '%CLSID%'
CurVer = s '%PROGID%.%VERSION%'
}
NoRemove CLSID
{
ForceRemove %CLSID% = s '%DESCRIPTION%'
{
ProgID = s '%PROGID%.%VERSION%'
VersionIndependentProgID = s '%PROGID%'
ForceRemove 'Programmable'
InprocServer32 = s '%MODULE%'
{
val ThreadingModel = s '%THREADING%'
}
'TypeLib' = s '{}'
}
}
}
Actually mine has a small difference ('TypeLib' = s '{}') but I don't recall any reason why.
|
|
|
|
 |
|
 |
In your example, how is 'CLSID_ClassName' defined? I am trying to figure out a way to define a GUID value constant so that I can use is with the registry map and with the IDL file for my COM classes.
|
|
|
|
 |
|
 |
First, I would like to thanks Michael for his great idea
The CLSIDs are defined in the IDL file by the uuid attribute set on the coclass
[uuid(618A7B8C-FED6-4A48-83C1-B1057A91A590)]
coclass ClassName
{
[default] interface IClassName;
}From the statement above, the midl compiler generates the following macros in the <project>_i.c file:
#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
...
MIDL_DEFINE_GUID(CLSID, CLSID_ClassName,0x618A7B8C,0xFED6,0x4A48,0x83,0xC1,0xB1,0x05,0x7A,0x91,0xA5,0x90);wich defines a CLSID structure containing the GUID of the coclass.
I hope this will answer your question.
As an improvement, it is possible to throw exceptions from the methods of the _ATL_REGMAP_ENTRYKeeper class. In such a case, any problem can be clearly reported during the registration process (regsvr32). For example:_ATL_REGMAP_ENTRYKeeper(const wchar_t* key, const wchar_t* data)
{
if (key == NULL) throw E_INVALIDARG;
szKey = key;
if (data== NULL) throw E_INVALIDARG;
HRESULT hr = S_OK;
size_t cch = 0;
const size_t cchMax = 255; hr = ::StringCchLength(data, cchMax, &cch);
if (FAILED(hr)) throw hr;
szData = new wchar_t[cch + 1];
hr = ::StringCchCopyW(const_cast<STRSAFE_LPWSTR>(szData), cch + 1, data);
if (FAILED(hr)) throw hr;
}
jmarzou
|
|
|
|
 |
|
 |
This article is very good and I use it pretty much when building ATL COM dll.
However, when building COM exe server, there are a few more things to take care of
[1] We need to take care of one more .rgs file for the exe itself. For example,
HKCR
{
NoRemove AppID
{
{92A64021-5C7D-49d4-BFFE-D4343B48C599} = s 'MyCOMExe'
'MyCOMExe.EXE'
{
val AppID = s {92A64021-5C7D-49d4-BFFE-D4343B48C599}
}
}
}
Is there a way to define %APPID% for this .rgs so that I can replace the above as
HKCR
{
NoRemove AppID
{
%APPID% = s 'MyCOMExe'
'MyCOMExe.EXE'
{
val AppID = s %APPID%
}
}
}
[2] Each COM class inside this exe server has one more attribute called AppID. I also need to use %APPID% as shown below:
HKCR
{
%PROGID%.%VERSION% = s '%DESCRIPTION%'
{
CLSID = s '%CLSID%'
}
%PROGID% = s '%DESCRIPTION%'
{
CLSID = s '%CLSID%'
CurVer = s '%PROGID%.%VERSION%'
}
NoRemove CLSID
{
ForceRemove %CLSID% = s '%DESCRIPTION%'
{
ProgID = s '%PROGID%.%VERSION%'
VersionIndependentProgID = s '%PROGID%'
ForceRemove 'Programmable'
LocalServer32 = s '%MODULE%'
val AppID = s '%APPID%'
'TypeLib' = s '%LIBID%'
}
}
}
|
|
|
|
 |
|
 |
Presumably you will have discovered that adding
REGMAP_ENTRY("APPID", "YourApp")
will quite happily expand %APPID% inside the rgs file.
//.ichael G.
|
|
|
|
 |
|
 |
A demo would be useful
|
|
|
|
 |
|
 |
I am new to ATL actually and thats why a bit confused with the article. I too want to cahnge the rgs file because of a version upgrade, but not getting how it can be done. can you be a bit simple..
Rahul
|
|
|
|
 |
|
 |
FYI...
To get this compiling and working in an atl7 com object built in .net(not upgraded to v60) I had to change the following line in registrymap.hpp
from
return _Module->UpdateRegistryFromResource((UINT)x, bRegister, _GetRegistryMap() );\
to
return ATL::_pAtlModule->UpdateRegistryFromResource((UINT)x, bRegister, _GetRegistryMap() );\
Gilles Gauthier
|
|
|
|
 |
|
 |
Thankyou, I'll incorporate that. Is there a version string that you (or anybody else) knows of that I can use to select which line to use?
//.
|
|
|
|
 |
|
 |
I'm wondering if anyone has seen or used any IDE tools
that can change all GUIDS/IIDs for a COM project. One
of my projects has 30+ classes, and I have to change
the IIDs and GUIDs for all of them in a major version
upgrade.
There's got to be a better way....
|
|
|
|
 |
|
 |
It's probably really bad COM practice, but we use a scheme at work where we embed the version in the uuid - and I have a macro that prepends the version. It probably breaks the uniqueness, but it works.
//.
|
|
|
|
 |
|
 |
Thanks for this excellent tip.
You might want to consider an example showing
where the BEGIN/END_REGISTRY_MAP goes (I presume
in the .h of the COM object).
|
|
|
|
 |
|
 |
Yes indeed. I have modified the article appropriately. Of course you are correct in your presumtions - and I normally put it below the DECLARE_REGISTRY_RESOURCEID_EX(RGS_OBJECT) declaration.
BTW, I would have responded sooner except that the site went down just as I went to post it *sigh*
//.
|
|
|
|
 |