ptrennum
asked on
LNK 2005 when compiling dll
error LNK2005: _DllMain@12 already defined in ShacoZip.obj
I get this error when I compile a dll I am trying to create using VS.NET 2003.
I added this DllMain() to the main.cpp because when I tried to regsvr32 the dll I got a message telling me that there was no entry point for the dll.
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
I have been doing some research and am seeing things relating to .def files. I am not very familiar with creating dll's but this needs to be done so a vb application can use it. Any help on how to get this to compile would be really appreciated.
PT
I get this error when I compile a dll I am trying to create using VS.NET 2003.
I added this DllMain() to the main.cpp because when I tried to regsvr32 the dll I got a message telling me that there was no entry point for the dll.
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
I have been doing some research and am seeing things relating to .def files. I am not very familiar with creating dll's but this needs to be done so a vb application can use it. Any help on how to get this to compile would be really appreciated.
PT
'DllMain()' is not needed for 'regsvr32', the latter app needs 'DllRegisterServer'()' and/or 'DllUnregisterServer()' - you can safely remove your 'DllMain()' code. See also http://support.microsoft.com/default.aspx?scid=kb;en-us;207132 ("INFO: How Regsvr32.exe Registers and Unregisters COM DLLs")
ASKER
I just added:
/FORCE:MULTIPLE
to my command line options under linker in project properties.
This allowed me to compile however I can still not register the dll successfully??
/FORCE:MULTIPLE
to my command line options under linker in project properties.
This allowed me to compile however I can still not register the dll successfully??
>>This allowed me to compile however I can still not register the dll successfully?
As I wrote, you'll need to provide 'DllRegisterServer'()' and/or 'DllUnregisterServer()', but _not_ 'DllMain()'.
As I wrote, you'll need to provide 'DllRegisterServer'()' and/or 'DllUnregisterServer()', but _not_ 'DllMain()'.
ASKER
Sorry, I wrote that before I noticed your post. It looks like there is source there to create my own register function, however I would really just like to add the register and un register to my existing project. Are there any good examples of how that can be done??
BTW, about how to implement the functionality of the aforementioned functions, see http://msdn.microsoft.com/library/en-us/dnesscom/html/classesservers.asp ("Classes and Servers (Essential COM)"):
All well-implemented COM servers support self-registration. For an in-process server, this means that the DLL must export the well-known functions
STDAPI DllRegisterServer(void);
STDAPI DllUnregisterServer(void);
Note that STDAPI is simply a macro that indicates that the function returns an HRESULT and uses COM's standard calling convention for global functions. These routines must be explicitly exported, using either a module definition file, linker switches, or compiler directives. These routines are used by the Class Store to configure the local cache after downloading the file to the client machine. In addition to the Class Store, these well-known routines are used by various environments (e.g., Microsoft Transaction Server, ActiveX Code Download, miscellaneous setup utilities) to install or uninstall servers on host machines. The Win32 SDK includes a utility, REGSVR32.EXE, that will install or uninstall a COM in-process server using these well-known exported functions.
All well-implemented COM servers support self-registration. For an in-process server, this means that the DLL must export the well-known functions
STDAPI DllRegisterServer(void);
STDAPI DllUnregisterServer(void);
Note that STDAPI is simply a macro that indicates that the function returns an HRESULT and uses COM's standard calling convention for global functions. These routines must be explicitly exported, using either a module definition file, linker switches, or compiler directives. These routines are used by the Class Store to configure the local cache after downloading the file to the client machine. In addition to the Class Store, these well-known routines are used by various environments (e.g., Microsoft Transaction Server, ActiveX Code Download, miscellaneous setup utilities) to install or uninstall servers on host machines. The Win32 SDK includes a utility, REGSVR32.EXE, that will install or uninstall a COM in-process server using these well-known exported functions.
>>I would really just like to add the register and un register to my existing project
We're kinda out-of-sync :o)
Check the above article and it's code samples, the main responsibility of the registration code is to cerate registry entries, e.g.
const char *g_RegTable[][3] = {
// format is { key, value name, value }
{ "CLSID\\{571F1680-CC83-11d 0-8C48-008 0C73925BA} ", 0, "Gorilla" },
{ "CLSID\\{571F1680-CC83-11d 0-8C48-008 0C73925BA} \\InprocSe rver32",
0, (const char*)-1 // rogue value indicating file name
},
{ "CLSID\\{571F1680-CC83-11d 0-8C48-008 0C73925BA} \\ProgID",
0, "Apes.Gorilla.1"
},
{ "Apes.Gorilla.1", 0, "Gorilla" },
{ "Apes.Gorilla.1\\CLSID",
0, "{571F1680-CC83-11d0-8C48- 0080C73925 BA}" },
};
STDAPI DllRegisterServer(void) {
HRESULT hr = S_OK;
// look up server's file name
char szFileName[MAX_PATH];
GetModuleFileNameA(g_hinst Dll, szFileName, MAX_PATH);
// register entries from table
int nEntries = sizeof(g_RegTable)/sizeof( *g_RegTabl e);
for (int i = 0; SUCCEEDED(hr) && i < nEntries; i++) {
const char *pszKeyName = g_RegTable[i][0];
const char *pszValueName = g_RegTable[i][1];
const char *pszValue = g_RegTable[i][2];
// map rogue value to module file name
if (pszValue == (const char*)-1)
pszValue = szFileName;
HKEY hkey;
// create the key
long err = RegCreateKeyA(HKEY_CLASSES _ROOT,
pszKeyName, &hkey);
if (err == ERROR_SUCCESS) {
// set the value
err = RegSetValueExA(hkey, pszValueName, 0,
REG_SZ, (const BYTE*)pszValue,
(strlen(pszValue) + 1));
RegCloseKey(hkey);
}
if (err != ERROR_SUCCESS) {
// if cannot add key or value, back out and fail
DllUnregisterServer();
hr = SELFREG_E_CLASS;
}
}
return hr;
}
We're kinda out-of-sync :o)
Check the above article and it's code samples, the main responsibility of the registration code is to cerate registry entries, e.g.
const char *g_RegTable[][3] = {
// format is { key, value name, value }
{ "CLSID\\{571F1680-CC83-11d
{ "CLSID\\{571F1680-CC83-11d
0, (const char*)-1 // rogue value indicating file name
},
{ "CLSID\\{571F1680-CC83-11d
0, "Apes.Gorilla.1"
},
{ "Apes.Gorilla.1", 0, "Gorilla" },
{ "Apes.Gorilla.1\\CLSID",
0, "{571F1680-CC83-11d0-8C48-
};
STDAPI DllRegisterServer(void) {
HRESULT hr = S_OK;
// look up server's file name
char szFileName[MAX_PATH];
GetModuleFileNameA(g_hinst
// register entries from table
int nEntries = sizeof(g_RegTable)/sizeof(
for (int i = 0; SUCCEEDED(hr) && i < nEntries; i++) {
const char *pszKeyName = g_RegTable[i][0];
const char *pszValueName = g_RegTable[i][1];
const char *pszValue = g_RegTable[i][2];
// map rogue value to module file name
if (pszValue == (const char*)-1)
pszValue = szFileName;
HKEY hkey;
// create the key
long err = RegCreateKeyA(HKEY_CLASSES
pszKeyName, &hkey);
if (err == ERROR_SUCCESS) {
// set the value
err = RegSetValueExA(hkey, pszValueName, 0,
REG_SZ, (const BYTE*)pszValue,
(strlen(pszValue) + 1));
RegCloseKey(hkey);
}
if (err != ERROR_SUCCESS) {
// if cannot add key or value, back out and fail
DllUnregisterServer();
hr = SELFREG_E_CLASS;
}
}
return hr;
}
ASKER
Sorry I'm not exactly following here, how are we out of sync?
I do not need to implement these functions in my code?
Is there anything I need to add to my .def file?
I do not need to implement these functions in my code?
Is there anything I need to add to my .def file?
>>how are we out of sync?
Never mind, that was about when we're posting comments :o)
>>I do not need to implement these functions in my code?
Yes, you do - unless you already have - are they declared like
extern "C" STDAPI DllRegisterServer ( void);
extern "C" STDAPI DllUnregisterServer ( void);
?
If so, you won't have to add them to your .def file.
Never mind, that was about when we're posting comments :o)
>>I do not need to implement these functions in my code?
Yes, you do - unless you already have - are they declared like
extern "C" STDAPI DllRegisterServer ( void);
extern "C" STDAPI DllUnregisterServer ( void);
?
If so, you won't have to add them to your .def file.
ASKER
No I don't have them anywhere in my code
Well, then it's not surprising that regsvr32.exe complains about them as 'missing'. Are you creating a COM DLL at all?
ASKER
So to summarize here:
I need to add ->
extern "C" STDAPI DllRegisterServer ( void);
extern "C" STDAPI DllUnregisterServer ( void);
to my main.h, then implement them in my main.cpp.
I need to add ->
extern "C" STDAPI DllRegisterServer ( void);
extern "C" STDAPI DllUnregisterServer ( void);
to my main.h, then implement them in my main.cpp.
ASKER
I am creating an MFC DLL
>>I need to add ->
>> extern "C" STDAPI DllRegisterServer ( void);
>> extern "C" STDAPI DllUnregisterServer ( void);
>>to my main.h, then implement them in my main.cpp.
If your DLL implements a COM/OLE object that should be exposed: Yes. If you're building a standard DLL (i.e. without COM/OLE support), there's no need to use 'regsvr32.exe' or to provide these functions.
>> extern "C" STDAPI DllRegisterServer ( void);
>> extern "C" STDAPI DllUnregisterServer ( void);
>>to my main.h, then implement them in my main.cpp.
If your DLL implements a COM/OLE object that should be exposed: Yes. If you're building a standard DLL (i.e. without COM/OLE support), there's no need to use 'regsvr32.exe' or to provide these functions.
ASKER
I need to use this dll in a vb application, I am assuming to do this it will need to be a com dll
That depends - a C++ DLL can be used from VB without COM. But, in general, you are right, mostly COM is used. In this case, the registration code is supposed to create the required registry entries, as described in the article I linked above.
ASKER
In dll unregister what on earth are these supposed to represent??
for (int i = nEntries - 1; i >= 0; i—–)
for (int i = nEntries - 1; i >= 0; i—–)
ASKER
Also in dllregister:
GetModuleFileNameA(g_hinst Dll, szFileName, MAX_PATH);
g_hinstDll is undefined.
GetModuleFileNameA(g_hinst
g_hinstDll is undefined.
LOL, missed that - well, it seems that the whole code should read
STDAPI DllUnregisterServer(void) {
HRESULT hr = S_OK;
int nEntries = sizeof(g_RegTable)/sizeof( *g_RegTabl e);
for (int i = nEntries - 1; i >= 0; i--){
const char *pszKeyName = g_RegTable[i][0];
long err = RegDeleteKeyA(HKEY_CLASSES _ROOT, pszKeyName);
if (err != ERROR_SUCCESS)
hr = S_FALSE;
}
return hr;
}
MS seems to have had a 'lil 'character set accident' there :o)
BTW, don't forget to make them 'extern "C"', or regsvr32.exe won't find them either.
STDAPI DllUnregisterServer(void) {
HRESULT hr = S_OK;
int nEntries = sizeof(g_RegTable)/sizeof(
for (int i = nEntries - 1; i >= 0; i--){
const char *pszKeyName = g_RegTable[i][0];
long err = RegDeleteKeyA(HKEY_CLASSES
if (err != ERROR_SUCCESS)
hr = S_FALSE;
}
return hr;
}
MS seems to have had a 'lil 'character set accident' there :o)
BTW, don't forget to make them 'extern "C"', or regsvr32.exe won't find them either.
ASKER
Ok so I can basically copy those functions into my source,
I still am not able to register my dll.
I don't need to add anything to my .def file?
Here is my source code in my main.cpp file, I know it isn't the prettiest but like I said I'm not exactly experienced with this kind of stuff.
// CShacoZipApp
// The module attribute causes DllMain, DllRegisterServer and DllUnregisterServer to be automatically implemented for you
BEGIN_MESSAGE_MAP(CShacoZi pApp, CWinApp)
END_MESSAGE_MAP()
extern "C" STDAPI DllRegisterServer(void);
extern "C" STDAPI DllUnregisterServer(void);
// CShacoZipApp construction
CShacoZipApp::CShacoZipApp ()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
// The one and only CShacoZipApp object
CShacoZipApp theApp;
// CShacoZipApp initialization
BOOL CShacoZipApp::InitInstance ()
{
CWinApp::InitInstance();
return TRUE;
}
const char *g_RegTable[][3] = {
// format is { key, value name, value }
{ "CLSID\\{571F1680-CC83-11d 0-8C48-008 0C73925BA} ", 0, "Gorilla" },
{ "CLSID\\{571F1680-CC83-11d 0-8C48-008 0C73925BA} \\InprocSe rver32",
0, (const char*)-1 // rogue value indicating file name
},
{ "CLSID\\{571F1680-CC83-11d 0-8C48-008 0C73925BA} \\ProgID",
0, "Apes.Gorilla.1"
},
{ "Apes.Gorilla.1", 0, "Gorilla" },
{ "Apes.Gorilla.1\\CLSID",
0, "{571F1680-CC83-11d0-8C48- 0080C73925 BA}" },
};
extern "C" STDAPI DllRegisterServer(void) {
HRESULT hr = S_OK;
// look up server's file name
char szFileName[MAX_PATH];
//GetModuleFileNameA(g_hin stDll, szFileName, MAX_PATH);
GetModuleFileNameA(NULL, szFileName, MAX_PATH);
// register entries from table
int nEntries = sizeof(g_RegTable)/sizeof( *g_RegTabl e);
for (int i = 0; SUCCEEDED(hr) && i < nEntries; i++) {
const char *pszKeyName = g_RegTable[i][0];
const char *pszValueName = g_RegTable[i][1];
const char *pszValue = g_RegTable[i][2];
// map rogue value to module file name
if (pszValue == (const char*)-1)
pszValue = szFileName;
HKEY hkey;
// create the key
long err = RegCreateKeyA(HKEY_CLASSES _ROOT,
pszKeyName, &hkey);
if (err == ERROR_SUCCESS) {
// set the value
err = RegSetValueExA(hkey, pszValueName, 0,
REG_SZ, (const BYTE*)pszValue,
(strlen(pszValue) + 1));
RegCloseKey(hkey);
}
if (err != ERROR_SUCCESS) {
// if cannot add key or value, back out and fail
DllUnregisterServer();
hr = SELFREG_E_CLASS;
}
}
return hr;
}
extern "C" STDAPI DllUnregisterServer(void) {
HRESULT hr = S_OK;
int nEntries = sizeof(g_RegTable)/sizeof( *g_RegTabl e);
for (int i = nEntries - 1; i >= 0; i--){
const char *pszKeyName = g_RegTable[i][0];
long err = RegDeleteKeyA(HKEY_CLASSES _ROOT, pszKeyName);
if (err != ERROR_SUCCESS)
hr = S_FALSE;
}
return hr;
}
I still am not able to register my dll.
I don't need to add anything to my .def file?
Here is my source code in my main.cpp file, I know it isn't the prettiest but like I said I'm not exactly experienced with this kind of stuff.
// CShacoZipApp
// The module attribute causes DllMain, DllRegisterServer and DllUnregisterServer to be automatically implemented for you
BEGIN_MESSAGE_MAP(CShacoZi
END_MESSAGE_MAP()
extern "C" STDAPI DllRegisterServer(void);
extern "C" STDAPI DllUnregisterServer(void);
// CShacoZipApp construction
CShacoZipApp::CShacoZipApp
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
// The one and only CShacoZipApp object
CShacoZipApp theApp;
// CShacoZipApp initialization
BOOL CShacoZipApp::InitInstance
{
CWinApp::InitInstance();
return TRUE;
}
const char *g_RegTable[][3] = {
// format is { key, value name, value }
{ "CLSID\\{571F1680-CC83-11d
{ "CLSID\\{571F1680-CC83-11d
0, (const char*)-1 // rogue value indicating file name
},
{ "CLSID\\{571F1680-CC83-11d
0, "Apes.Gorilla.1"
},
{ "Apes.Gorilla.1", 0, "Gorilla" },
{ "Apes.Gorilla.1\\CLSID",
0, "{571F1680-CC83-11d0-8C48-
};
extern "C" STDAPI DllRegisterServer(void) {
HRESULT hr = S_OK;
// look up server's file name
char szFileName[MAX_PATH];
//GetModuleFileNameA(g_hin
GetModuleFileNameA(NULL, szFileName, MAX_PATH);
// register entries from table
int nEntries = sizeof(g_RegTable)/sizeof(
for (int i = 0; SUCCEEDED(hr) && i < nEntries; i++) {
const char *pszKeyName = g_RegTable[i][0];
const char *pszValueName = g_RegTable[i][1];
const char *pszValue = g_RegTable[i][2];
// map rogue value to module file name
if (pszValue == (const char*)-1)
pszValue = szFileName;
HKEY hkey;
// create the key
long err = RegCreateKeyA(HKEY_CLASSES
pszKeyName, &hkey);
if (err == ERROR_SUCCESS) {
// set the value
err = RegSetValueExA(hkey, pszValueName, 0,
REG_SZ, (const BYTE*)pszValue,
(strlen(pszValue) + 1));
RegCloseKey(hkey);
}
if (err != ERROR_SUCCESS) {
// if cannot add key or value, back out and fail
DllUnregisterServer();
hr = SELFREG_E_CLASS;
}
}
return hr;
}
extern "C" STDAPI DllUnregisterServer(void) {
HRESULT hr = S_OK;
int nEntries = sizeof(g_RegTable)/sizeof(
for (int i = nEntries - 1; i >= 0; i--){
const char *pszKeyName = g_RegTable[i][0];
long err = RegDeleteKeyA(HKEY_CLASSES
if (err != ERROR_SUCCESS)
hr = S_FALSE;
}
return hr;
}
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
JKR - You are fantastic!!
Thank you very much for your patience and knowledge!
PT
Thank you very much for your patience and knowledge!
PT
You're most welcome :o)