Compiler Linker External Symbol Mhook_SetHook - c++

Visual Studio 2017 (fresh install- command line version) gives error:
LNK2019: unresolved external symbol Mhook_SetHook referenced in function wmain
LNK2019: unresolved external symbol Mhook_UnHook referenced in function wmain
Compile command: cl /Y- /EHsc /DUNICODE mhook-test.cpp gdi32.lib user32.lib
I thought this might be related to C / C++ mixup, so I modified mhook.h as follows:
#ifdef __cplusplus
extern "C" {
#endif
BOOL Mhook_SetHook(PVOID *ppSystemFunction, PVOID pHookFunction);
BOOL Mhook_Unhook(PVOID *ppHookedFunction);
#ifdef __cplusplus
} // extern "C"
#endif
This did not make a difference in results.
I don't understand why the linker is having a problem.
mhook-test.cpp came with the mhook library.

The mhook library is not distributed precompiled; it must be compiled into libraries which can then be specified to linker.
So, for each ".c" and ".cpp" file in the source code of the mhook directory:
"First, run cl /c /EHsc MathFuncsLib.cpp to compile the code and create an object file that's named MathFuncsLib.obj. (The cl command invokes the compiler, Cl.exe, and the /c option specifies compile without linking). Second, run lib MathFuncsLib.obj to link the code and create the static library MathFuncsLib.lib." - https://msdn.microsoft.com/en-us/library/ms235627.aspx
These must then be specified for the final compile command: "cl /Y- /EHsc /DUNICODE /D_UNICODE mhook-test.cpp gdi32.lib user32.lib mhook.lib disasm.lib misc.lib disasm_x86.lib cpu.lib"

Related

Visual Studio link error "CloseWindow already defined" only when raylib.lib is linked after user32.lib

I have a compiled static library of raylib : raylib.lib. I compiled this library myself with Librarian > General > Additional Dependencies: winmm.lib
This library has a C function like the following:
void CloseWindow(void);
And I also have my very basic C++ project that uses raylib:
// main.cpp
#include "raylib.h"
int main()
{
InitWindow(100, 100, "");
while (!WindowShouldClose())
{
BeginDrawing();
ClearBackground(RAYWHITE);
EndDrawing();
}
CloseWindow();
return 0;
}
Now, when I compile my project with Linker > Additional Dependencies set to:
raylib.lib; user32.lib; shell32.lib; gdi32.lib
It compiles and links without any warning.
But when I swap the order of raylib.lib and user32.lib:
user32.lib; raylib.lib; shell32.lib; gdi32.lib
Then I get a linker error:
Link:
D:\Visual Studio Community 2019\VC\Tools\MSVC\14.29.30133\bin\HostX86\x64\link.exe
/ERRORREPORT:QUEUE /OUT:"bin\MyProject.exe" /INCREMENTAL:NO /NOLOGO /LIBPATH:bin
user32.lib raylib.lib shell32.lib gdi32.lib winmm.lib /MANIFEST
/MANIFESTUAC:"level='asInvoker' uiAccess='false'" /manifest:embed /DEBUG:FULL
/PDB:"bin\MyProject.pdb" /SUBSYSTEM:CONSOLE /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE
/NXCOMPAT /IMPLIB:"bin\MyProject.lib" /MACHINE:X64 obj\Release\MyProject\main.obj
raylib.lib(core.obj) : error LNK2005: CloseWindow already defined in user32.lib(USER32.dll) [D:\example\MyProject.vcxproj]
bin\MyProject.exe : fatal error LNK1169: one or more multiply defined symbols found [D:\example\MyProject.vcxproj]
So how is this possible that it's already defined? Why does the linking order matter?
UPDATE
When I compiled raylib with Librarian > General > Additional Dependencies: winmm.lib; user32.lib then I get this warning (when compiling the library):
Lib:
D:\Visual Studio Community 2019\VC\Tools\MSVC\14.29.30133\bin\HostX86\x64\Lib.exe /OUT:"bin\raylib.lib" winmm.lib user32.lib /NOLOGO /MACHINE:X64 obj\Release\raylib\core.obj
obj\Release\raylib\models.obj
obj\Release\raylib\raudio.obj
obj\Release\raylib\rglfw.obj
obj\Release\raylib\shapes.obj
obj\Release\raylib\text.obj
obj\Release\raylib\textures.obj
obj\Release\raylib\utils.obj
user32.lib(USER32.dll) : warning LNK4006: __NULL_IMPORT_DESCRIPTOR already defined in winmm.lib(WINMM.dll); second definition ignored [D:\example\raylib.vcxproj]
raudio.obj : warning LNK4006: PlaySound already defined in winmm.lib(WINMM.dll); second definition ignored [D:\example\raylib.vcxproj]
core.obj : warning LNK4006: CloseWindow already defined in user32.lib(USER32.dll); second definition ignored [D:\example\raylib.vcxproj]
core.obj : warning LNK4006: ShowCursor already defined in user32.lib(USER32.dll); second definition ignored [D:\example\raylib.vcxproj]
Having raylib compiled this way MyProject does not need to link with user32.lib and it works.
What is the best way to use raylib in this situation? Should I always compile raylib with it's dependencies (user32.lib etc.) and get those warnings or maybe I should link with them later when MyProject is compiled (then I need to make sure that raylib is linked before it's dependencies)?

