views:

228

answers:

5
+1  Q: 

Link issues (VC6)

I've opened an old workspace that is a libray and its test harness. It used to work fine but now doesn't and older versions of the code don't work either with the same errors. I've tried recreating the project and that causes the same errors too. Nothing seems out of order in project settings and the code generated works in the main app.

I've stripped out most of the files and got it down to the bare minimum to generate the error. Unfortunately I can't post the project as this is used in production code.

The LNK2001 linker error I get usually means I've left off a library or forgot to implement a virtual function. However this is part of the standard template library - and is a header at that.

The code that is listed as having the problem in IOCompletionPort.obj doesn't actually use std::string directly, but does call a class that does: Comms::Exception accepts a std::string and the value of GetLastError or WSAGetLastError.

The function mentioned in the error (GetMessage) is implemented, but is a virtual function so other classes can override it if need be. However it appears that the compiler has made it as an Ansi version, but I can't find any options in the settings that would control that. I suspect that might be the problem but since there's very little in the way of options for the library I have no way of knowing for sure. However both projects to specify _MBCS in the compiler options.

--------------------Configuration: TestComms - Win32 Debug--------------------
Linking... 
Comms.lib(IOCompletionPort.obj) : error LNK2001: unresolved external symbol "public: virtual class std::basic_string,class std::allocator > __thiscall Comms::Exception::GetMessageA(void)const " (?GetMessageA@
Exception@Comms@@UBE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ) 
Debug/TestComms.exe : fatal error LNK1120: 1 unresolved externals 
Error executing link.exe.

TestComms.exe - 2 error(s), 0 warning(s)

Any suggestions? I've lost most of the morning to this and don't want to lose most of the afternoon too.

Thanks, G.

+2  A: 

One possibility lies with Win32 ANSI/Unicode "name-mangling", which turns the symbol "GetMessage" into either "GetMessageA" or "GetMessageW". There are three possibilities:

  1. Windows.h hasn't been loaded, so GetMessage stays GetMessage

  2. Windows.h was loaded with symbols set for ANSI, so GetMessage becomes GetMessageA

  3. Windows.h was loaded with symbols set for Unicode, so GetMessage becomes GetMessageW

If you've compiled two different files in ways that trigger two different scenarios, you'll get a linker error. The error message indicates that the Comms::Exception class was an instance of #2, above -- perhaps it's used somewhere that windows.h hasn't been loaded?

Other things I'd do in your place, just as a matter of routine: 1) Ensure that my include and library paths don't contain anything that I'm not expecting. 2) Do a "build clean" and then manually verify it, deleting any extra object files if necessary. 3) Make sure there aren't any hardcoded paths in include statements that don't mean what they meant when the project was originally rebuilt.

EDIT: Fighting with the formatting :(

Curt Hagenlocher
A: 

windows.h is declared at the top of IOCompletionPort.h as an include - I was sick of seeing 7 lines just to include 1 file so I have wrapped it its own file and includes that itself. This also contains some additional #defines (ie ULONG_PTR) as our main app won't compile with the Platform SDK installed:-(

  1. That is confirmed. Nothing is out of place.
  2. I've done that - deleted the build directories
  3. I never use hard-coded paths.

Thanks, G.

graham.reeds
A: 

Presuming you haven't futzed around with the Project settings deleting something you ought not have (which is where I'd expect external dependencies like User32.lib to be):

Check Tools | Options | Directories | Libraries (going from memory here) and ensure that you're not missing the common-all-garden variety lib directories (again, without VC6 in front of me, I can't tell you what they are)

Josh
A: 

@Curt: I think you came the closest. I haven't tested this but I think I sort of gave the answer in my original question.

GetMessage is a define in Windows.h wrapped in a ifndef block to switch between Ansi (GetMessageA) and Unicode (GetMessageW).

graham.reeds
A: 

This is a general problem with the way Microsoft handled the ANSI vs. Unicode APIs. Since they are all (or pretty much all) done by defining macros for the function names that resolve to the 'A' or 'W' versions of the function names you cannot safely have an identifier in your namespace/class/struct/enum/function that matches a Windows API name.

The windows.h macros run roughshod over all other namespaces.

Michael Burr