I'm trying to make a program that sends key presses to an inactive window, I'm using "SendMessageCallback()" but it isn't giving an error, or sending the key press.
typedef enum {false,true} bool;
bool KeyDown(HWND hWnd, WORD dKey){
if(!SendMessageCallback(hWnd, WM_KEYDOWN, 0, dKey, (SENDASYNCPROC)NULL, (ULONG_PTR)NULL))
return false;
return true;
}
bool KeyUp(HWND hWnd, WORD uKey){
if(!SendMessageCallback(hWnd, WM_KEYDOWN, 0, uKey, (SENDASYNCPROC)NULL, (ULONG_PTR)NULL))
return false;
return true;
}
then, I simply call it like this:
HWND FOO = FindWindow("FOO", NULL );
if( FOO == NULL )
MessageBox(NULL, "FOO Not Found", "ERROR", MB_OK);
if (!KeyDown(FOO, VK_SPACE))
MessageBox(NULL, "KeyDown failed to execute!", "ERROR", MB_OK);
if (!KeyUp(FOO, VK_SPACE))
MessageBox(NULL, "KeyUp failed to execute!", "ERROR", MB_OK);
I substituted What the real HWND is for FOO, If more information is needed please tell me.
The problem is it doesn't send the key press or show a message box.
Edit: I tried adding a delay between pressing the key down and releasing it and that didn't solve it.
Without knowing anything about the window you are working with, I can only surmise that it is not coded to process keystrokes in its WndProc. You can use Spy++ or similar tool to verify that the messages are actually being sent, but that is no guarantee that they will be processed. You cannot send keystrokes to arbitrary windows that are not expecting them. And BTW, keystroke messages are typically posted to a window's message queue, not sent directly to the window's WndProc, so try using PostMessage() instead.
Related
I have dialog created using CreateDialogParam. It has only a single ListView child control. In the dialog WM_INITDIALOG message handler, I subclass the ListView to customize header redrawing.
Now I want to prevent the user from resizing the ListView column (header) and, to do this, I just need to handle the HDN_BEGINTRACKA notification message in the ListView's WndProc, like below:
case WM_NOTIFY:
{
if ((((LPNMHDR)lParam)->code == HDN_BEGINTRACKA)
|| (((LPNMHDR)lParam)->code == HDN_BEGINTRACKW))
return TRUE; // to disable column resizing
}
This works OK; but, for some reason I want to handle this message in the parent (dialog) procedure. So, I forward this message to that parent as below:
case WM_NOTIFY:
{
if ((((LPNMHDR)lParam)->code == HDN_BEGINTRACKA)
|| (((LPNMHDR)lParam)->code == HDN_BEGINTRACKW))
{
BOOL b = FALSE;
HWND hParent = GetRealParent(hwnd);
if (hParent) b = SendMessage(hParent, msg, wParam, lParam);
return b; // to disable column resizing return TRUE;
}
}
break;
The message is sent OK but, even though I return TRUE from the dialog procedure, here in the ListView procedure, the return value of the SendMessage call is FALSE.
In the dialog procedure, the code is as below:
case WM_NOTIFY:
{
if ((((LPNMHDR)lParam)->code == HDN_BEGINTRACKA)
|| (((LPNMHDR)lParam)->code == HDN_BEGINTRACKW))
return TRUE;
}
So, my question is why directly sending (forwarding) the WM_NOTIFY message to the parent returns a different result, or simply just doesn't work?
Edit :-
In the past, I have faced the same problem; to solve it, I tried a user-defined message, like:
#define UWM_WM_NOTIFY (WM_APP + 7)
and use that with SendMessage to communicate between child and parent, or between any other dialogs. But it also fails to get proper return values.
So, I am using SendMessage as follow:
BOOL b = FALSE;
SendMessageA(hDlg, UWM_ANY_WM, 0, (LPARAM) &b);
return b;
Sending address of variable as LPARAM to get return value. Is there any better way to do this. Or Why SendMessageA return value is different?
From the Microsoft documentation for the WM_NOTIFY message1:
If the message handler is in a dialog box procedure, you must use the
SetWindowLong function with DWL_MSGRESULT to set a return value.
So, using the more up-to-date SetWindowLongPtr function, your parent (dialog box) handling for the WM_NOTIFY message should look something like this:
case WM_NOTIFY:
{
if ((((LPNMHDR)lParam)->code == HDN_BEGINTRACKA)
|| (((LPNMHDR)lParam)->code == HDN_BEGINTRACKW))
{
SetWindowLongPtr(hWnd, DWL_MSGRESULT, TRUE); // hWnd is dialog's HWND
return TRUE;
}
}
Also note that your handler should continue to return TRUE, as noted in this document:
If you use SetWindowLong with the DWL_MSGRESULT index to set the
return value for a message processed by a dialog procedure, you should
return TRUE directly afterward. Otherwise, if you call any function
that results in your dialog procedure receiving a window message, the
nested window message could overwrite the return value you set using
DWL_MSGRESULT.
1 Actually, you need to use the outlined mechanism to set the return value for (almost) any message handled by a dialog procedure, as nicely described in this blog by Raymond Chen.
Standard Windows message boxes have a functionality of copying their contents on pressing Ctrl+C to clipboard.
Ok, I decided to try doing this myself.
Here is my dialogue resource:
IDD_MAIN DIALOGEX 0,0,500,250 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
CAPTION "Information"
FONT 8, "MS Shell Dlg",0,0,0x1
{ LTEXT "I strongly recommend you to move all your user folders to disk D\:",ID_INFOTEXT,10,10,100,100
CHECKBOX "&Do not show this dialogue again",ID_SHOWSTATE,10,120,100,15
DEFPUSHBUTTON "&Ok",IDOK,273, 148, 100, 15
}
Dialogue is created quite fine, everything works fine too.
Checkbox is checked/unchecked as expected, and Ok closes the dialogue.
Now when you press Ctrl+C you hear an ugly beep.
I have tryed to handle the Ctrl+C in dialogue proc, but keystrokes do not go there at all.
Now I have used a WM_GETDLGCODE in a subclassed control window proc, but also with no result - could not get rid that ugly beep and Ctrl+C does not go there too.
Ok, I have replaced a windowProc for a dialogue, but still no result - the ugly beep is in place and no Ctrl+C there.
So the question at the very end is where does that ugly beep come from by default? Any special message handle somewhere in DefWindowProc?
Where can I handle it finally and replace handler?
P. S. No MFC, no startup code, no .net, pure C and WinAPI only.
The dialog manager treats MessageBox based dialogs in a special way and sends them a WM_COPY message so it can fill the clipboard.
The beep comes from IsDialogMessage because the child control with the keyboard focus does not want the keyboard input.
To catch the Ctrl+C keypress and avoid the beep you must process keyboard messages before calling IsDialogMessage. You could call TranslateAccelerator or do your own custom handling:
INT_PTR CALLBACK DlgProc(HWND hDlg, UINT Msg, WPARAM Wp, LPARAM Lp)
{
switch(Msg)
{
case WM_CLOSE:
DestroyWindow(hDlg);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_COPY:
MessageBoxA(hDlg, "TODO: Set clipboard content here", 0, 0);
break;
}
return FALSE;
}
BOOL IsKbdCopyMessage(HWND hDlg, MSG*pMsg)
{
if (pMsg->message == WM_CHAR && pMsg->wParam == VK_CANCEL)
{
LRESULT dlgcod = SendMessage(pMsg->hwnd, WM_GETDLGCODE, pMsg->wParam, 0);
if (!(dlgcod & (DLGC_WANTMESSAGE|DLGC_WANTCHARS)))
{
SendMessage(hDlg, WM_COPY, 0, 0);
return TRUE;
}
}
return FALSE;
}
...WinMain(...)
{
MSG msg;
HWND hDlg = CreateDialog(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_MAIN), NULL, DlgProc);
while(GetMessage(&msg, 0, 0, 0))
{
if (IsKbdCopyMessage(hDlg, &msg)) continue;
if (IsDialogMessage(hDlg, &msg)) continue;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
One way to detect Ctrl-C could be to on receiving a WM_KEYDOWN passing a 0x43 (virtual key-code for the C-key) as wParam call GetAsyncKeyState() and test its result for having VK_CONTROL set.
You could avoid calling call GetAsyncKeyState() by tracking the Ctrl-keys' states yourself by also monitoring WM_KEYUP messages, for the relevant "virtual key-code".
my first post on stackoverflow.
I'm not much of a coder, I dabble in coding sometimes for fun and as such I don't invest much time in understanding the fundamentals, but rather find whatever solution that works, even if it's a little "ugly".
Which brings me to my problem: I wrote a simple winapi program in C with one dialog box and one DlgProc.
It accepts files and does something with them, lets say, for the sake of simplification that all it does is create a copy of the file with the extension *.BAK.
I've added a key to the registry (HKEY_CLASSES_ROOT*\shell\BKUP\command) so that I can select several files in windows explorer and have the option "Create Backup" to send all their names to my program but that calls my program for each file separately. So I googled, did some reading, turns out I need something called IPC (Interprocess Communications), read some options, WM_COPYDATA message looked like it was the simplest and easiest solution, so I used it and it works like a charm, BUT, sometimes it just doesn't... First I'll explain what I do:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
HWND hwnd;
COPYDATASTRUCT dsIPC;
hwnd=FindWindow("#32770","Backup program");
if(hwnd)
{
// send "__argv[1]" via SendMessage(hwnd,WM_COPYDATA... etc.
return(0);
}
return DialogBox(hInstance, MAKEINTRESOURCE(ID_DIALOG), NULL, DlgProc);
}
I use FindWindow() to check if there is an instance of the program running, if not it runs normally, if yes I send the file name to the window found by FindWindow() and exit that instance of the program completely.
Inside the dialog process I have code to fill an array with the names of the files and for each set a short timer with SetTimer() and when all the file names are received the timer goes off and I start copying the files.
Again, all this works great but on occasion, two or even 3 instances of the program are opening and the files are split between them, which means FindWindow() sometimes fails to find the 1st window.
example:
I select 10 files in windows explorer, right click them and choose "Create Backup".
2 windows of my program open.
1st window output:
"File 00.DAT" Backed up successfully.
"File 01.DAT" Backed up successfully.
2nd window output:
"File 02.DAT" Backed up successfully.
"File 03.DAT" Backed up successfully.
"File 04.DAT" Backed up successfully.
"File 05.DAT" Backed up successfully.
"File 06.DAT" Backed up successfully.
"File 07.DAT" Backed up successfully.
"File 08.DAT" Backed up successfully.
"File 09.DAT" Backed up successfully.
And then, I close the 2 windows and again select the same 10 files and again choose "Create Backup" but this time and for the next several attempts I get only one window:
1st window output:
"File 00.DAT" Backed up successfully.
"File 01.DAT" Backed up successfully.
"File 02.DAT" Backed up successfully.
"File 03.DAT" Backed up successfully.
"File 04.DAT" Backed up successfully.
"File 05.DAT" Backed up successfully.
"File 06.DAT" Backed up successfully.
"File 07.DAT" Backed up successfully.
"File 08.DAT" Backed up successfully.
"File 09.DAT" Backed up successfully.
Can anyone explain why does it happen?
P.S. If it matters, I'm testing on Windows 7 x64.
[Edit - May 16th 2017]
Here is the dumbed down version of zett42's code, it works great for testing but on my to-do-list I wrote down to read and understand the rest of zett42's code because mine's probably flawed in some way.
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
HWND hwnd;
COPYDATASTRUCT dsIPC;
int i;
DWORD err;
HANDLE hMutex;
hMutex = CreateMutex(NULL, TRUE, "56f0e348-2c1a-4e01-a98e-3e6c8198f9aa");
err = GetLastError();
if(!hMutex)
{
MessageBox(NULL, "Cannot create mutex object. Click OK to exit.", "Error:", MB_OK | MB_ICONSTOP);
return (1);
}
if(err == ERROR_ALREADY_EXISTS)
{
for(i=0 ; i<1000 ; i++)
{
hwnd=FindWindow("#32770","Backup program");
if(hwnd) break;
Sleep(30);
}
if(i==1000) return (1);
dsIPC.dwData=666;
dsIPC.cbData=lstrlen(__argv[1])+1;
dsIPC.lpData=__argv[1];
SendMessage(hwnd, WM_COPYDATA, (WPARAM)hInstance, (LPARAM)&dsIPC);
return(0);
}
return DialogBox(hInstance, MAKEINTRESOURCE(ID_DIALOG), NULL, DlgProc);
}
As commenter treintje suggested:
There could be a race condition happening where two of your program
instances are started at the same time and neither of them had the
chance to create a dialog window yet, causing FindWindow to return
NULL in both cases. You could prevent this by using a mutex object to
check if another instance is already running.
Here is a code sample to show how such mutex could be used to avoid the race condition:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
// Try to create a mutex. Replace the string by something globally unique,
// for instance a GUID created by using the GuidGen utility, that comes with
// Visual Studio (look in the "Extras" menu).
HANDLE hMutex = CreateMutexW(nullptr, TRUE, L"REPLACE-WITH-YOUR-GUID");
// Make sure to put no other code in between the CreateMutex() and the
// GetLastError() calls to prevent the last error value from being messed up.
DWORD err = GetLastError();
if(!hMutex)
{
// TODO: error handling
return 1;
}
if(err == ERROR_ALREADY_EXISTS)
{
// An instance of this process is already running, but it might not
// have created the window yet, so FindWindow() could still fail.
// You could call FindWindow() in a loop but that would waste resources.
// So I'm using an event object to wait until the window has been created.
// This event object must be set to "signaled" state in WM_INITDIALOG
// handler of the dialog.
HANDLE hWindowCreatedEvent = CreateEventW(nullptr, TRUE, FALSE,
L"PUT-ANOTHER-GUID-HERE");
if(hWindowCreatedEvent)
{
// Wait with timeout of 30s because the 1st process might have failed
// to create the window for some reason.
DWORD waitRes = WaitForSingleObject(hWindowCreatedEvent, 30 * 1000);
if(waitRes == WAIT_OBJECT_0)
{
// The event is signaled so now we know for sure that the window
// has been created.
HWND hwnd;
COPYDATASTRUCT dsIPC;
hwnd=FindWindow("#32770","Backup program");
if(hwnd)
{
// send "__argv[1]" via SendMessage(hwnd,WM_COPYDATA... etc.
}
}
else
{
// TODO: error handling
}
CloseHandle(hWindowCreatedEvent);
}
else
{
// TODO: error handling
}
}
else
{
// This is the first instance of this process.
return DialogBox(hInstance, MAKEINTRESOURCE(ID_DIALOG), NULL, DlgProc);
}
CloseHandle(hMutex);
}
Edit your DialogProc to set the event object that signals other instances of the process that the window has been created:
INT_PTR CALLBACK DialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch(uMsg)
{
case WM_INITDIALOG:
{
// Use the same event name as in WinMain()!
HANDLE hWindowCreatedEvent = CreateEventW(nullptr, TRUE, FALSE,
L"PUT-GUID-FROM-WINMAIN-HERE");
if(hWindowCreatedEvent)
{
SetEvent(hWindowCreatedEvent);
CloseHandle(hWindowCreatedEvent);
}
// other initialization code...
return TRUE;
}
}
return FALSE;
}
Another suggestion: Don't search for the window caption because "Backup program" is way to generic and could be used by other applications. Then you would send WM_COPYDATA to wrong process.
Instead, register a window class with a globally unique name and only search for the class name (call FindWindow() with NULL as the argument for lpWindowName). You must also specify the class name in the dialog template.
First of all, let me get my point for this:
This is an emergency alert system, it pulls from a website which we manipulate in the back office, the program can be minimized but cannot be closed (easily, at least none of the people that will use it will know how). As you can see, if the program was closed the Emergency Alerts wouldn't be seen/heard....that's an issue. I have to deploy this application on over 200 computers so I want it simple, I don't want to create a scheduled task, etc.. to keep it running. I simply want it to not be easy to close.
See my code, below:
/* example.c
This is a Win32 C application (ie, no MFC, WTL, nor even any C++ -- just plain C) that demonstrates
how to embed a browser "control" (actually, an OLE object) in your own window (in order to display a
web page, or an HTML file on disk). The bulk of the OLE/COM code is in DLL.c which creates a DLL that
we use in this simple app. Furthermore, we use LoadLibrary and GetProcAddress, so our DLL is not
actually loaded until/unless we need it.
NOTE: The DLL we create does not normally use UNICODE strings. If you compile this example as UNICODE,
then you should do the same with DLL.C.
*/
#include <windows.h>
#include "..\CWebPage.h" /* Declarations of the functions in DLL.c */
// A running count of how many windows we have open that contain a browser object
unsigned char WindowCount = 0;
// The class name of our Window to host the browser. It can be anything of your choosing.
static const TCHAR ClassName[] = "EAS";
// Where we store the pointers to CWebPage.dll's functions
EmbedBrowserObjectPtr *lpEmbedBrowserObject;
UnEmbedBrowserObjectPtr *lpUnEmbedBrowserObject;
DisplayHTMLPagePtr *lpDisplayHTMLPage;
DisplayHTMLStrPtr *lpDisplayHTMLStr;
/****************************** WindowProc() ***************************
* Our message handler for our window to host the browser.
*/
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_CREATE)
{
// Embed the browser object into our host window. We need do this only
// once. Note that the browser object will start calling some of our
// IOleInPlaceFrame and IOleClientSite functions as soon as we start
// calling browser object functions in EmbedBrowserObject().
if ((*lpEmbedBrowserObject)(hwnd)) return(-1);
// Another window created with an embedded browser object
++WindowCount;
// Success
return(0);
}
if (uMsg == WM_DESTROY)
{
// Detach the browser object from this window, and free resources.
(*lpUnEmbedBrowserObject)(hwnd);
// One less window
--WindowCount;
// If all the windows are now closed, quit this app
if (!WindowCount) PostQuitMessage(0);
return(TRUE);
}
// NOTE: If you want to resize the area that the browser object occupies when you
// resize the window, then handle WM_SIZE and use the IWebBrowser2's put_Width()
// and put_Height() to give it the new dimensions.
return(DefWindowProc(hwnd, uMsg, wParam, lParam));
}
/****************************** WinMain() ***************************
* C program entry point.
*
* This creates a window to host the web browser, and displays a web
* page.
*/
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hInstNULL, LPSTR lpszCmdLine, int nCmdShow)
{
HINSTANCE cwebdll;
MSG msg;
WNDCLASSEX wc;
// Load our DLL containing the OLE/COM code. We do this once-only. It's named "cwebpage.dll"
if ((cwebdll = LoadLibrary("cwebpage.dll")))
{
// Get pointers to the EmbedBrowserObject, DisplayHTMLPage, DisplayHTMLStr, and UnEmbedBrowserObject
// functions, and store them in some globals.
// Get the address of the EmbedBrowserObject() function. NOTE: Only Reginald has this one
lpEmbedBrowserObject = (EmbedBrowserObjectPtr *)GetProcAddress((HINSTANCE)cwebdll, "EmbedBrowserObject");
// Get the address of the UnEmbedBrowserObject() function. NOTE: Only Reginald has this one
lpUnEmbedBrowserObject = (UnEmbedBrowserObjectPtr *)GetProcAddress((HINSTANCE)cwebdll, "UnEmbedBrowserObject");
// Get the address of the DisplayHTMLPagePtr() function
lpDisplayHTMLPage = (DisplayHTMLPagePtr *)GetProcAddress((HINSTANCE)cwebdll, "DisplayHTMLPage");
// Get the address of the DisplayHTMLStr() function
lpDisplayHTMLStr = (DisplayHTMLStrPtr *)GetProcAddress((HINSTANCE)cwebdll, "DisplayHTMLStr");
// Register the class of our window to host the browser. 'WindowProc' is our message handler
// and 'ClassName' is the class name. You can choose any class name you want.
ZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.hInstance = hInstance;
wc.lpfnWndProc = WindowProc;
wc.lpszClassName = &ClassName[0];
RegisterClassEx(&wc);
// Create another window with another browser object embedded in it.
if ((msg.hwnd = CreateWindowEx(0, &ClassName[0], "Emergency Alert System", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
HWND_DESKTOP, NULL, hInstance, 0)))
{
// For this window, display a URL. This could also be a HTML file on disk such as "c:\\myfile.htm".
(*lpDisplayHTMLPage)(msg.hwnd, "http://www.google.com");
// Show the window.
ShowWindow(msg.hwnd, nCmdShow);
UpdateWindow(msg.hwnd);
}
// Do a message loop until WM_QUIT.
while (GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Free the DLL.
FreeLibrary(cwebdll);
return(0);
}
MessageBox(0, "Can't open cwebpage.dll! You are not protected by Emergency Alerting System. Click OK to terminate this application. Contact the developer, Scott Plunkett.", "ERROR", MB_OK);
return(-1);
}
It took this from an example tutorial I found, I have never done any windows programming before so I had to figure out a quick solution.
I appreciate any and all help on this.
If you create a handler for the WM_SYSCOMMAND message and check for the SC_SYSCLOSE parameter, you can stop it from executing the default action of closing the window.
I noticed it's not an MFC application, so you have to call Win32 Library to enable the feature.
Try this out:http://www.davekb.com/browse_programming_tips:win32_disable_close_button:txt
---EDIT---
Sorry the code did not work out. I did not have resources to debug it.
To disable the X of the window, you can either set CS_NOCLOSE property of WNDCLASSEX:
wc.style = CS_NOCLOSE;//in your code
or rewrite the WM_CLOSE message handler function. Thanks.
First of all, sorry for my ignorance of the window creation process. Today is actually the first day of my experimenting with it.
I started to code a text based game a few days ago and I have the main menu, and 3 or 4 different functions that control various things with text. I was then advised to look into Windows API and create a window for the program. I have created the window which can be seen here:
#include <Windows.h>
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PWSTR nCmdLine, int nCmdShow)
{
const wchar_t CLASS_NAME[] = L"WindowClass";
WNDCLASS wc = { };
wc.lpfnWndProc = WindowProc;
wc.lpszClassName = CLASS_NAME;
wc.hInstance = hInstance;
RegisterClass(&wc);
HWND hwnd = CreateWindowEx( //This creats a new instance of a window
0,
CLASS_NAME,
L"MyFirstWindow",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
500,
500,
NULL,
NULL,
hInstance,
NULL);
if(hwnd == 0)
return 0;
ShowWindow(hwnd,nCmdShow);
nCmdShow = 1;
MSG msg = { };
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_DESTROY:PostQuitMessage(0); return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd,&ps);
FillRect(hdc,&ps.rcPaint,(HBRUSH)(COLOR_WINDOW+5));
EndPaint(hwnd, &ps);
}return 0;
case WM_CLOSE:
{
if(MessageBox(hwnd,L"Do you want to exit?",L"Exit",MB_OKCANCEL)==IDOK)
DestroyWindow(hwnd);
} return 0;
}
return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
This looks a bit messy, but you probably will not need it anyway.
So at this point I have my original program and this program that creates a window. My question is how, or even where, do I put my original program's code so that it can be incorporated into the window.
If you are reading this and thinking I'm a total moron for doing it this way, I'm open to ideas that are a lot simpler than what I'm doing right now.
Your code is the standard boilerplate for creating a window using c and win32 API functions. I recommend that you modify the message pump (it's the while loop in middle calling GetMessage). Instead do this:
Run an infinite loop
Peek a message
If the message is not there, execute your code
Else process messages including the quit message
Here's what the code should look like:
while (1)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
//Your game code
}
}
I also want to point, that while learning game programming using C and calling Win32 API is a worthy goal, you might want to look at XNA game studio.
The reason I am recommending it is because it is easier to learn and you can make much more interesting games faster. Here are a few links to get you started if you are interested.
http://joshua-w-wise78.livejournal.com/
http://www.krissteele.net/blogdetails.aspx?id=72
http://www.codeproject.com/KB/game/xna1.aspx
http://msdn.microsoft.com/en-us/library/bb203894.aspx
If your original program was a console app, that read input and printed output, then you will probably want to get input from your window to implement your game.
Instead of looking at it from the perspective of read user input from stdin then generate output to stdout, you have to think of it from the view of window messaging. So you need to process the WM_KEYDOWN messages, you can then use DrawText() to show the user input in your client area, or you could use a c++ RichEdit control. Once you process the WM_KEYDOWN messages you know what the user has pressed and then your program can do it's thing (maybe being triggered to process an accumalated buffer of characters whenever the WM_KEYDOWN key is equal to the enter key?) and write the output to your client area using DrawText() or send WM_KEYDOWN messages to your richedit window using SendMessage().
I think this is what you meant by a text based game, anyway, you just have to start thinking of doing everything by monitoring windows messages. Anything that the user does to your window, Windows will send a message to it to let it know.