pragma comment(lib) not working

Given this library:
lib1.h:
#pragma once
#include <windows.h>
void foo();
lib1.cpp
#include "lib1.h"
void foo() {
MessageBox(NULL, "XXX", "YYY1", MB_OK);
}
Created in the command line with the next commands:
cl /c lib1.cpp
lib lib1.obj
And then this little test:
#pragma comment(lib, "lib1")
#include "lib1.h"
void start() {
foo();
}
I've tried to run it on a windows vs2015 project setting:
/NODEFAULTLIB
entry:start
optimization disabled (/Od)
(security check disabled) /GS-
But I'm facing a linker error such as:
main.obj : error LNK2019: unresolved external symbol "void __cdecl foo(void)" (?foo##YAXXZ) referenced in function "void __cdecl start(void)" (?start##YAXXZ)
I've tried changing the pragma comment to #pragma comment(lib, "lib1.lib"), #pragma comment(lib, ".\\lib1.lib"), #pragma comment(lib, "./lib1.lib") and none of them worked.
I've also tried to include in the linker additional paths the path of lib1.lib and then using either #pragma comment(lib, "lib1.lib") or ``#pragma comment(lib, "lib1.lib")`, no luck.
In fact, the funny thing is, when turning on the /VERBOSE in the linker I don't see any linker's attempt to use the #pragma directive. Of course, If i added lib1.cpp or lib1.lib to the project it'd work but I'm trying to figure out how to use the pragma directive... So, anyone could explain what's going on here and how to solve this issue?
Don't use /NODEFAULTLIB, it basically instructs the linker to ignore the lib #pragma. Explanation from here for instance:
When you use #pragma comment(linker) or #pragma comment(lib) you get a
special entry in the object file (it's a special COFF section usually
named ".drectve" with the directive bit set). Once the linker sees
this entry it treats it as if the switch was given on the linker
command line.
So:
t.cpp:
#pragma comment(lib,"advapi32.lib")
...
cl t.cpp
is equivalent to
t.cpp:
...
cl t.cpp /link /DEFAULTLIB:advapi32.lib
and when you add /NODEFAULTLIB to that last comment it will ignore whatever is specified as /DEFAULTLIB

unresolved external symbol, but dumpbin says it's ok

I downloaded Crypto++ 5.62 and built it with default project settings. In my project I set up the path to cryptopp.lib and defined its name in "Additional Dependencies". Both Crypto++ and my project - VS 2008.
During building of my project I get:
main.obj : error LNK2001: unresolved external symbol
"class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const CryptoPP::DEFAULT_CHANNEL" (?DEFAULT_CHANNEL#CryptoPP##3V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##B)
main.obj : error LNK2001: unresolved external symbol
"bool (__cdecl* CryptoPP::g_pAssignIntToInteger)(class type_info const &,void *,void const *)" (?g_pAssignIntToInteger#CryptoPP##3P6A_NABVtype_info##PAXPBX#ZA)
dumpbin /all cryptopp.lib shows me in the public symbols section
19471C _imp_?DEFAULT_CHANNEL#CryptoPP##3V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##B
1D6F30 __imp_?g_pAssignIntToInteger#CryptoPP##3P6A_NABVtype_info##PAXPBX#ZA
What's wrong then? Why the linker can't find the symbols?
upd:
linker command line from my project settings
/OUT:"C:\Projects\crypto_hash\Debug\crypto_hash.exe" /NOLOGO /LIBPATH:"e:\libs\cryptopp\cryptopp562\cryptopp\Win32\DLL_Output\Debug" /MANIFEST /MANIFESTFILE:"Debug\crypto_hash.exe.intermediate.manifest" /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"C:\Projects\crypto_hash\Debug\crypto_hash.pdb" /DYNAMICBASE /NXCOMPAT /MACHINE:X86 /ERRORREPORT:PROMPT cryptopp.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
Try adding CRYPTOPP_IMPORTS to your project defines.
From config.h:
#ifdef CRYPTOPP_EXPORTS
# define CRYPTOPP_IS_DLL
# define CRYPTOPP_DLL __declspec(dllexport)
#elif defined(CRYPTOPP_IMPORTS)
# define CRYPTOPP_IS_DLL
# define CRYPTOPP_DLL __declspec(dllimport)
#else
# define CRYPTOPP_DLL
#endif
Or include Crypto++'s dll.h. It sets CRYPTOPP_IMPORTS:
#if !defined(CRYPTOPP_IMPORTS) && !defined(CRYPTOPP_EXPORTS) && !defined(CRYPTOPP_DEFAULT_NO_DLL)
# ifdef CRYPTOPP_CONFIG_H
# error To use the DLL version of Crypto++, this file must be included before any other Crypto++ header files.
# endif
# define CRYPTOPP_IMPORTS
#endif
If that does not work...
g_pAssignIntToInteger is from algparams.cpp:
$ grep -R g_pAssignIntToInteger *
algparam.cpp:PAssignIntToInteger g_pAssignIntToInteger = NULL;
algparam.h:CRYPTOPP_DLL extern PAssignIntToInteger g_pAssignIntToInteger;
algparam.h: if (!(g_pAssignIntToInteger != NULL && typeid(T) == typeid(int) && g_pAssignIntToInteger(valueType, pValue, &m_value)))
integer.cpp: if (!g_pAssignIntToInteger)
integer.cpp: g_pAssignIntToInteger = AssignIntToInteger;
Looking at the declaration in algparam.h:
// to allow the linker to discard Integer code if not needed.
typedef bool (CRYPTOPP_API * PAssignIntToInteger)(const std::type_info &valueType, void *pInteger, const void *pInt);
CRYPTOPP_DLL extern PAssignIntToInteger g_pAssignIntToInteger;
And the implementation in algparam.cpp:
#ifndef CRYPTOPP_IMPORTS
...
NAMESPACE_BEGIN(CryptoPP)
PAssignIntToInteger g_pAssignIntToInteger = NULL;
...
So you might need to change the implementation to ensure the code uses g_pAssignIntToInteger (to keep it from being discarded). Unfortunately, nothing comes to mind at the moment.
DEFAULT_CHANNEL is declared in cryptlib.h and has storage allocated in cryptolib.cpp:
$ grep -R DEFAULT_CHANNEL *
...
cryptlib.cpp:const std::string DEFAULT_CHANNEL;
...
cryptlib.h:extern CRYPTOPP_DLL const std::string DEFAULT_CHANNEL;
...
This might be a different problem since I'm not used to seeing issues with DEFAULT_CHANNEL. See how CRYPTOPP_IMPORTS works for you, and then ask a different question since this might be a different problem.

Which compilation options should I use to link with Boost using cl.exe?

I have a program which I would like compile using cl.exe on the command-line. This program depends on some boost libraries which I fail to link to.
The error I'm getting is:
cl /Fosamples\proxy\proxy.obj /c samples\proxy\proxy.cpp /TP /O2 /EHsc
/DBOOST_ALL_NO_LIB /DBOOST_THREAD_USE_LIB /DBOOST_SYSTEM_USE_LIB
/DBOOST_USE_WINDOWS_H /DTAP_ID=\"tap0901\" /D_WIN32_WINNT=0x0501 /MD /nologo
/Isamples\proxy /Iinclude proxy.cpp
link /nologo /MD /OUT:samples\proxy\proxy.exe /LIBPATH:samples\proxy
/LIBPATH:lib asiotap.lib libboost_system-vc100-mt-1_47.lib
libboost_thread-vc100-mt-1_47.lib ws2_32.lib gdi32.lib iphlpapi.lib
advapi32.lib samples\proxy\proxy.obj
LINK : warning LNK4044: unrecognized option '/MD'; ignored
asiotap.lib(bootp_builder.obj) : error LNK2001: unresolved external
symbol "class boost::system::error_category const & __cdecl
boost::system::system_category(void)"
(?system_category#system#boost##YAAEBVerror_category#12#XZ)
I compiled Boost, using the following command-line, from the x64 MSVC command prompt:
.\b2.exe install toolset=msvc --prefix=C:\Boost-VC-x64
If I look inside libboost_system-vc100-mt-1_47.lib I can see that:
?system_category#system#boost##YAABVerror_category#12#XZ
Is exported. But If you look closely it differs a bit from the one in my compilation errors:
?system_category#system#boost##YAAEBVerror_category#12#XZ // The symbol I miss
?system_category#system#boost##YAABVerror_category#12#XZ // The exported symbol
I guess I should either change Boost or my compilation options but fail to figure what to change exactly. Any clue ?
Thank you very much.
After some investigations, I realized that I compiled Boost for a x86 platform where I was linking with a x64 binary.
I thought that compiling Boost inside a Visual Studio x64 command prompt was enough but you actually have to specify:
.\b2.exe install toolset=msvc address-model=64 --prefix=C:\Boost-VC-x64
To make it work.

How to link against a static library which uses static libraries itself using scons and Visual C++?

My SConstruct file looks something like this:
jnglLibs = Split("freetype png ogg vorbisfile") # left out a few
env.Library(target="jngl", source=source_files, LIBS=jnglLibs)
env.Program("test.cpp", LIBS=Split("jngl") + jnglLibs)
The static library links fine but the program fails with unresolved external symbols from the libraries in jnglLibs.
lib /nologo /OUT:jngl.lib finally.obj freetype.obj main.obj opengl.obj sprite.ob
j tess.obj texture.obj window.obj windowptr.obj callbacks.obj ConvertUTF.obj aud
io.obj win32\message.obj win32\time.obj win32\window.obj
cl /Fotest.obj /c test.cpp /TP /nologo /EHsc /MD -O2 -DNDEBUG /I.
test.cpp
link /OUT:test.exe /LIBPATH:. /LIBPATH:lib jngl.lib freetype.lib png.lib opengl3
2.lib glu32.lib user32.lib shell32.lib gdi32.lib z.lib jpeg.lib dl.lib openal32.
lib alut.lib ogg.lib vorbisfile.lib test.obj
Microsoft (R) Incremental Linker Version 10.00.30319.01
Copyright (C) Microsoft Corporation. All rights reserved.
jngl.lib(freetype.obj) : error LNK2019: unresolved external symbol FT_Done_FreeT
ype referenced in function "public: __cdecl jngl::Font::~Font(void)" (??1Font#jn
gl##QEAA#XZ)
... and so on
Why doesn't it find the symbol FT_Done_FreeType which is in freetype.lib? It works perfectly with GCC.
There are a lot of quirks with static linking on Windows.. I've had one or two similar problems to this but mostly my problem was once the 'static' libs were compiled they still depended on the .dll's being there. Anyway, I've been feeling your pain for a while now but got through it for my purposes... here's one page that really helped me.
http://xmlsoft.org/XSLT/tutorial2/libxslt_pipes.html#windows-build
It doesn't have to do with those particular libraries you listed but it might give you some clues. One thing is figuring out which C-runtime library each of those .libs (or '_a.libs,' which you might want to look into) were compiled against and make sure they are all the same when you statically link. So since you're using /MD, make sure all those libs were also compiled with /MD and not /MT. That COULD be a reason it isn't finding that freetype symbol, but it's just one guess. Good luck!