Link to home
Start Free TrialLog in
Avatar of ptrennum
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
Avatar of jkr
jkr
Flag of Germany image

'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")
Avatar of ptrennum
ptrennum

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??
>>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()'.
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.
>>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-11d0-8C48-0080C73925BA}",  0, "Gorilla" },
{ "CLSID\\{571F1680-CC83-11d0-8C48-0080C73925BA}\\InprocServer32",
  0, (const char*)-1 // rogue value indicating file name
},
{ "CLSID\\{571F1680-CC83-11d0-8C48-0080C73925BA}\\ProgID",
  0, "Apes.Gorilla.1"
},
{ "Apes.Gorilla.1", 0,  "Gorilla" },
{ "Apes.Gorilla.1\\CLSID",
   0,  "{571F1680-CC83-11d0-8C48-0080C73925BA}" },
};


STDAPI DllRegisterServer(void) {
  HRESULT hr = S_OK;
// look up server's file name
  char szFileName[MAX_PATH];
  GetModuleFileNameA(g_hinstDll, szFileName, MAX_PATH);
// register entries from table
  int nEntries = sizeof(g_RegTable)/sizeof(*g_RegTable);
  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;
}


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?
>>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.
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?
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 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.
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.
In dll unregister what on earth are these supposed to represent??
for (int i = nEntries - 1; i >= 0; i—–)
Also in dllregister:

GetModuleFileNameA(g_hinstDll, szFileName, MAX_PATH);
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_RegTable);
  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.
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(CShacoZipApp, 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-11d0-8C48-0080C73925BA}",  0, "Gorilla" },
{ "CLSID\\{571F1680-CC83-11d0-8C48-0080C73925BA}\\InprocServer32",
  0, (const char*)-1 // rogue value indicating file name
},
{ "CLSID\\{571F1680-CC83-11d0-8C48-0080C73925BA}\\ProgID",
  0, "Apes.Gorilla.1"
},
{ "Apes.Gorilla.1", 0,  "Gorilla" },
{ "Apes.Gorilla.1\\CLSID",
   0,  "{571F1680-CC83-11d0-8C48-0080C73925BA}" },
};

extern "C" STDAPI DllRegisterServer(void) {
  HRESULT hr = S_OK;
// look up server's file name
  char szFileName[MAX_PATH];
  //GetModuleFileNameA(g_hinstDll, szFileName, MAX_PATH);
  GetModuleFileNameA(NULL, szFileName, MAX_PATH);
// register entries from table
  int nEntries = sizeof(g_RegTable)/sizeof(*g_RegTable);
  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_RegTable);
  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;
}
ASKER CERTIFIED SOLUTION
Avatar of jkr
jkr
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
JKR - You are fantastic!!

Thank you very much for your patience and knowledge!

PT
You're most welcome :o)