Having searched for days now i decided to post a question here and hope that somebody has the ultimate idea or advice.
I wrote a WINAPI wrapping mechanism consisting of a WindowManager and a WINAPIWindow class. The latter uses the famous "First WINAPI Window" functionality known from most tutorials in a more structured manner, mainly HWND and HINSTANCE.
Remarks: the macro "_ WINDOWS _" (without spaces but this tool makes it bold otherwise ) is a macro defined in one of my headers to determine, wether the compilation environment supports WIN32 and the WINAPI.
#if defined(_ _WINDOWS_ _)
LRESULT CALLBACK gDefaultWndProcFwd(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
#pragma region WINAPIWindow
class WINAPIWindow : public WindowBase
{
friend class WindowManager;
public:
virtual ~WINAPIWindow();
RESULT show();
inline HWND handle() const;
LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
private:
WINAPIWindow(__in const HINSTANCE hInstance, __in const Rect& bounds, __in const String& title = "", __in const int flags = WDF_DEFAULT);
HRESULT createWindowClass(__in const HINSTANCE hInstance, __in const String& clsName);
tInt16 _wndState;
HWND _hWnd;
};
typedef WINAPIWindow Window;
#pragma endregion
#elif
The mechanism is located in a static library called "ShirabePlatformFeatureLayer.lib".
This static library uses classes and code from another custom static lib called "ShiCore.lib" which does not use any platform dependent code.
My actual application project (x64!) now imports both as additional depenencies using the WindowManager.
Although both library projects compile fine and without errors, compiling the Application Project leads to the following error messages.
Error 43 error LNK2019: unresolved external symbol "public: struct HWND__ * __cdecl ShirabePlatformFeatureLayer::WINAPIWindow::handle(void)const " (?handle#WINAPIWindow#ShirabePlatformFeatureLayer##QEBAPEAUHWND__##XZ) referenced in function wWinMain C:\Users\Dev.Dev-PC\Documents\Workspaces\ShirabeEngine\ShirabeDevelopment\Win32TestProject\main.obj Win32TestProject
Error 45 error LNK2019: unresolved external symbol "__int64 __cdecl ShirabePlatformFeatureLayer::gDefaultWndProcFwd(struct HWND__ *,unsigned int,unsigned __int64,__int64)" (?gDefaultWndProcFwd#ShirabePlatformFeatureLayer##YA_JPEAUHWND__##I_K_J#Z) referenced in function "private: long __cdecl ShirabePlatformFeatureLayer::WINAPIWindow::createWindowClass(struct HINSTANCE__ * const,class ShirabeCORE::String const &)" (?createWindowClass#WINAPIWindow#ShirabePlatformFeatureLayer##AEAAJQEAUHINSTANCE__##AEBVString#ShirabeCORE###Z) C:\Users\Dev.Dev-PC\Documents\Workspaces\ShirabeEngine\ShirabeDevelopment\Win32TestProject\ShirabePlatformFeatureLayer.lib(Window.obj) Win32TestProject
Error 44 error LNK2001: unresolved external symbol "public: struct HWND__ * __cdecl ShirabePlatformFeatureLayer::WINAPIWindow::handle(void)const " (?handle#WINAPIWindow#ShirabePlatformFeatureLayer##QEBAPEAUHWND__##XZ) C:\Users\Dev.Dev-PC\Documents\Workspaces\ShirabeEngine\ShirabeDevelopment\Win32TestProject\ShirabePlatformFeatureLayer.lib(WindowManager.obj) Win32TestProject
Error 46 error LNK1120: 2 unresolved externals C:\Users\Dev.Dev-PC\Documents\Workspaces\ShirabeEngine\ShirabeDevelopment\Debug\Win32TestProject.exe Win32TestProject
I checked, whether the methods are declared and defined properly. I also included and imported the libs.
#if defined(_ _WINDOWS_ _)
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "kernel32.lib")
#pragma comment(lib, "gdi32.lib")
#include <Windows.h>
#endif
In addition i registered the 3 libs above as additional dependencies and the lib-directories are $(VC_LibraryPath_x64) and $(WindowsSDK_LibraryPath_x64).
My first thoughts after having analyzed this a bit is, that all methods or functions that use WINAPI classes and structs are not linked into the import library "ShirabePlatformFeatureLayer.lib". Having registered them above 3 libs as additional dependencies with equal library paths as above and the /VERBOSE:LIB shows me that the libraries are appended but not with "x64\gdi32.lib" as the message but "GDI32.DLL". Likewise for the other two.
Doing /VERBOSE:LIB in the application project shows me the actual relative paths to the "~.lib" and not "~.DLL".
What can cause the methods to not being linked/included/important when they use WINAPI functionality?
Is the general build design with so many .libs the problem?
Does anybody else have an idea?
Here the entire affected code ( imho ): http://pastebin.com/f7MaBBwM
If any further information is required, please tell me.
EDIT: I've continued searching and came up with the "project to project" dependencies in the new MSBuild system. Although this appeared to be the same problem, it isn't since obviously the dependency of "ShirabePlatformFeatureLayer.lib" to the import libs kernel32, gdi32 and user32 causes problem, when effectively being consumed by the Win32TestProject using the ShirabePlatformFeatureLayer.lib code.
Unfortunately i wasn't able to solve the problem yet with the various advice given est. 10 different articles on the topic. :/
Edit: Consulting Rodrigo s remarks i was able to get rid of the handle() unresolved symbol. However the second with gDefaultWndProcFwd seems to be a logic/design error.
Once i managed to get 10 Reputation I'll attach an image of the relation between WindowManager, WINAPIWindow and gDefaultWndProcFwd!
That said here a textual description:
1) Creating the window implies creating the WindowClassEx structure that refers to gDefaultWndProcFwd using a forward declaration in Window.h.
2) When the window is created and shown the method should be called, which consults WIndowManager::get(key : HWND) : WindowBase*;
3) If found, the function invokes wndProc on the window pointer and leaves handling to the specified implementation of the wndproc.
The gDefaultWndProcFwd is declared and defined in WindowManager.h/.cpp.
The design flaw becomes more and more obvious, as I'm thinking about a solution!
See the pastebin link for the actual code!
Thank you very much for your help in advance.
Sincerely, Marc
You have 2 unresolved external symbols:
HWND ShirabePlatformFeatureLayer::WINAPIWindow::handle(void) const
LRESULT ShirabePlatformFeatureLayer::gDefaultWndProcFwd(HWND,UINT,WPARAM,LPARAM)
The first one is probably due to handle() being inline. You probably defined it in the CPP file (or you forgot it?) , but since it is inline, the definition is not exported. Instead it is expected to be available to every compilation unit that needs it. In other words, inline functions should be defined in the same header file as the declaration.
The second one is trickier without seeing all your code. But I'd bet that you simply forgot to write the defintion of gDefaultWndProcFwd(). Or maybe you wrote it in a different namespace, or with different parameters.
Note that static libraries are not linked, so unresolved symbol errors such as yours, will never happen when building the library, even when the defect is in the library itself. Linker errors will always happen when linking the final executable.
UPDATE: Ok, I said it was tricky... Re-reading your code I noticed that the offending function is declared twice, and defined once. That itself is not a problem, but look at the two declarations together:
LRESULT CALLBACK gDefaultWndProcFwd(HWND hWnd, UINT msg, LPARAM lParam, WPARAM wParam);
LRESULT CALLBACK gDefaultWndProcFwd(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
And the definition is:
LRESULT CALLBACK gDefaultWndProcFwd(HWND hWnd, UINT msg, LPARAM lParam, WPARAM wParam)
Do you see the difference? WPARAM and LPARAM are swapped!!!
Related
I was trying to implement mouse and keyboard support in my game engine using DirectXTK. It was quite simple for keyboard, but I have got a problem with implementing proper mouse support. I was following THIS for implementing mouse into my engine. This article from Microsoft wiki says that I have call SetWindow, before I will be able to change mouse mode from absolute to relative. It sounds easy, but when I try to do this like this:
auto mouse = std::make_unique<DirectX::Mouse>();
mouse->SetWindow(hwnd);
mouse->SetMode(DirectX::Mouse::Mode::MODE_RELATIVE);
I get an error:
E0135 class "DirectX::Mouse" has no member "SetWindow"
It looks like this method doesn't exist in Mouse class. It is weird, becuse if I remove this line with setting window it will compile, but I will fail in runtime due to this assertion in Mouse class:
assert(mWindow != nullptr);
So it is required to set window, but how can I do this, when this function doesn't exist? What's worse the article from wiki is not old, it's from 18 Apr 2019. Have anyone encountered this problem? How can I fix this?
A quick look at the header file and you'll see this
#if (!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) && defined(WM_USER)
void __cdecl SetWindow(HWND window);
static void __cdecl ProcessMessage(UINT message, WPARAM wParam, LPARAM lParam);
#endif
So it seems likely that you don't have WINAPI_FAMILY and/or WM_USER defined in a suitable way to enable the declaration of that method in the header file.
I believe WM_USER will be defined by #include <windows.h> so maybe all you need to do is place that include before #include <mouse.h>
I'm working on a BHO written a long time ago in C++, without the use of any of the VS wizards. As a result, this project deviates from the COM conventions and the boilerplate for a COM product. I worked with COM long ago, but never really did any Windows GUI/dialog stuff...
I'm trying to add a dialog box to allow the user to set the values of some new settings:
// serverDialog will be NULL
HWND serverDialog = CreateDialog(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_PROPPAGE_SETTINGS), NULL, DialogProc);
id (!serverDialog)
{
int error = GetLastError(); //1813
...
}
....
1813 means that the resource cannot be found. The IDD used there is in resource.h, which I manually included where needed.
DialogProc is defined as:
INT_PTR CALLBACK DialogProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
return FALSE;
}
Which I know I will have to change later if I want the dialog to actually process messages, but I haven't gotten that far yet. The 1813 error suggests failure before the dialog is even created as does the NULL dialog handle returned.
To add the dialog I used the Add Resource wizard and added a small property page.
I've tried to follow advice here, but to no avail.
Thanks!
You are passing GetModuleHandle(NULL) as the instance of the module that contains the resource. But GetModuleHandle(NULL) defines the executable file module. You need to pass the instance of the module containing your code. This question covers that topic: How do I get the HMODULE for the currently executing code?
You probably ought to pass a window handle to the hWndParent parameter so that the dialog is owned.
I am writing\compiling a DLL that(currently) only exports a blank function. Source code:
DLLMain.cpp-
LIBRARYEXPORT LRESULT CALLBACK KeyboardProc(
int code,
WPARAM wParam,
LPARAM lParam
){
return 0;
}
Everything is okay so far, and here is my DLLMain.h-
using namespace std;
#include <iostream>
#include <fstream>
#include <string>
#include <Windows.h>
#define LIBRARYEXPORT __declspec(dllexport)
LIBRARYEXPORT LRESULT CALLBACK KeyboardProc(
int code,
WPARAM wParam,
LPARAM lParam
);
I plan to use this DLL with windows hooks to detect key presses, but when I call LoadLibrary from a separate executable, it returns with a runtime error saying
"DLL 'C:\Users\Orin\Documents\Visual Studio 2010\Projects\winmain\Debug\winmain.dll' is attempting managed execution inside OS Loader lock. Do not attempt to run managed code inside a DllMain or image initialization function since doing so can cause the application to hang."
That's great, but here's the catch: I'm not running any code at all in my KeyboardProc function, and I don't even have a DllMain routine
What I've tried(and hasn't worked):
Disabling CLR in project properties
Removing my "DllMain" routine
Using '#pragma unmanaged' when declaring functions
Suggestions and comments are really appreciated!
Found Answer:
When using Visual Studio, you must not choose a CLR Library project. Instead use the "Win32 Project" template. I can't believe I missed that!
EDIT: I forgot to mention, I do not have source code for the DLL that creates window, so I can't actually change the function to return HWND.
I am creating a Win32 application, and am using a DLL that creates a window for me through one of its exported function "void X();" I call X() in my WinMain().
It does create a window for me. I want to get the HWND of the window that was created by this exported library function, as X() returns void, so I can use it for other API calls.
Can someone tell the easiest to get the HWND?
I have searched and questions answered here, but I cant somehow figure out the exact, appropriate solution. I tried EnumWIndows() and then getting the Process ID, and then comparing with the current thread process ID. But I guess there should be a far better much more efficient and a easy way to get HWND.
After all, I am in the WinMain of the process that created this window in the first place.
If I need to explain anything, that I have missed out writing here, please let me know.
I am sure that this is very basic and am missing something blatantly here. Sorry.
Thanks & Regards!
Use a tool like Spy++ or Winspector to see all of the HWNDs created by your app, in particular their class names and window titles. Then you can copy those values into your code and make a single call to FindWindow() after the DLL has created its window, eg:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
// ...
X();
HWND hWnd = FindWindow("ClassNameHere", "TitleHere");
// ...
return 0;
}
The easiest way to do that is to use the function SetWindowsHookEx(WH_CBT, fun, NULL, GetCurrentThreadId()). Then the fun function, a callback defined by you, will be called when a number of events happen. The one you want is the HCBT_CREATEWND.
Somethink like that (totally untested):
HWND hDllHandle = NULL;
LRESULT CALLBACK X_CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HCBT_CREATEWND)
hDllHandle = (HWND)wParam;
return CallNextHookEx(NULL, nCode, wParam, lParam); //The first parameter is useless
}
HWND CallXAndGetHWND()
{
HHOOK hDllHook = SetWindowsHookEx(WH_CBT, X_CBTProc, NULL, GetCurrentThreadId());
X();
UnhookWindowsHookEx(hDllHook);
//hDllHandle is a global variable, so will be now you window!
return hDllHandle;
}
Note that this function is not thread-aware, but most likely you will call it just once at the beginning of your code, so it shouldn't matter.
And beware! Many functions, even Win32 API functions, create hidden windows. This code will hook all of them and return the last one to be created. Changing it to return any other, or even a list of them, if needed, should be trivial.
In my DDL, I have the following function defined:
extern "C" __declspec(dllexport) void hideme(HWND h) {
//ShowWindow(h, SW_HIDE);
SendMessage(h, WM_SHOWWINDOW, FALSE, 0);
}
As you can see, I've tried multiple things to get this working...
I have it declared in my winform as followed:
typedef void (*HideMe)(HWND);
In my System::Windows::Forms::Form Load event, I have the following code:
...
HINSTANCE hinst = LoadLibrary(_T("My.dll"));
if (hinst == NULL)
System::Diagnostics::Debug::WriteLine("null hinst");
else
hideme = (HideMe) GetProcAddress(hinst, "hideme");
...
In my System::Windows::Forms::Form Shown event, I have the following code:
...
hideme((HWND)this->Handle.ToPointer());
...
I think the problem must lie in the way I send over the HWND, but I've been searching all day, and can't find an alternative.
I've also tried setting this->Visible = false; but then I can't figure out how to trigger it back to visible from the DLL (abuse sendmessage?).
I'm not a C++ programmer, I normally only program in managed languages, so any help (and patience is appreciated.
Thanks,
Nick.
N.B.
One weird thing I can't explain is that I can't call ShowWindow from the WinForm itself. It will throw up this gem:
Error 2 error LNK2028: unresolved token (0A00001E) "extern "C" int __stdcall ShowWindow(struct HWND__ *,int)" (?ShowWindow##$$J18YGHPAUHWND__##H#Z) referenced in function "private: void __clrcall CheckMSNCpp::frmMain::frmMain_Shown(class System::Object ^,class System::EventArgs ^)" (?frmMain_Shown#frmMain#CheckMSNCpp##$$FA$AAMXP$AAVObject#System##P$AAVEventArgs#4##Z)
Error 3 error LNK2019: unresolved external symbol "extern "C" int __stdcall ShowWindow(struct HWND__ *,int)" (?ShowWindow##$$J18YGHPAUHWND__##H#Z) referenced in function "private: void __clrcall CheckMSNCpp::frmMain::frmMain_Shown(class System::Object ^,class System::EventArgs ^)" (?frmMain_Shown#frmMain#CheckMSNCpp##$$FA$AAMXP$AAVObject#System##P$AAVEventArgs#4##Z)
Error 4 error LNK1120: 2 unresolved externals
[EDIT1]
Hans Passant said:
The linker error message you got on
the ShowWindow() attempt is also a
strong hint why your current code is
not working. You forgot to add error
checking code, GetProcAddress() can
fail and will return a NULL pointer.
It will, the function isn't exported
by the "hideme" name. In a 32-bit
build, it will be exported as
"_hideme", note the underscore. Which
was added to indicate that the
function uses the __cdecl calling
convention. The linker error on
ShowWindow demonstrates C++ name
decoration, you forgot to #include
windows.h and made up your own,
incorrect, declaration for ShowWindow.
This is not the right way to do it,
you should just set the Visible
property to false. Like you tried. Why
you cannot set it back to true is
quite unguessable.
What you said makes no sense to me at all for a few reasons.
1)
The imports for the winform:
#include "stdafx.h"
#include <windows.h>
#include <iostream>
#include <stdio.h>
As you can tell, windows.h is in there.
2) the ShowWindor error is not in the DLL, there I can call it fine, it's in the WinForm code.
3) I never exported ShowWindow, just my own functions.
[/EDIT1]
[EDIT2]
Uwe Keim said:
Why do you need an extra DLL that is
merely just a wrapper to another DLL
function?
I would do it like in e.g. C# by using
PInvoke from your managed C++
application. The signature for
SendMessage would be (in C#):
The PInvoke stuff just doesn't make any sense, like commenters said.
As for the DLL, it needs to be a DLL because i require a global hook to respond to my hotkeys & WH_CBT. In this case, I want the program to start hidden & just show a setting screen when pressing a key combo.
Everything in the program works as expected, the hotkey works like a charm, the only thin I can't get right, is showing the application, triggered from the DLL.
[/EDIT2]
[EDIT3]
Example code at: http://www.nickkusters.com/CPP_PROBLEM_Demo-NOBIN.zip
[/EDIT3]
The linker error message you got on the ShowWindow() attempt is also a strong hint why your current code is not working. You forgot to add error checking code, GetProcAddress() can fail and will return a NULL pointer. It will, the function isn't exported by the "hideme" name. In a 32-bit build, it will be exported as "_hideme", note the underscore. Which was added to indicate that the function uses the __cdecl calling convention. The linker error on ShowWindow demonstrates C++ name decoration, you forgot to #include windows.h and made up your own, incorrect, declaration for ShowWindow.
This is not the right way to do it, you should just set the Visible property to false. Like you tried. Why you cannot set it back to true is quite unguessable.
Why do you need an extra DLL that is merely just a wrapper to another DLL function?
I would do it like in e.g. C# by using PInvoke from your managed C++ application. The signature for SendMessage would be (in C#):
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(
IntPtr hWnd,
UInt32 Msg,
IntPtr wParam,
IntPtr lParam);