Window GUI for DirectX Game seems to be faulty - c

I wanna developp a game using DirectX in Windows10. I use to write code with CodeBlocks. Following code will throw out error like this:
undefined reference to `GetStockObject#4'
What is problem with this Windowsfunction? I don't have to initialize or to write this function seperatly, don't I? Commenting out error code will compile code, but there is no gui...
Here is code:
#include <windows.h>
#include"Frame.h"
//global definitions
BOOL done;
int Spiel_Zustand;
HWND hwnd;
//Function:CallBack
LRESULT CALLBACK WindowProc (HWND hwnd,UINT message, WPARAM wparam,LPARAM lparam)
{
switch(message)
{
case WM_DESTROY :
{
done=TRUE;
PostQuitMessage(0);
return 0;
}
break;
case WM_KEYDOWN:
switch(wparam)
{
case VK_ESCAPE:
{
PostMessage(hwnd,WM_CLOSE,0,0);
return 0;
}
break;
}
break;
default:
break;
}//End of switch
return DefWindowProc(hwnd,message,wparam,lparam);
}//End of CallBack
//Function:Start
int WINAPI WinMain(HINSTANCE hinst,HINSTANCE hprevinst,LPSTR lpcmdline,int ncmdshow)
{
WNDCLASSEX winclass;
MSG message;
const char szclassname[]="Klassenname";
DWORD loop_start_time;
winclass.cbSize=sizeof(WNDCLASSEX);
winclass.style=CS_HREDRAW|CS_VREDRAW;
winclass.lpfnWndProc=WindowProc;
winclass.cbClsExtra=0;
winclass.cbWndExtra=0;
winclass.hInstance=hinst;
winclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
winclass.hCursor=LoadCursor(NULL,IDC_ARROW);
winclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);//this will throw out error
winclass.lpszClassName=szclassname;
winclass.hIconSm=LoadIcon(NULL,IDI_APPLICATION);
if(!RegisterClassEx(&winclass))
return 0;
//Create handle of windows ans save it globally
if(!(hwnd=CreateWindowEx(NULL,szclassname,"3D Gameprograming - Title",WS_POPUPWINDOW|WS_VISIBLE,0,0,400,300,NULL,NULL,hinst,NULL)))
return 0;
done=FALSE;
Spiel_Zustand=SPIEL_AUSWAHL;
//Phase 1.1:
Spiel_Initialisieren();
//Phase 1.2:: Main Looping
while(!done)
{
//Any message to handle?
while(GetMessage(&message,NULL,0,0))
{
TranslateMessage(&message);
DispatchMessage(&message);
}
//Start time of Main Loop
loop_start_time=GetTickCount;
switch(Spiel_Zustand)
{
case SPIEL_AUSWAHL:
{
//[....]
Spiel_Zustand=SPIEL_START;
}
break;
case SPIEL_START:
{
//[...]
Spiel_Zustand=SPIEL_LAEUFT;
}
break;
case SPIEL_LAEUFT:
{
//waiting for User input
//Manage User input
//Artificial Intelligence and game logic
//Rendering Frame
} break;
case SPIEL_NEUSTART:
{
//[...]
Spiel_Zustand=SPIEL_START;
}
break;
default:
break;
}//End of switch
//Restricting Frame rate
while((GetTickCount()-loop_start_time)<40);
}//End of Main Looping
//Phase 1.3
Spiel_Beenden();
return message.wParam;
}//End of Start
//Phase 2.1
int Spiel_Initialisieren(void)
{
//ToDO:initializations etc..
return 1;
}
//Phase 2.2
int Spiel_Beenden(void)
{
//ToDO:Free Memory etc..
return 1;
}

You need to link gdi32.lib when you compile -lgdi32
Undefined reference to GetStockObject#4

Related

Custom WM_APP message isn't posted in the message queue

I am trying to send a custom message (WM_APP + 1) when WM_SIZE is send to the window procedure. I want to be able to catch it from an other function using PeekMessage and do somethings. But when I test it the messages seem to not be send to the queue. Adding some printf statements shows me that it goes to the window procedure. The weird thing is that when I step through the code in the debugger it works fine but when I'm running normally, it goes back to not working.
Working example program with the problem, resize the window to test:
#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "user32.lib")
#define OBG_EVENT_QUIT 0
#define OBG_EVENT_RESIZE 1
#define OBG_EVENT_NO -1
#define OBG_EVENT_UNKNOWN -2
//user defined event
#define OBG_WM_RESIZE (WM_APP + 1)
typedef union
{
int type;
struct
{
int type;
int width;
int height;
} resizeEvent;
} obg_event;
LRESULT CALLBACK obgpf_DefaultWindowCallback(HWND window, UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT result = 0;
switch(message)
{
case WM_CLOSE:
{
PostMessageA(window, WM_QUIT, 0, 0);
} break;
//this should be handled by OBGGetEvent
case OBG_WM_RESIZE:
{
printf("MESSAGE WENT THROUGH. DON'T WANT THIS\n");
} break;
case WM_SIZE:
{
PostMessageA(window, OBG_WM_RESIZE, wParam, lParam);
} break;
default:
{
result = DefWindowProc(window, message, wParam, lParam);
} break;
}
return result;
}
int OBGGetEvent(obg_event *event)
{
int moreMessages = 0;
MSG message;
if(PeekMessage(&message, 0, 0, 0, PM_REMOVE))
{
moreMessages = 1;
switch(message.message)
{
case WM_QUIT:
{
event->type = OBG_EVENT_QUIT;
} break;
case OBG_WM_RESIZE:
{
event->type = OBG_EVENT_RESIZE;
event->resizeEvent.type = OBG_EVENT_RESIZE;
event->resizeEvent.width = LOWORD(message.lParam);
event->resizeEvent.height = HIWORD(message.lParam);
} break;
default:
{
event->type = OBG_EVENT_UNKNOWN;
TranslateMessage(&message);
DispatchMessage(&message);
} break;
}
}
else
{
event->type = OBG_EVENT_NO;
}
return moreMessages;
}
int main()
{
HINSTANCE instance = GetModuleHandleA(0);
WNDCLASSEX windowClass = {0};
windowClass.cbSize = sizeof(windowClass);
windowClass.style = CS_HREDRAW | CS_VREDRAW;
windowClass.lpfnWndProc = obgpf_DefaultWindowCallback;
windowClass.hInstance = instance;
windowClass.lpszClassName = "testClass";
windowClass.hIcon = LoadIcon(0, IDI_APPLICATION);
windowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
windowClass.hIconSm = LoadIcon(0, IDI_APPLICATION);
windowClass.hCursor = LoadCursorA(0, IDC_ARROW);
HWND window;
if(RegisterClassEx(&windowClass))
{
window = CreateWindowEx(0,
windowClass.lpszClassName,
"test window",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
500,
300,
0,
0,
instance,
0);
if(window)
{
int appIsRunning = 1;
obg_event event = {0};
event.type = -1;
while(appIsRunning)
{
while(OBGGetEvent(&event))
{
if(event.type == OBG_EVENT_QUIT)
{
printf("event quit\n");
appIsRunning = 0;
break;
}
else if(event.type == OBG_EVENT_RESIZE)
{
printf("window resized: width %d height %d\n", event.resizeEvent.width, event.resizeEvent.height);
}
}
Sleep(33);
}
}
else
{
printf("window error\n");
}
}
else
{
printf("windowClass error\n");
}
return 0;
}
I tried doing this with SendMessage instead of PeekMessage but the same thing happened. Not sure what I'm missing or misunderstanding but any help is appreciated!
EDIT: added a complete working program that reproduces the problem
Thank you for the example code.
The behaviour you're seeing is because when the window is being resized using the mouse, the OS enters a modal message loop to process mouse input. During this loop, your message loop doesn't run - which means your PeekMessage() and the special message handling doesn't run either. Instead, messages are simply dispatched as normal to your window procedure.
There are two solutions that come to mind immediately but how you deal with this really depends on the design of your program and why you want to process size events in this way.
The first idea I had is to keep track of whether you're in a modal sizing loop or not, and defer posting the notification message until the loop is finished. An example of how to do that using your provided window procedure is below.
The second solution is to simply call your resize event handler directly whenever you get WM_SIZE (or, if you must go through the event system, put the handler for it in the window procedure rather than using PostMessage).
Example code for the first suggestion:
LRESULT CALLBACK obgpf_DefaultWindowCallback(HWND window, UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT result = 0;
static bool fResized = false;
static bool fInSizeLoop = false;
switch(message)
{
case WM_CLOSE:
{
PostMessageA(window, WM_QUIT, 0, 0);
} break;
//this should be handled by OBGGetEvent
case OBG_WM_RESIZE:
{
printf("MESSAGE WENT THROUGH. DON'T WANT THIS\n");
} break;
case WM_SIZE:
{
if (fInSizeLoop) // in modal size loop, defer notification
fResized = true;
else
PostMessageA(window, OBG_WM_RESIZE, wParam, lParam);
} break;
case WM_ENTERSIZEMOVE:
fInSizeLoop = true; // begin modal size loop
break;
case WM_EXITSIZEMOVE:
fInSizeLoop = false; // left modal size loop
// post resize notification now
if (fResized) {
RECT rc;
GetClientRect(window, &rc);
PostMessageA(window, OBG_WM_RESIZE, 0, MAKELPARAM(rc.right - rc.left, rc.bottom - rc.top));
fResized = false;
}
break;
default:
{
result = DefWindowProc(window, message, wParam, lParam);
} break;
}
return result;
}
(sorry, this is C++ code and I just noticed you had tagged as C - but the principle is the same).

Global keyboard hook in C using DLL doesn't work

I tried to do global keyboard hooking in C and got in trouble.
My purpose is that when I type F2 key or Ctrl key, some lines will be printed to check whether it works or not, and if I press the q key, it will stop hooking.
To test the whole code, I've used printf in some parts.
I have no idea how to figure out this problem, but really want to solve it.
.cpp code:
#include "stdio.h"
#include "conio.h"
#include "windows.h"
#define DEF_HOOKSTART "HookStart"
#define DEF_HOOKSTOP "HookStop"
typedef void(*PFN_HOOKSTART)();
typedef void(*PFN_HOOKSTOP)();
void main() {
HMODULE hDll = NULL;
PFN_HOOKSTART HookStart = NULL;
PFN_HOOKSTOP HookStop = NULL;
char ch = 0;
// load Dll
hDll = LoadLibrary(L"HookTest.dll");
if (hDll == NULL) {
printf("load fail \n");
return;
}
else {
printf("load success \n");
}
HookStart = (PFN_HOOKSTART)GetProcAddress(hDll, DEF_HOOKSTART);
HookStop = (PFN_HOOKSTOP)GetProcAddress(hDll, DEF_HOOKSTOP);
HookStart();
printf("press 'q' to quit!\n");
// if user push 'q' key, HookStop
while (1) {
if (_getch() == 'q') {
break;
}
printf("Test Typing \n");
}
HookStop();
FreeLibrary(hDll);
}
.dll code:
#include <stdio.h>
#include <windows.h>
#pragma data_seg(".kbdata")
HINSTANCE g_hInstance = NULL;
HHOOK g_hHook = NULL;
HWND g_hWnd = NULL;
#pragma data_seg()
#pragma comment(linker, "/SECTION:.kbdata,RWS")
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved) {
switch (dwReason) {
case DLL_PROCESS_ATTACH:
g_hInstance = hinstDLL;
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
extern "C" {
LRESULT __declspec(dllexport) CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
printf("Test 1 --- KeyboardProc sucess \n");
if (nCode >= 0) {
printf("Test 2 --- \n");
if (wParam == VK_F2) {
printf("F2 Key Typed ");
}
else if (wParam == VK_CONTROL) {
printf("Ctrl Key Typed ");
}
else {
printf("Other Key Typed");
}
}
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
}
extern "C" __declspec(dllexport) void HookStart() {
g_hHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hInstance, 0);
printf("Test 3 --- HookStart Call \n");
}
extern "C" __declspec(dllexport) void HookStop() {
printf("Test 4 --- HookStop Call \n");
if (g_hHook) {
UnhookWindowsHookEx(g_hHook);
g_hHook = NULL;
}
}

Memory increases every time I resize the window

I have created a simple Win32 Application and try to fill the Client Area with a Color. When the line "Clear RenderTarget" is included I see that the memory increases a few KB every time I resize the window.
My WindowProc:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_SIZE:
{
if (pRenderTarget != NULL)
{
RECT rc;
GetClientRect(globalWindowHandle, &rc);
D2D1_SIZE_U size = D2D1::SizeU(rc.right, rc.bottom);
pRenderTarget->Resize(size);
InvalidateRect(globalWindowHandle, NULL, FALSE);
}
return 0;
}
break;
case WM_CREATE:
{
HRESULT dx = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pFactory);
if (FAILED(dx))
{
MessageBox(globalWindowHandle, "Error creating D2D1Factory", "Error", MB_ICONERROR);
return -1;
}
return 0;
}
break;
case WM_KEYDOWN:
{
int ret = HandleKeyboardInput(uMsg, wParam, lParam);
if (ret == 0)
{
return 0;
}
}
break;
case WM_PAINT:
{
HRESULT hr = CreateGraphicsResources();
if (SUCCEEDED(hr))
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
pRenderTarget->BeginDraw();
// Clear RenderTarget
pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::SkyBlue));
hr = pRenderTarget->EndDraw();
if (FAILED(hr) || hr == D2DERR_RECREATE_TARGET)
{
pRenderTarget->Release();
pSolidBrush->Release();
pRenderTarget = NULL;
pSolidBrush = NULL;
}
EndPaint(hwnd, &ps);
return 0;
}
}
break;
case WM_CLOSE:
{
int box = MessageBox(hwnd, "Would you like to close the editor ?", "Question", MB_OKCANCEL);
if (box == IDOK)
{
DestroyWindow(hwnd);
}
return 0;
}
break;
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
break;
default:
{
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
break;
}
return 0;
}
CreateGraphicsResources
HRESULT CreateGraphicsResources()
{
HRESULT hr = S_OK;
if (pRenderTarget == NULL)
{
RECT rc;
GetClientRect(globalWindowHandle, &rc);
D2D1_SIZE_U size = D2D1::SizeU(rc.right, rc.bottom);
hr = pFactory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(globalWindowHandle, size),
&pRenderTarget);
if (SUCCEEDED(hr))
{
const D2D1_COLOR_F color = D2D1::ColorF(1.0f, 1.0f, 1.0f, 0);
hr = pRenderTarget->CreateSolidColorBrush(color, &pSolidBrush);
if (SUCCEEDED(hr))
{
}
}
}
return hr;
}
Globals:
BOOL ctrlPressed = FALSE;
HWND globalWindowHandle;
ID2D1Factory *pFactory;
ID2D1SolidColorBrush *pSolidBrush;
ID2D1HwndRenderTarget *pRenderTarget;
Do I miss something to free up memory or what could be the reason? If I resize the window e.g. 5 sec the memory goes from 4KB up to 22KB.
My OS is Windows 10 x64
The issue seems to be solved. In fact the memory did not go up much more so it seems the OS assigns the other memory.

My Win32 application won't exit the main loop

This is my main loop:
while(TRUE)
{
PeekMessage(&msg,hWnd,0,0,PM_REMOVE);
if (msg.message==WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
and this is my callback procedure:
LRESULT CALLBACK WinProc(HWND hWnd,UINT msg1,WPARAM wParam,LPARAM lParam)
{
switch(msg1)
{
case WM_DESTROY :
{
PostQuitMessage(0);
return 0;
}
break;
}
return DefWindowProc(hWnd,msg1,wParam,lParam);
}
I found out that when I press Close button WM_NCLBUTTONDOWN will be returned by the PeekMessage function in the next loop, and no WM_QUIT!
The correct way to do a message loop is
BOOL bRet;
MSG msg;
while ((bRet = GetMessage(&msg, hWnd, 0, 0)) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
You can use PeekMessage if you really need to... but why are you ignoring the return value?
Also, note that this is specific to a window. I believe PostQuitMessage is for a thread... I don't remember it off the top of my head, but you might need to pass NULL instead of hWnd.
If you have any other windows, that may hijack their message loop as well -- I don't think it's usually an issue, but it might potentially be one; keep that in mind.
Here's some code I found. It should give you something to work with.
// Main message loop:
do
{
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// Run game code here.
gTradeApp->ExecuteNextAction();
}
while (msg.message != WM_QUIT);
and the WndProc
LRESULT CALLBACK WndProc(HWND aHWnd, UINT aMessage, WPARAM aWParam, LPARAM aLParam)
{
switch (aMessage)
{
case WM_COMMAND:
return HandleCommand(aHWnd, aMessage, aWParam, aLParam);
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(aHWnd, aMessage, aWParam, aLParam);
}
return 0;
}
I recommend sticking with this, to ensure errors (-1) returned by GetMessage can be handled properly:
while(GetMessage(&Msg, NULL, 0, 0) > 0) {
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
Also, another error is not handling WM_CLOSE properly. Try this instead to make your program actually listen to WM_CLOSE (the close button):
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
switch(Message) {
case WM_CLOSE: {
DestroyWindow(hwnd); // this
break;
}
case WM_DESTROY: {
PostQuitMessage(0);
break;
}
default:
return DefWindowProc(hwnd, Message, wParam, lParam);
}
return 0;
}

Set static text color Win32

I am making a dll that controls a dialogue box. I like to get a certain area to have red text. This code does compile, but the effect is not seen. Here is the area where the dialogProc is done:
LRESULT CALLBACK DialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_INITDIALOG:
CheckDlgButton(hDlg, IDC_CHECK, FALSE);
EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_CHECK:
if (IsDlgButtonChecked(hDlg, IDC_CHECK))
{
EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
EnableWindow(GetDlgItem(hDlg, IDCANCEL), FALSE);
}
else
{
EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
EnableWindow(GetDlgItem(hDlg, IDCANCEL), TRUE);
}
break;
case IDOK:
{
EndDialog(hDlg, TRUE);
return FALSE;
}
case IDCANCEL:
{
EndDialog(hDlg, FALSE);
return FALSE;
}
case WM_CTLCOLORSTATIC:
// Set the colour of the text for our URL
if ((HWND)lParam == GetDlgItem(hDlg,IDC_WARNING))
{
// we're about to draw the static
// set the text colour in (HDC)lParam
SetBkMode((HDC)wParam,TRANSPARENT);
SetTextColor((HDC)wParam, RGB(255,0,0));
return (BOOL)CreateSolidBrush (GetSysColor(COLOR_MENU));
}
return TRUE;
}
}
return FALSE;
}
WM_CTLCOLORSTATIC is a separate message from WM_COMMAND. Your desired handling of the message appears to be correct except that the check for the message is inside your check for WM_COMMAND specific items. Try reorganizing your outer switch statement. Perhaps something like the following:
LRESULT CALLBACK DialogProc(HWND hDlg, UINT message,
WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_INITDIALOG:
// ...
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_CHECK:
// ...
break;
case IDOK:
// ...
break;
case IDCANCEL:
// ...
break;
}
break;
case WM_CTLCOLORSTATIC:
// Set the colour of the text for our URL
if ((HWND)lParam == GetDlgItem(hDlg, IDC_WARNING))
{
// we're about to draw the static
// set the text colour in (HDC)lParam
SetBkMode((HDC)wParam,TRANSPARENT);
SetTextColor((HDC)wParam, RGB(255,0,0));
// NOTE: per documentation as pointed out by selbie, GetSolidBrush would leak a GDI handle.
return (BOOL)GetSysColorBrush(COLOR_MENU);
}
break;
}
return FALSE;
}
Also note that it would be kinda weird to filter WM_COMMAND's wParam argument when wParam is supposed to provide the HDC for WM_CTLCOLORSTATIC.
WM_CTLCOLORSTATIC Notification at MSDN

Resources