Preface: I'm fairly new to C++ and am just beginning to seriously program.
Post-Preface: I tried to post a link for the functions/pages I mention in this post, but Stack Overflow yelled at me because I don't have enough reputation to post more than two links.
I'm attempting to make a few simple GUIs in C++ with the Windows API using MinGW and the command line. I'm trying to change the window background, and one function which helps do this is the CreateSolidBrush function. This function requires the gdi32 library, but each time I try to compile/link to this library, I receive an error along the lines of "can't find that library, sucka".
Page1 and page2 provide useful information about MinGW's library functionality. Stack Overflow post # 5683058 and # 17031290 describe what I think are similar questions/problems to mine. I've searched far and wide for a simple and direct answer about how to link files/libraries from other directories (especially Windows libraries), but no luck in implementing the knowledge from these pages. Perhaps the answer is staring me right in the face, but my valiant efforts to "see the cat, draw the tiger" are in vain. It's possible that I'm entering the incorrect path/name (lib vs dll?), or maybe I'm completely overlooking something more fundamental (missing a header?). One command I've tried to use is
g++ -LC:\WINDOWS\System32 -lgdi32 gui.cpp
but this doesn't seem to work (note: source file named "gui.cpp").
Question 1: To start simple, what is the proper notation/command to link to individual header/source files which are not in the current directory?
Question 2: What is the proper notation/command to link to a library which is in the current directory?
Question 3: What is the proper notation/command to link to a library which is not in the current directory?
I realize these questions are sorta-kinda answered in a variety of ways on other pages, but they're often mingled with directions regarding Visual Studio, Eclipse, Code::Blocks, etc. and therefore unclear for the novices who forgo the luxuries of an IDE. I would appreciate a straightforward answer for your typical, run-of-the-mill noob. Many thanks in advance for any help or guidance.
I'll post my code, but I'm thinking only a couple of the first five lines are relevant:
#include <windows.h>
#include <string>
COLORREF desired_color = RGB(200,200,200);
HBRUSH hBrush = CreateSolidBrush(desired_color);
static char str_class_name[] = "MyClass";
static char str_titlebar[] = "My Window Title";
static int window_width = 300;
static int window_height = 300;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
static HINSTANCE program_global_instance = NULL;
int WINAPI WinMain(HINSTANCE program_current_instance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
program_global_instance = program_current_instance;
WNDCLASSEX window_class;
HWND window_handle;
MSG window_message;
window_class.cbSize = sizeof(WNDCLASSEX); // size of struct; always set to size of WndClassEx
window_class.style = 0; // window style
window_class.lpfnWndProc = WndProc; // window callback procedure
window_class.cbClsExtra = 0; // extra memory to reserve for this class
window_class.cbWndExtra = 0; // extra memory to reserve per window
window_class.hInstance = program_global_instance; // handle for window instance
window_class.hIcon = LoadIcon(NULL, IDI_APPLICATION); // icon displayed when user presses ALT+TAB
window_class.hCursor = LoadCursor(NULL, IDC_ARROW); // cursor used in the program
window_class.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); // brush used to set background color
window_class.lpszMenuName = NULL; // menu resource name
window_class.lpszClassName = str_class_name; // name with which to identify class
window_class.hIconSm = LoadIcon(NULL, IDI_APPLICATION); // program icon shown in taskbar and top-left corner
if(!RegisterClassEx(&window_class)) {
MessageBox(0, "Error Registering Class!", "Error!", MB_ICONSTOP | MB_OK);
return 0;
}
window_handle = CreateWindowEx(
WS_EX_STATICEDGE, // dwExStyle: window style
str_class_name, // lpClassName: pointer to class name
str_titlebar, // lpWindowName: window titlebar
WS_OVERLAPPEDWINDOW, // dwStyle: window style
CW_USEDEFAULT, // x: horizontal starting position
CW_USEDEFAULT, // y: vertical starting position
window_width, // nWidth: window width
window_height, // nHeight: window height
NULL, // hWndParent: parent window handle (NULL for no parent)
NULL, // hMenu: menu handle (Null if not a child)
program_global_instance, // hInstance : current window instance
NULL // lpParam -Points to a value passed to the window through the CREATESTRUCT structure.
);
if (window_handle == NULL) {
MessageBox(0, "Error Creating Window!", "Error!", MB_ICONSTOP | MB_OK);
return 0;
}
ShowWindow(window_handle, nCmdShow);
UpdateWindow(window_handle);
while(GetMessage(&window_message, NULL, 0, 0)) {
TranslateMessage(&window_message);
DispatchMessage(&window_message);
}
return window_message.wParam;
}
// window_handle: window ID
// uMsg: window message
// wParam: additional message info; depends on uMsg value
// lParam: additional message info; depends on uMsg value
LRESULT CALLBACK WndProc(
HWND window_handle,
UINT Message,
WPARAM wParam,
LPARAM lParam
) {
switch(Message) {
case WM_CLOSE:
DestroyWindow(window_handle);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(window_handle, Message, wParam, lParam);
}
return 0;
}
Question 1: To start simple, what is the proper notation/command to link to individual header/source files which are not in the current directory?
That's not linking, that's compiling/including (unless you compile those source files to object files, first).
So:
gcc {other options} -o gui.exe gui.cpp /path/to/source_file_one.cpp /path/to/source_file_n.cpp
or, compile the others first:
gcc {other options} -c -o source_file_one.o /path/to/source_file_one.cpp
gcc {other options} -c -o source_file_n.o /path/to/source_file_n.cpp
gcc {other options} -o gui.exe source_file_n.o source_file_one.o gui.cpp
-c tells gcc not to try and link things together, as this is done in the last step.
{other options} can contain -I{include dirs} to inform gcc where to look when you #include something.
Question 2: What is the proper notation/command to link to a library which is in the current directory?
See 3; -L. should work.
Question 3: What is the proper notation/command to link to a library which is not in the current directory?
You're doing it right, so far: -L tells gcc about paths to look into for libraries, and -l{libname} links against a library.
Related
I'm having an issue where if I get ProgMan to create a WorkerW window behind the desktop icons (as described by https://stackoverflow.com/a/56132585/5923516), it allows me to draw to it the first time, but if I stop it and then try and run it again, it fails to draw. By 'fails to draw', I mean that I don't see any errors, but it just doesn't do anything. I've also tried to debug it and none of the effected values change (i.e. the wallpaper_hwnd variable points to the same place, and none of the SDL functions return error values) I've verified this behaviour on both Windows 10 and 11, both using different video drivers. The only way I've found to fix this is to log out then log back in, which doesn't really help.
Once exited I also noticed that the background instantly changes back to the wallpaper picture/colour. But I don't know if that information is useful.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shellapi.h>
// Can also be <SDL.h> depending on the install of SDL
#include <SDL2/SDL.h>
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {
HWND ShellHandle = FindWindowEx(hwnd, NULL, "SHELLDLL_DefView", NULL);
HWND *ret = (HWND *) lParam;
if (ShellHandle) {
*ret = FindWindowEx(NULL, hwnd, "WorkerW", NULL);
}
return true;
}
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int ShowCmd) {
// Get the ProgMan Window
HWND progman = FindWindow("ProgMan", NULL);
// Get ProgMan to create a WorkerW
SendMessageTimeout(progman, 0x052C, 0, 0, SMTO_NORMAL, 1000, nullptr);
// Find the WorkerW that was spawned
HWND wallpaper_hwnd = nullptr;
EnumWindows(EnumWindowsProc, (LPARAM) &wallpaper_hwnd);
// Init SDL2
SDL_Init(SDL_INIT_VIDEO);
// Create an SDL Window from this
SDL_Window* sdl_window = SDL_CreateWindowFrom((void*)wallpaper_hwnd);
// Create SDL Renderer from the SDL Window
SDL_Renderer* renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
// Clear the window as a test
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
// Sleep for 1 second so that the change is actually visible
Sleep(1000);
// Clean up
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(sdl_window);
SDL_Quit();
// In my testing this doesn't fix it:
// DestroyWindow(wallpaper_hwnd);
return 0;
}
If anyone can work out why I'm getting these issues then I would greatly appreciate it.
EDIT:
After messing around a bit, I've found that wintabbing makes it work again. This still isn't a very good solution, however.
This question already has an answer here:
Getting "a function that returns 'auto' cannot be used before it is defined" while using CoreDispatcher::RunAsync in C++/WinRT project
(1 answer)
Closed 3 years ago.
I am trying to convert a small win32 desktop app for consumption of c++/winrt components and XAML islands. I have followed the numerous article on the subject and have indeed been able to compile and run the application with some basic XAML controls. My problem arose when using FileOpenPicker and the subsequent error message indicating that "a function that returns 'auto' cannot be used before it is defined". I have seen others have solved this by including the relevant header files but I have already done that and I am still getting the error.
I have included the header files ; - I tried including in the pch file and in the source file itself.
#include "pch.h"
#include <winrt/Windows.Storage.h>
#include <winrt/Windows.Storage.Pickers.h>
#include "360MediaPlayer.h"
using namespace winrt;
using namespace Windows::UI;
using namespace Windows::UI::Composition;
using namespace Windows::UI::Xaml::Hosting;
using namespace Windows::Foundation::Numerics;
using namespace Windows::Storage;
using namespace Windows::Storage::Pickers;
using namespace Windows::Media::Playback;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
#define MAX_LOADSTRING 100
// Global Variables:
HWND _hWnd;
HWND _childhWnd;
HINSTANCE _hInstance;
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
_hInstance = hInstance;
// The main window class name.
const wchar_t szWindowClass[] = L"Win32DesktopApp";
WNDCLASSEX windowClass = { };
windowClass.cbSize = sizeof(WNDCLASSEX);
windowClass.lpfnWndProc = WndProc;
windowClass.hInstance = hInstance;
windowClass.lpszClassName = szWindowClass;
windowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
//windowClass.hIconSm = LoadIcon(windowClass.hInstance, IDI_APPLICATION);
if (RegisterClassEx(&windowClass) == NULL)
{
MessageBox(NULL, L"Windows registration failed!", L"Error", NULL);
return 0;
}
_hWnd = CreateWindow(
szWindowClass,
L"Windows c++ Win32 Desktop App",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
if (_hWnd == NULL)
{
MessageBox(NULL, L"Call to CreateWindow failed!", L"Error", NULL);
return 0;
}
/* // Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_MY360MEDIAPLAYER, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
*/
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MY360MEDIAPLAYER));
// The call to winrt::init_apartment initializes COM; by default, in a multithreaded apartment.
winrt::init_apartment(apartment_type::single_threaded);
// Initialize the Xaml Framework's corewindow for current thread
WindowsXamlManager winxamlmanager = WindowsXamlManager::InitializeForCurrentThread();
// This DesktopWindowXamlSource is the object that enables a non-UWP desktop application
// to host UWP controls in any UI element that is associated with a window handle (HWND).
DesktopWindowXamlSource desktopSource;
// Get handle to corewindow
auto interop = desktopSource.as<IDesktopWindowXamlSourceNative>();
// Parent the DesktopWindowXamlSource object to current window
check_hresult(interop->AttachToWindow(_hWnd));
// This Hwnd will be the window handler for the Xaml Island: A child window that contains Xaml.
HWND hWndXamlIsland = nullptr;
// Get the new child window's hwnd
interop->get_WindowHandle(&hWndXamlIsland);
// Update the xaml island window size becuase initially is 0,0
SetWindowPos(hWndXamlIsland, 0, 200, 100, 800, 200, SWP_SHOWWINDOW);
//Creating the Xaml content
Windows::UI::Xaml::Controls::StackPanel xamlContainer;
xamlContainer.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() });
Windows::UI::Xaml::Controls::TextBlock tb;
tb.Text(L"Hello World from Xaml Islands!");
tb.VerticalAlignment(Windows::UI::Xaml::VerticalAlignment::Center);
tb.HorizontalAlignment(Windows::UI::Xaml::HorizontalAlignment::Center);
tb.FontSize(48);
MediaPlayer mpSphere = MediaPlayer();
FileOpenPicker foPicker = FileOpenPicker();
StorageFile file(foPicker.PickSingleFileAsync().get());
mpSphere.SetFileSource(file);
mpSphere.Play();
// xamlContainer.Children().Append(tb);
xamlContainer.UpdateLayout();
desktopSource.Content(xamlContainer);
//End XAML Island section
ShowWindow(_hWnd, nCmdShow);
UpdateWindow(_hWnd);
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
So the full error messsage I'm getting is the following:
Error C3779 'winrt::impl::consume_Windows_Foundation_IAsyncOperation<winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFile>,TResult>::get': a function that returns 'auto' cannot be used before it is defined'
despite the presence of the header files as can be seen above. If I remove the code dealing with the Media file and leave only the XAML stuff, it runs. Anyone know what I'm missing? I can provide the full project if needed.
auto Keyword simple ask the compiler at compilation time to deduce the type with whatever you are type to use it as, maybe a return from a function, or a hard coded POD type like an int.
the issue with your code is your missing your include for winrt foundation, which is required for your code since its accessing Async functions, honestly most WinRT code requires the include for foundation
#include <winrt/Windows.Foundation.h>
using namespace winrt;
using namespace Windows::Foundation;
since you forgot to include the foundation include, the compiler had no way to deduce the type for which the error was thrown.....
please note that auto keyword is great for functions in the form of trailing return types, but i highly suggest you don't use them for variables for a number of reasons, a few notable ones being odd bugs with vector iterators, where even when included properly, inside a template function the auto keyword wont be able to deduce the type and will cause an error,
template <typename T>
auto findSomething(:std::string name)
-> T*
{
// the code here causes an error since we are trying to deduce the var inside a
// template function using auto
auto _Found = ::std::find_if(somevector.begin(), somevector.end(), [&](::std::pair<::std::string, ::std::unique_ptr<class Someclass>>& pair){ return (pair.first = name) ? true : false; });
if(_Found != somevector.end())
{
return static_cast<T*>(_Found->second.get());
}
return nullptr;
}
Corrected
template <typename T>
auto findSomething(:std::string name)
-> T*
{
::std::vector<::std::pair<::std::string, ::std::unique_ptr<class Someclass>>>::iterator _Found = ::std::find_if(somevector.begin(), somevector.end(), [&](::std::pair<::std::string, ::std::unique_ptr<class Someclass>>& pair){ return (pair.first = name) ? true : false; });
if(_Found != somevector.end())
{
return static_cast<T*>(_Found->second.get());
}
return nullptr;
}
if your dont want to type ::std::vector<::std::pair<::std::string, ::std::unique_ptr<class someclass>>>::iterator every time simply type alias your type wit the using keyword using myvectortype = ::std::vector<::std::pair<::std::string, ::std::unique_ptr<class someclass>>> that way you only need to type myvectortype::iterator....
hope this helped you fix your code.
I'm trying to learn some windows and directX programming and I was messing around trying some different things. When suddently my the windows stopped appearing, even tho it was a successful build. I figured I must have messed something up and I undid everything until i got back to the place where I last managed to get the window to appear, but now when I run (with a successful build) it still doesn't show :( And I'm starting to run out of ideas what the problem could be, it so strange. One of the thing I did since last time I got it to work was add some libs directories but I have a hard time seeing how that would affect the program this way. Have anyone of you run in to this problem before, and if so how did you solve it? Here is the code of the func creating the window (and yes I am aware of the infinite loop, it shouldn't cause this problem tho, right?) :
ps. I have also tried changing between WINDCLASSEX and WINDCLASS, with all the functions that need to be change with it, didn't make any difference ds.
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow){
// Register the window class.
const wchar_t CLASS_NAME[] = L"Sample Window Class";
WNDCLASS wc = { };
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
RegisterClass(&wc);
RECT wr = {0, 0, 500, 400}; // set the size, but not the position
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE); // adjust the size
// Create the window.
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class
L"My first window", // Window text
WS_OVERLAPPEDWINDOW, // Window style
CW_USEDEFAULT, CW_USEDEFAULT,//position x,y
wr.right-wr.left, wr.bottom-wr.top,//width, height
NULL, // Parent window
NULL, // Menu
hInstance, // Instance handle
NULL // Additional application data
);
if (hwnd == NULL){
return 0;
}
InitD3D(hwnd);
// Run the message loop.
MSG msg = { };
while (true){
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else{
}
}
return 0;
}
looks like you need a ShowWindow call in there (unless InitD3D does that, you haven't shown the code)
windows are by default created non-visible, so that you can do various initialization without the user seeing what goes on
as an alternative you can create the window already visible, but generally it's a good idea to keep to a single convention
by the way, you can just use a standard int main, no need to use the Microsoft monstrosity
with GNU toolchain that's all, with Microsoft's tools you then have to tell the linker to accept the standard code, if you use the GUI subsystem, via linker option /entry:mainCRTStartup.
also, the call to non-blocking PeekMessage means your message loop will most likely be a CPU hog
instead, use blocking GetMessage
and remember to exit the loop when GetMessage returns 0 (which indicates a WM_QUIT message has been posted)
I am following a tutorial. And I am trying to draw a .bmp file to the screen. It builds with no errors but no image appears. according to the book, I should see the image pop up in random places. Below is my code. The author doesnt recommend this technique for drawing objects, he is just doing for demostration. In case your wondering.
The image is a 25x25 square red square.
#include <windows.h>
#include <iostream>
#include <time.h>
using namespace std;
const string APPTITLE = "Game Loop";
HWND window;
HDC device;
bool gameover = false;
void DrawBitmap(char *filename, int x, int y)
{
//load the bitmap image
HBITMAP image = (HBITMAP)LoadImage(0,"c.bmp", IMAGE_BITMAP,0,0, LR_LOADFROMFILE);
BITMAP bm;
GetObject(image, sizeof(BITMAP), &bm);
HDC hdcImage = CreateCompatibleDC(device);
SelectObject(hdcImage,image);
BitBlt(
device,
x,y,
bm.bmWidth, bm.bmHeight,
hdcImage,
0,0,
SRCCOPY);
//deletec the device context and bitmap
DeleteDC(hdcImage);
DeleteObject((HBITMAP)image);
}
bool Game_Init()
{
srand(time(NULL));
return 1;
}
void Game_Run()
{
if(gameover == true) return;
RECT rect;
GetClientRect(window, &rect);
//draw bitmap at random location
int x = rand() % (rect.right - rect.left);
int y = rand() % (rect.bottom - rect.top);
DrawBitmap("c.bmp",x,y);
}
void Game_End()
{
//free the device
ReleaseDC(window,device);
}
LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM WParam, LPARAM lparam)
{
switch(message)
{
case WM_DESTROY:
gameover = true;
PostQuitMessage(0);
break;
}
return DefWindowProc(hWnd, message, WParam, lparam);
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
//set the new windows properties
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC) WinProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName= APPTITLE.c_str();
wc.hIconSm = NULL;
return RegisterClassEx(&wc);
}
bool InitInstance(HINSTANCE hInstance, int nCmdShow)
{
//create a new window
window = CreateWindow(
APPTITLE.c_str(),
APPTITLE.c_str(),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
640,480,
NULL,
NULL,
hInstance,
NULL);
//was there an error creating the window ?
if(window == 0) return 0;
//display the window
ShowWindow(window, nCmdShow);
UpdateWindow(window);
device = GetDC(window);
return 1;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
//declare variables
MSG msg;
//register the class
MyRegisterClass(hInstance);
//initialize application
if(!InitInstance(hInstance, nCmdShow)) return 0;
//initilize the game
if(!Game_Init()) return 0;
//main message loop
while(!gameover)
{
if(PeekMessage(&msg,NULL, 0, 0,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Game_Run();
}
Game_End();
return msg.wParam;
}
I am not sure if its because I have the image in the wrong location. but if that was the case. I figure it would throw a error. I have the image placed at the root of my source folder.
[EDIT]
Also , when I rebuild, I get a warning which might be a cause but here is the warning
1>------ Rebuild All started: Project: Begin, Configuration: Debug Win32 ------
1>Deleting intermediate and output files for project 'Begin', configuration 'Debug|Win32'
1>Compiling...
1>main.cpp
1>c:\users\numerical25\documents\visual studio 2008\projects\begin\begin\main.cpp(39) : warning C4244: 'argument' : conversion from 'time_t' to 'unsigned int', possible loss of data
1>Compiling manifest to resources...
1>Microsoft (R) Windows (R) Resource Compiler Version 6.1.6723.1
1>Copyright (C) Microsoft Corporation. All rights reserved.
1>Linking...
1>LINK : C:\Users\numerical25\Documents\Visual Studio 2008\Projects\Begin\Debug\Begin.exe not found or not built by the last incremental link; performing full link
1>Embedding manifest...
1>Microsoft (R) Windows (R) Resource Compiler Version 6.1.6723.1
1>Copyright (C) Microsoft Corporation. All rights reserved.
1>Build log was saved at "file://c:\Users\numerical25\Documents\Visual Studio 2008\Projects\Begin\Begin\Debug\BuildLog.htm"
1>Begin - 0 error(s), 1 warning(s)
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========
The code does work, you just forgot to put your c.bmp in the right location. Put it in the project output folder (i.e. bin/Debug) if you're launching the program from Explorer or to the project folder if you're lanching the program from Visual Studio.
Your code seems to work, for a sufficiently loose definition of "work". Unless you've modified the code (quite a bit) in attempting to make it work, my advice would be to find a different tutorial to follow -- at least to me, most of what's there right now is quite unimpressive.
Just for example, Game_Run() passes the name of the bitmap file as a parameter to Draw_Bitmap(), but the parameter gets ignored, and Draw_Bitmap() uses a hard-coded file name instead.
The PeekMessage() loop makes the program look like it was written about 25 years ago, in the days of 16-bit Windows (and arguably not so great even then). There's rarely (if ever) a good reason to use PeekMessage() in a new code, and code that did use it is probably overdue for an overhaul. The main loop normally uses GetMessage(), and you can (for example) use SetTimer (with a duration of 0) to compute new coordinates for drawing the bitmap, and then calling InvalidateRect() to get it drawn. At one time there was a fair argument that the extra messages involved in this caused excessive overhead, but on a modern machine it'll keep up with the monitor refresh rate while using on the order of 10% of the CPU or less.
To keep CPU usage down, however, you want to restructure the code a bit -- right now, every time you draw, you're getting the window rectangle, reloading the BMP from disk, selecting the BMP into a compatible DC, and finally BitBlting to get the image to the screen. That's the part of the code where optimization will make a difference -- by strong preference, you want it to just call BitBlt and be done. The rest of the code should be moved elsewhere so it happens only when needed. For example, you can retrieve the window rectangle in response to WM_SIZE, and just save it in-between. Since you're using the same bitmap for the duration, load it once, and from them on just display it.
I'm trying to create a dialog box using C++ and the windows API, but I don't want the dialog defined in a resource file. I can't find anything good on this on the web, and none of the examples I've read seem to define the dialog programmatically.
How can I do this?
A simple example is fine. I'm not doing anything complicated with it yet.
Raymond Chen wrote a few posts about the dialog manager:
The dialog manager, part 1: Warm-ups
The dialog manager, part 2: Creating the frame window
The dialog manager, part 3: Creating the controls
The dialog manager, part 4: The dialog loop
The dialog manager, part 5: Converting a non-modal dialog box to modal
The dialog manager, part 6: Subtleties in message loops
The dialog manager, part 7: More subtleties in message loops
The dialog manager, part 8: Custom navigation in dialog boxes
The dialog manager, part 9: Custom accelerators in dialog boxes
If all you want to do is show a window with controls, it's possible to create a window without using resource (.rc) files / scripts.
This isn't the same as a dialog, but it might be easier than creating a dialog programmatically.
First, a few notes about how this is done:
Instead of designing the dialog in the rc file, you could manually use CreateWindow (or CreateWindowEx) to create child windows of a main window. (for .NET Windows Forms programmers, these windows are like Controls).
This process will not be graphical at all (you will need to manually type in the location and size of each window), but I think this can be a great way to understand how dialogs are created under the hood.
There are some disadvantages to not using a real dialog, namely that tab will not work when switching between controls.
About the example:
This example features a dialog box with two buttons, an edit box (.NET Windows Forms programmers would think of it as a TextBox), and a check box.
It has been tested under the following conditions:
x86 build
x64 build
Unicode build (UNICODE and _UNICODE defined)
Non-Unicode build (UNICODE and _UNICODE not defined)
Built with Visual Studio's C compiler
Built with Visual Studio's C++ compiler
OS: Windows 10 64 bit
Note: UNICODE
As of the time of writing, UTF-8 is still in beta for Windows 10
If you have not enabled this setting, you should assume that any char* is ACP, not UTF-8, this applies to standard library functions too
Even though in Linux, that same standard library function would be UTF-8.
Sadly, some C++ standard library features only work with char* (e.g., exception messages).
You can still use UTF-8 in Windows without the option set, you will just have to encode it back to UTF-16 before calling winapi functions.
Here is a reddit thread with a reply from somebody who claims to have worked on UTF-8 on Windows, it has some good information.
UNICODE in Windows means "UTF-16", not "UTF-8".
Using Unicode of some kind is strongly recommended for any version of Windows that is not very old.
Be aware that if you don't use Unicode, your program may be utterly unable to open file names containing Unicode characters, handle directories (e.g., usernames) with non-ACP characters, etc.
Using ACP functions (SendMessageA,etc) without somehow verifying that UTF-8 is enabled (it's disabled by default) is probably a bug.
For max portability/flexibility, I would recommend using UTF-16 and the W version of all API functions, translating from UTF-8 to UTF-16 at the last minute. Read this page very carefully.
Now for the code:
Note that a large amount of comments have been added to try to document the windows functions, I recommend copy/pasting this into a text editor, for best results.
// This sample will work either with or without UNICODE, it looks like
// it's recommended now to use UNICODE for all new code, but I left
// the ANSI option in there just to get the absolute maximum amount
// of compatibility.
//
// Note that UNICODE and _UNICODE go together, unfortunately part
// of the Windows API uses _UNICODE, and part of it uses UNICODE.
//
// tchar.h, for example, makes heavy use of _UNICODE, and windows.h
// makes heavy use of UNICODE.
#define UNICODE
#define _UNICODE
//#undef UNICODE
//#undef _UNICODE
#include <windows.h>
#include <tchar.h>
// I made this struct to more conveniently store the
// positions / size of each window in the dialog
typedef struct SizeAndPos_s
{
int x, y, width, height;
} SizeAndPos_t;
// Typically these would be #defines, but there
// is no reason to not make them constants
const WORD ID_btnHELLO = 1;
const WORD ID_btnQUIT = 2;
const WORD ID_CheckBox = 3;
const WORD ID_txtEdit = 4;
const WORD ID_btnShow = 5;
// x, y, width, height
const SizeAndPos_t mainWindow = { 150, 150, 300, 300 };
const SizeAndPos_t btnHello = { 20, 50, 80, 25 };
const SizeAndPos_t btnQuit = { 120, 50, 80, 25 };
const SizeAndPos_t chkCheck = { 20, 90, 185, 35 };
const SizeAndPos_t txtEdit = { 20, 150, 150, 20 };
const SizeAndPos_t btnShow = { 180, 150, 80, 25 };
HWND txtEditHandle = NULL;
// hwnd: All window processes are passed the handle of the window
// that they belong to in hwnd.
// msg: Current message (e.g., WM_*) from the OS.
// wParam: First message parameter, note that these are more or less
// integers, but they are really just "data chunks" that
// you are expected to memcpy as raw data to float, etc.
// lParam: Second message parameter, same deal as above.
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
// Create the buttons
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// Note that the "parent window" is the dialog itself. Since we are
// in the dialog's WndProc, the dialog's handle is passed into hwnd.
//
//CreateWindow( lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam
//CreateWindow( windowClassName, initial text, style (flags), xPos, yPos, width, height, parentHandle, menuHandle, instanceHandle, param);
CreateWindow( TEXT("Button"), TEXT("Hello"), WS_VISIBLE | WS_CHILD, btnHello.x, btnHello.y, btnHello.width, btnHello.height, hwnd, (HMENU)ID_btnHELLO, NULL, NULL);
CreateWindow( TEXT("Button"), TEXT("Quit"), WS_VISIBLE | WS_CHILD, btnQuit.x, btnQuit.y, btnQuit.width, btnQuit.height, hwnd, (HMENU)ID_btnQUIT, NULL, NULL);
// Create a checkbox
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
CreateWindow( TEXT("button"), TEXT("CheckBox"), WS_VISIBLE | WS_CHILD | BS_CHECKBOX, chkCheck.x, chkCheck.y, chkCheck.width, chkCheck.height, hwnd, (HMENU)ID_CheckBox, NULL, NULL);
// Create an edit box (single line text editing), and a button to show the text
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//Handle = CreateWindow(windowClassName, windowName, style, xPos, yPos, width, height, parentHandle, menuHandle, instanceHandle, param);
txtEditHandle = CreateWindow(TEXT("Edit"), TEXT("Initial Text"), WS_CHILD | WS_VISIBLE | WS_BORDER, txtEdit.x, txtEdit.y, txtEdit.width, txtEdit.height, hwnd, (HMENU)ID_txtEdit, NULL, NULL);
//CreateWindow( windowClassName, windowName, style, xPos, yPos, width, height, parentHandle, menuHandle, instanceHandle, param);
CreateWindow( TEXT("Button"), TEXT("Show"), WS_VISIBLE | WS_CHILD, btnShow.x, btnShow.y, btnShow.width, btnShow.height, hwnd, (HMENU)ID_btnShow, NULL, NULL);
// Create an Updown control. Note that this control will allow you to type in non-number characters, but it will not affect the state of the control
break;
// For more information about WM_COMMAND, see
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms647591(v=vs.85).aspx
case WM_COMMAND:
// The LOWORD of wParam identifies which control sent
// the WM_COMMAND message. The WM_COMMAND message is
// sent when the button has been clicked.
if (LOWORD(wParam) == ID_btnHELLO)
{
MessageBox(hwnd, TEXT("Hello!"), TEXT("Hello"), MB_OK);
}
else if (LOWORD(wParam) == ID_btnQUIT)
{
PostQuitMessage(0);
}
else if (LOWORD(wParam) == ID_CheckBox)
{
UINT checked = IsDlgButtonChecked(hwnd, ID_CheckBox);
if (checked)
{
CheckDlgButton(hwnd, ID_CheckBox, BST_UNCHECKED);
MessageBox(hwnd, TEXT("The checkbox has been unchecked."), TEXT("CheckBox Event"), MB_OK);
}
else
{
CheckDlgButton(hwnd, ID_CheckBox, BST_CHECKED);
MessageBox(hwnd, TEXT("The checkbox has been checked."), TEXT("CheckBox Event"), MB_OK);
}
}
else if (LOWORD(wParam) == ID_btnShow)
{
int textLength_WithNUL = GetWindowTextLength(txtEditHandle) + 1;
// WARNING: If you are compiling this for C, please remember to remove the (TCHAR*) cast.
TCHAR* textBoxText = (TCHAR*) malloc(sizeof(TCHAR) * textLength_WithNUL);
GetWindowText(txtEditHandle, textBoxText, textLength_WithNUL);
MessageBox(hwnd, textBoxText, TEXT("Here's what you typed"), MB_OK);
free(textBoxText);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
// hInstance: This handle refers to the running executable
// hPrevInstance: Not used. See https://blogs.msdn.microsoft.com/oldnewthing/20040615-00/?p=38873
// lpCmdLine: Command line arguments.
// nCmdShow: a flag that says whether the main application window
// will be minimized, maximized, or shown normally.
//
// Note that it's necessary to use _tWinMain to make it
// so that command line arguments will work, both
// with and without UNICODE / _UNICODE defined.
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
MSG msg;
WNDCLASS mainWindowClass = { 0 };
// You can set the main window name to anything, but
// typically you should prefix custom window classes
// with something that makes it unique.
mainWindowClass.lpszClassName = TEXT("JRH.MainWindow");
mainWindowClass.hInstance = hInstance;
mainWindowClass.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
mainWindowClass.lpfnWndProc = WndProc;
mainWindowClass.hCursor = LoadCursor(0, IDC_ARROW);
RegisterClass(&mainWindowClass);
// Notes:
// - The classname identifies the TYPE of the window. Not a C type.
// This is a (TCHAR*) ID that Windows uses internally.
// - The window name is really just the window text, this is
// commonly used for captions, including the title
// bar of the window itself.
// - parentHandle is considered the "owner" of this
// window. MessageBoxes can use HWND_MESSAGE to
// free them of any window.
// - menuHandle: hMenu specifies the child-window identifier,
// an integer value used by a dialog box
// control to notify its parent about events.
// The application determines the child-window
// identifier; it must be unique for all
// child windows with the same parent window.
//CreateWindow( windowClassName, windowName, style, xPos, yPos, width, height, parentHandle, menuHandle, instanceHandle, param);
CreateWindow( mainWindowClass.lpszClassName, TEXT("Main Window"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, mainWindow.x, mainWindow.y, mainWindow.width, mainWindow.height, NULL, 0, hInstance, NULL);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
// This code is based roughly on tutorial code present at http://zetcode.com/gui/winapi/
Further reading
The builtin set of window classes are rather limited, so you might be curious as to how you can define your own window classes ("Controls") using the Windows API, see the articles below:
Custom Controls in Win32 API: The Basics (Code Project)
The WINE emulator source serves as a good example of how the Windows API could be implemented, and how you can make your own window classes that imitate the behavior of builtin classes.
Zetcode.com's tutorials
NOTE: I originally intended this post to cover the creation of dialogs programmatically. Due to a mistake on my part I didn't realize that you can't just "show" a window as a dialog. Unfortunately I wasn't able to get the setup mentioned by Raymond Chen working. Even looking at WINE's source, it's not super clear.
Take a look at this toolkit that describes how to create dialogs without resource files.
It's in WTL. However, I'm sure you can pick apart the internals to achieve the same thing using the Win32 API directly.
Here you can find how to use Windows API dialogs without using resource files.
The Windows API (only the C Win32 API, no MFC) tutorial:
Windows API tutorial
Try to search MSDN for "dialog templates in memory".
See this for example: Dialog Boxes