I'm trying to build a sample project for windows mobile (pre-windows phone 7). I've created a Win32 device project in VS 2008 and i have the windows mobile SDKs installed. I replace the main function stub with the following sample code, but it fails to build with two linker errors. I'm guessing this is some sort of configuration error or build settings error but i don't know where to look. I've built very few C++ projects and i'm not familiar with the different options. Can anyone suggest anything that might help?
Taken from: Auto-launching CF apps with the HKLM\Init Registry Key
extern "C" DWORD WaitForAPIReady(DWORD, DWORD);
extern "C" BOOL IsAPIReady(DWORD hAPI);
int _tmain(int argc, _TCHAR* argv[])
{
// quick sanity check - HKLM\Init will send in our order number
if(argc == 0) return 0;
BOOL success = FALSE;
// wait for window manager - that should be enough for us
#if _WIN32_WCE > 0x500
success = (WaitForAPIReady(SH_WMGR, 5000) == WAIT_OBJECT_0);
#else
int i = 0;
while((! IsAPIReady(SH_WMGR)) && (i++ < 50))
{
Sleep(100);
}
success = (i < 50);
#endif
if(success)
{
int launchCode = _ttoi(argv[1]);
SignalStarted(launchCode);
}
else
{
RETAILMSG(TRUE, (_T("CFInitGate timed out - SH_WMGR was not ready after 5 seconds\r\n")));
}
return 0;
}
And the linker errors i see:
Error 1 error LNK2019: unresolved external symbol WaitForAPIReady referenced in function wmain LaunchGate.obj LaunchGate
Error 2 fatal error LNK1120: 1 unresolved externals Windows Mobile 6 Standard SDK LaunchGate
According to the WaitForAPIReady documentation i need to include kfuncs.h and according to the IsAPIReady documentation i should use windev.h. When i #include "kfuncs.h" i get no syntax errors, but the linker still complains. When i #include "windev.h" i get file not found.
Any ideas?
thanks,
brian
Don't declare them as extern "C". Declare thus:
extern WINAPI DWORD WaitForAPIReady(DWORD, DWORD);
extern WINAPI BOOL IsAPIReady(DWORD hAPI);
It's a different calling convention - stdcall vs. cdecl, thus different name mangling rules.
Do an dumpbin /EXPORTS of the dll and see how it is mangled. if you see an bunch of odd symbols, it's an c++ created dll and you should declare them as seva answered, else you should declare them as you do.
Why are you declaring the functions yourself instead of #include'ing kfuncs.h?
Related
I am trying to get the Windows System Tray geometry:
RECT rect;//Rect System Tray
HWND taskBar = FindWindow(L"Shell_traywnd", NULL);//Error
if(taskBar && GetWindowRect(taskBar, &rect))//Error
//...
But the compiler MSVC 2013 64 bit extradite errors:
Window.obj:-1: error: LNK2019: a reference to the unresolved external symbol __imp_GetWindowRect in the function "private: class QRect __cdecl Window::availableGeometry(bool const &)" (?availableGeometry#Window##AEAA?AVQRect##AEB_N#Z)
Window.obj:-1: error: LNK2019: a reference to the unresolved external symbol __imp_FindWindowW in the function "private: class QRect __cdecl Window::availableGeometry(bool const &)" (?availableGeometry#Window##AEAA?AVQRect##AEB_N#Z)
If I use MinGw 32 bit, compiler does not extradite errors.
Please tell me what is the problem. Thanks in advance.
I use Qt 5,5 on Windows 8.1.
Basically, MingW doesn't have the symbols loaded for those libraries.
MSVC might have them already... but even MSVC doesn't include all the libraries at times, especially uncommon ones. But you can get around it by explicitly loading the libraries yourself. I've done this a number of times using QLibrary and the MSDN documentation.
You need to copy the header file information for the functions you are using, and load the symbol and typecast it as the function you are using. I'll post a code sample shortly.
So for the first one: GetWindowRect, you can find it under:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms633519(v=vs.85).aspx
BOOL WINAPI GetWindowRect(
_In_ HWND hWnd,
_Out_ LPRECT lpRect
);
Note that on the bottom of the page it mentions which header file it is in an which dll/lib it is a part of. Also note which versions of windows it will apply for. You can query the version of windows and switch how you behave for specific versions of windows in some cases.
To add this with an explicit declaration, here is a nice little wrapper class:
winlibs.h
#ifndef WINLIBS_H
#define WINLIBS_H
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <QLibrary>
typedef HWND (WINAPI * GetShellWindow_Ptr)(void);
typedef BOOL (WINAPI * GetWindowRect_Ptr)(
/*_In_*/ HWND hWnd,
/*_Out_*/ LPRECT lpRect
);
class WinLibs
{
public:
WinLibs();
static GetShellWindow_Ptr GetShellWindow;
static GetWindowRect_Ptr GetWindowRect;
static void cleanUp();
static QLibrary * myLib;
};
#endif // WINLIBS_H
winlibs.cpp
#include "winlibs.h"
#include <QDebug>
GetShellWindow_Ptr WinLibs::GetShellWindow = 0;
GetWindowRect_Ptr WinLibs::GetWindowRect = 0;
QLibrary * WinLibs::myLib = 0;
bool WinLibs::hasInitialized = false;
WinLibs::WinLibs()
{
if(hasInitialized)
return;
myLib = new QLibrary("User32.dll");
GetShellWindow = (GetShellWindow_Ptr) myLib->resolve("GetShellWindow");
GetWindowRect = (GetWindowRect_Ptr) myLib->resolve("GetWindowRect");
if(GetShellWindow == 0 || GetWindowRect == 0)
qCritical() << "Failed to load User32.dll properly!";
hasInitialized = true;
}
void WinLibs::cleanUp()
{
hasInitialized = false;
myLib->unload();
delete myLib;
myLib = 0;
}
example usage:
WinLibs w;
if(w.GetShellWindow)
{
// use w.GetShellWindow here
}
if(w.GetWindowRect)
{
// use w.GetWindowRect here
RECT rect;//Rect System Tray
HWND taskBar = FindWindow(L"Shell_traywnd", NULL);
if(taskBar && w.GetWindowRect(taskBar, &rect))
{
// .. more code
}
}
Be sure to handle errors and return values properly from Windows functions when trying to debug them, too. And note that you will get errors if you are building a 64 bit program and you try to access a 32 bit dll and vice versa. Usually you don't have to worry about this for windows libraries because the system will add the correct one to the path when they are getting resolved.
Hope that helps.
I am trying to port a 32-bit dll (and application) to 64-bit and I have managed to build it without errors. When trying to load it with my 64-bit application I noticed that the exported function names differ. This is how I export the functions:
#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllexport) long __stdcall Connect(char * name, long size);
#ifdef __cplusplus
}
#endif
In Dependency Walker the exported functions have the following format:
32-bit: _Connect#8
64-bit: Connect
In the application using the dll I explicitly load the dll (LoadLibrary is successful) but GetProcAddress fails for 64-bit because it cannot find a function with the provided name.
In our application I keep the function names as follows:
#define ConnectName "_Connect#8"
...
GetProcAddress(Dll, ConnectName);
So I was wondering if it is possible to export the same function names for both 32-bit and 64-bit dlls or is this a bad idea? Or do I need to do the following in my applications:
#if _WIN64
#define ConnectName "Connect"
#else
#define ConnectName "_Connect#8"
#endif
I appreciate any help.
An option you have to export function names without any decoration (independently from the particular calling convention you used in x86, __stdcall, __cdecl, or other) and with the same undecorated name in both x86 and x64 builds, is to export your DLL functions using DEF files.
E.g. you could add a .DEF file like this to your project:
LIBRARY YOURDLL
EXPORTS
Connect #1
AnotherFunction #2
... etc. ...
Repro Follows
Create an empty solution in Visual Studio (I used VS2013), and inside that create an empty Win32 console project (the test client) and an empty Win32 DLL project (the test DLL).
Add this NativeDll.def .DEF file in the DLL project:
LIBRARY NATIVEDLL
EXPORTS
SayHello #1
Add this NativeDll.cpp C++ source code in the DLL project:
///////////////////////////////////////////////////////////////////////////////
//
// NativeDll.cpp -- DLL Implementation Code
//
///////////////////////////////////////////////////////////////////////////////
#include <Windows.h>
#include <atldef.h>
#include <atlstr.h>
//
// Test function exported from the DLL
//
extern "C" HRESULT WINAPI SayHello(PCWSTR name)
{
//
// Check for null input string pointer
//
if (name == nullptr)
{
return E_POINTER;
}
try
{
//
// Build a greeting message and show it in a message box
//
CString message;
message.Format(L"Hello %s from the native DLL!", name);
MessageBox(nullptr, message, L"Native DLL Test", MB_OK);
// All right
return S_OK;
}
//
// Catch exceptions and convert them to HRESULT codes
//
catch (const CAtlException& ex)
{
return static_cast<HRESULT>(ex);
}
catch (...)
{
return E_FAIL;
}
}
Add this NativeClient.cpp C++ source code in the client test project:
///////////////////////////////////////////////////////////////////////////////
//
// NativeClient.cpp -- EXE Test Client Code
//
///////////////////////////////////////////////////////////////////////////////
#include <Windows.h>
//
// Prototype of the function to be loaded from the DLL
//
typedef HRESULT (WINAPI *SayHelloFuncPtr)(PCWSTR /* name */);
//
// Simple RAII wrapper on LoadLibrary()/FreeLibrary().
//
class ScopedDll
{
public:
//
// Load the DLL
//
ScopedDll(PCWSTR dllFilename) throw()
: m_hDll(LoadLibrary(dllFilename))
{
}
//
// Unload the DLL
//
~ScopedDll() throw()
{
if (m_hDll)
{
FreeLibrary(m_hDll);
}
}
//
// Was the DLL loaded successfully?
//
explicit operator bool() const throw()
{
return (m_hDll != nullptr);
}
//
// Get the DLL handle
//
HINSTANCE Get() const throw()
{
return m_hDll;
}
//
// *** IMPLEMENTATION ***
//
private:
//
// The wrapped raw DLL handle
//
HINSTANCE m_hDll;
//
// Ban copy
//
private:
ScopedDll(const ScopedDll&) = delete;
ScopedDll& operator=(const ScopedDll&) = delete;
};
//
// Display an error message box
//
inline void ErrorMessage(PCWSTR errorMessage) throw()
{
MessageBox(nullptr, errorMessage, L"*** ERROR ***", MB_OK | MB_ICONERROR);
}
//
// Test code calling the DLL function via LoadLibrary()/GetProcAddress()
//
int main()
{
//
// Return codes
//
static const int kExitOk = 0;
static const int kExitError = 1;
//
// Load the DLL with LoadLibrary().
//
// NOTE: FreeLibrary() automatically called thanks to RAII!
//
ScopedDll dll(L"NativeDll.dll");
if (!dll)
{
ErrorMessage(L"Can't load the DLL.");
return kExitError;
}
//
// Use GetProcAddress() to access the DLL test function.
// Note the *undecorated* "SayHello" function name!!
//
SayHelloFuncPtr pSayHello
= reinterpret_cast<SayHelloFuncPtr>(GetProcAddress(dll.Get(),
"SayHello"));
if (pSayHello == nullptr)
{
ErrorMessage(L"GetProcAddress() failed.");
return kExitError;
}
//
// Call the DLL test function
//
HRESULT hr = pSayHello(L"Connie");
if (FAILED(hr))
{
ErrorMessage(L"DLL function call returned failure HRESULT.");
return kExitError;
}
//
// All right
//
return kExitOk;
}
Build the whole solution (both the .EXE and the .DLL) and run the native .EXE client.
This is what I get on my computer:
It works without modifications and with the undecorated function name (just SayHello) on both x86 and x64 builds.
__stdcall is not supported (and is ignored) on x64. Quoting MSDN:
On ARM and x64 processors, __stdcall is accepted and ignored by the compiler; on ARM and x64 architectures, by convention, arguments are passed in registers when possible, and subsequent arguments are passed on the stack.
The calling convention on x64 is pretty much __fastcall.
Since the calling conventions and name decoration rules on x86 and x64 differ, you have to abstract this somehow. So your idea with #if _WIN64 goes in the right direction.
You can examine x86 calling conventions and your needs and perhaps devise a macro which could automate the name selection process.
As you can tell, in 64-bit Windows names are not decorated.
In 32-bit __cdecl and __stdcall symbols, the symbol name is prepended by an underscore. The trailing '#8' in the exported name for the 32-bit version of your example function is the number of bytes in the parameter list. It is there because you specified __stdcall. If you use the __cdecl calling convention (the default for C/C++ code), you won't get that. If you use __cdecl, it makes it much easier to wrap GetProcAddress() with something like:
#if _WIN64
#define DecorateSymbolName(s) s
#else
#define DecorateSymbolName(s) "_" ## s
#endif
then just call with
pfnConnect = GetProcAddress(hDLL, DecorateSymbolName("Connect"));
pfnOtherFunc = GetProcAddress(hDLL, DecorateSymbolName("OtherFunc"));
or something similar (error checking omitted in example).
To do this, remember to declare your exported functions as:
__declspec(dllexport) long __cdecl Connect(char * name, long size);
__declspec(dllexport) long __cdecl OtherFunc(int someValue);
In addition to being easier to maintain, if during development the signature of an exported function changes, you don't have to screw around with your #define wrappers.
Downside: if during development the number of bytes in a given function's parameter list changes, it will not be caught by the application importing the function because the changing the signature will not change the name. Personally, I don't think this is an issue because the 64-bit build would blow up under the same circumstances anyway as the names are not decorated. You just have to make sure your application is using the right version of the DLL.
If the user of the DLL is using C++, you can wrap things in a better way using C++ capabilities (wrap the entire explicitly-loaded library in a wrapper class, e.g.):
class MyDLLWrapper {
public:
MyDLLWrapper(const std::string& moduleName); // load library here
~MyDLLWrapper(); // free library here
FARPROC WINAPI getProcAddress(const std::string& symbolName) const {
return ::GetProcAddress(m_hModule, decorateSymbolName(symbolName));
}
// etc., etc.
private:
HMODULE m_hModule;
// etc.
// ...
};
There's actually a lot more you can do with a wrapper class like this, it's just an example.
On edit: since OP mentioned using PInvoke in the comments - if anyone decides to do this, do not forget to add CallingConvention = CallingConvention.Cdecl in the [DllImport] declaration when using PInvoke. __cdecl might be the default for unmanaged C/C++, but is not the default for managed code.
For Win32 build:
If you use __stdcall, you will get something like this (dumped with dumpbin /exports):
__declspec(dllexport) int __stdcall
->
ordinal hint RVA name
1 0 00001240 _F1#0 = _F1#0
2 1 0000124D _F2#0 = _F2#0
And you have to use GetProcAddress("_F1#0") to locate the function pointer.
If you use __cdecl, you will get something like this:
__declspec(dllexport) int __cdecl
->
ordinal hint RVA name
1 0 00001240 F1 = _F1
2 1 0000124D F2 = _F2
And you can use GetProcAddress("F1") to locate the function pointer.
BTW, if you add a XXX.def file to your Visual Studio project. One more link option will be silently added to your linker command line /DEF:"XXX.def" in the All Options window. And if you change your .def file name later for whatever reason, this link option doesn't change accordingly. You need to manually change the def file name in the project properties window.
I have tried this code in a totally separate project, and it works fine (the only difference being that the project that is not working is being exported as a DLL). Here is the code:
RTATMATHLIB.CPP
#include "stdafx.h"
#include "RTATMATHLIB.h"
#include <math.h>
#include <vector>
#include <algorithm>
#include <stdexcept>
using namespace std;
double someFunc(double** Y, int length)
{
vector<double> myVector;
for(int i = 0; i < length; i++)
{
double value = (*Y)[i];
vector<double>::iterator it = find(myVector.begin(), myVector.end(), value);
if(it != myVector.end())
{
continue;
}
else
{
myVector.push_back(value);
}
}
return 0;
}
RTATMATHLIB.H
__declspec(dllexport) double someFunc(double** Y, int length);
ERRORS
Error 1 error LNK2019: unresolved external symbol __imp___CrtDbgReportW referenced in function "public: __thiscall std::_Vector_const_iterator<double,class std::allocator<double> >::_Vector_const_iterator<double,class std::allocator<double> >(double *,class std::_Container_base_secure const *)" (??0?$_Vector_const_iterator#NV?$allocator#N#std###std##QAE#PANPBV_Container_base_secure#1##Z) RTATMATHLIB.obj RTATMATHLIB
Error 2 fatal error LNK1120: 1 unresolved externals
And that's it. I am not sure why it works in the other project and not this one...
I found another forum post, where somebody seems to have reported the same exact problem that you are having. Please check to see if you have
_DEBUG
defined either in your project settings (under C/C++ -- Preprocessor) or somewhere in your code (or include files).
It looks as if std::vector thinks you are building a debug build, when you are in fact creating a release build.
I hope this helps.
The problem in my case was a Debug configuration with Runtime Library set to Multi-threaded DLL. The fix was to change it to Multi-threaded Debug DLL. The error is gone. Removing _DEBUG macro was also a kind of workaround, by I guess it's not a good idea because you end up with debug build linked to non-debug standard library.
The problem was I had _DEBUG defined in C/C++->Preprocessor. Changing it to NDEBUG solved the problem.
Worked for me with :
The problem in my case was a Debug configuration with Runtime Library set to Multi-threaded DLL. The fix was to change it to Multi-threaded Debug DLL
I have a DLL with the /clr option ON. I have the following declaration in my DLL:
int __declspec(dllexport) __cdecl test();
Also, I have a console with /clr option ON. And have the following declaration on my main.cpp file:
int __declspec(dllimport) __cdecl test();
I added the Reference to the DLL project on the property settings of my console application. But I still get unresolved externals from the compiler about the test function.
I managed to compile by manually adding a reference to the lib file generated by the compiler. But then I can't hit breakpoints inside the DLL functions (it says the source code is different from the original version or the symbols have not been loaded...)
Can someone help me?
If your DLL doesn't use any managed functionality, simply remove the /clr option from that project and recompile. If you still get the errors, it's probably related to the references in the console application.
If the DLL use managed functionality, what you need is instead like so:
DLL:
#include "stdafx.h"
namespace Test1
{
public ref class Test2
{
public:
static int test()
{
return 1;
}
};
}
Console app:
#include <iostream>
int main(int argc, char* argv[])
{
int i = Test1::Test2::test();
std::cout << i << std::endl;
return 0;
}
I'm trying to build a console application without using the CRT, or any other imports than kernel32.lib in any case. I get my code to compile, but can't wrap the linker around a few problems:
unresolved external symbol #__security_check_cookie#4
unresolved external symbol "int __cdecl FreeLibrary(void *)" (?FreeLibrary##YAHPAX#Z)
unresolved external symbol "void * __cdecl LoadLibraryW(wchar_t *)" (?LoadLibraryW##YAPAXPA_W#Z)
unresolved external symbol "int (__cdecl*__cdecl GetProcAddress(void *,char *))(void)" (?GetProcAddress##YAP6AHXZPAXPAD#Z)
unresolved external symbol _wmainCRTStartup
FreeLibrary, LoadLibraryW and GetProcAddress I've brought in to program explicitly, not using windows.h:
#pragma comment(lib, "kernel32.lib")
typedef int(*FARPROC)();
void* LoadLibraryW( wchar_t* lpLibFileName );
FARPROC GetProcAddress( void* hModule, char* lpProcName );
int FreeLibrary( void* hLibModule );
I suppose something is wrong with my prototypes.
However, the bigger problem are __security_check_cookie and _wmainCRTStartup, which obviously have something to do with the CRT.
So I'm wondering how I'd go about overriding the default int wmain(int argc, wchar_t* argv[]) for entrypoint, and how to get rid of whatever the security cookie is.
_wmainCRTStartup is the function that calls wmain()
IIRC it should be available in some .o file that you can link with, look in your lib directory.
Maybe this is useful reading too: Reduce EXE and DLL Size with LIBCTINY.LIB (and Matt Pietrek rocks :-)
Well, answering myself here to sum up, in case someone else finds this page looking for info.
As MSalters advised, the security cookie code can be stolen from the CRT source, but doing that I found that the /GS- compiler flag can be used to avoid the security stuff altogether.
As SoapBox said, the API functions need to be __stdcall, as well as the entry point does.
I fixed the entry point issue with linker command line flag /entry:wmain.
And finally, as Tomek pointed out, the API functions gotta be in extern C!
So:
#pragma comment(lib, "kernel32.lib")
typedef int(*FARPROC)();
extern "C" {
void* __stdcall LoadLibraryW( wchar_t* lpLibFileName );
FARPROC __stdcall GetProcAddress( void* hModule, char* lpProcName );
int __stdcall FreeLibrary( void* hLibModule );
typedef int (__stdcall *f_MessageBoxW_t)( unsigned long hWnd, wchar_t* lpText, wchar_t* lpCaption, unsigned long uType);
f_MessageBoxW_t fnMsg;
void* hUser;
};
int __stdcall wmain(int argc, wchar_t* argv[])
{
hUser = LoadLibraryW( L"user32.dll" );
fnMsg = (f_MessageBoxW_t)GetProcAddress( hUser, "MessageBoxW" );
fnMsg( 0, L"foo", L"bar", 0 );
FreeLibrary( hUser );
return 0;
}
More correct entry point declaration will be:
int __stdcall wmain(PVOID ThreadParam)
Without CRT entry point called directly by BaseThreadInitThunk. Its passes pointer to something, but not argc+argv.
You can look in Windows.h to see the prototypes you need for your kernel32 imports. In general, windows functions are defined WINAPI which is actually __stdcall and not __cdecl. That will fix that problem at least.
As for your other problem, you need to explore the linker commandline arguments and see if there is a way to get it to not look for things from CRT. I don't know if there is a way to do that or not. But you're going to have to find a way or define those functions your self (which you probably don't want to do).
I'd recommend just using a different compiler/linker.
You need to declare windows.h functions as extern "C".
The proper entry point is main(), not wmain() (since you're compiling a console app).
The security cookie code can be nicked from the CRT source code; no need to link it in.