Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 342
  • Last Modified:

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
0
ptrennum
Asked:
ptrennum
  • 11
  • 11
1 Solution
 
jkrCommented:
'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")
0
 
ptrennumAuthor Commented:
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??
0
 
jkrCommented:
>>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()'.
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
ptrennumAuthor Commented:
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??
0
 
jkrCommented:
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.
0
 
jkrCommented:
>>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;
}


0
 
ptrennumAuthor Commented:
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?
0
 
jkrCommented:
>>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.
0
 
ptrennumAuthor Commented:
No I don't have them anywhere in my code
0
 
jkrCommented:
Well, then it's not surprising that regsvr32.exe complains about them as 'missing'. Are you creating a COM DLL at all?
0
 
ptrennumAuthor Commented:
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.
0
 
ptrennumAuthor Commented:
I am creating an MFC DLL
0
 
jkrCommented:
>>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.
0
 
ptrennumAuthor Commented:
I need to use this dll in a vb application, I am assuming to do this it will need to be a com dll
0
 
jkrCommented:
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.
0
 
ptrennumAuthor Commented:
In dll unregister what on earth are these supposed to represent??
for (int i = nEntries - 1; i >= 0; i—–)
0
 
ptrennumAuthor Commented:
Also in dllregister:

GetModuleFileNameA(g_hinstDll, szFileName, MAX_PATH);
g_hinstDll is undefined.
0
 
jkrCommented:
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.
0
 
ptrennumAuthor Commented:
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;
}
0
 
jkrCommented:
>>I still am not able to register my dll.

U, make the declaration read

extern "C"  STDAPI  __declspec(dllexport) DllRegisterServer(void);
extern "C"  STDAPI  __declspec(dllexport) DllUnregisterServer(void);

If you want to put them in your .def file, you could use

LIBRARY      "ShacoZip"

EXPORTS
    DllRegisterServer           @4 PRIVATE
    DllUnregisterServer         @5 PRIVATE
0
 
ptrennumAuthor Commented:
JKR - You are fantastic!!

Thank you very much for your patience and knowledge!

PT
0
 
jkrCommented:
You're most welcome :o)
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 11
  • 11
Tackle projects and never again get stuck behind a technical roadblock.
Join Now