Is there a better way to implement a word replacement feature in the Win32 API? - c++

I am creating a note pad application and I already have the basic stuff done (open file, save file, write to a file). I am now trying to add a word replacement feature just like the one in MS WORD which finds the inputted word and replaces all of its occurrences with the new word. Below is my code.
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define FILE_MENU_EXIT 2
#define FILE_MENU_BUILD 3
#define FILe_MENU_OPEN 4
#define FILE_MENU_SAVE 5
#define SEARCH_MENU_REPLACE 6
HMENU hMenu;
HMENU hDevMenu;
HWND hEdit,hCurrentPath;
HWND hOldWord,hNewWord;
int messagebox_id;
void replacerDialog(HINSTANCE);
void StillUnderConst();
void AddMenu(HWND);
void AddControls(HWND);
void AddDialogButton(HWND);
LRESULT CALLBACK WindowProcedure(HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst , LPSTR args, int ncmdshow)
{
WNDCLASSW wc = {0};
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.hCursor = LoadCursor(NULL,IDC_ARROW);
wc.hInstance = hInst;
wc.lpszClassName = L"mywindowclass";
wc.lpfnWndProc = WindowProcedure;
if(!RegisterClassW(&wc))
return -1;
replacerDialog(hInst);
CreateWindowW(L"mywindowclass",L"Note Book",WS_VISIBLE|WS_MINIMIZEBOX|WS_SYSMENU,50,50,1000,650,NULL,NULL,NULL,NULL);
MSG msg = {0};
while(GetMessage(&msg,NULL,NULL,NULL))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
void display_file(char* path)
{
FILE *file;
//this function helps us open and access the file passed in
file = fopen(path,"rb");
//this function helps as move to certain parts of the file thats why its a file pointer
fseek(file,0,SEEK_END);
//the ftell() function retuurn an integer type whic is stored in a var so that the file can later be read
//it is a needed to have the file size to be able to read fromt the file thats why we went for its size
int _size = ftell(file);
//this takes us back to the beginning of he file
rewind(file);
//this is thevar in which the files data will be kept
char *data = new char[_size+1];
//the fread function helps us to read from of specified file
//fread function requires us to know the file size to be able to read from it
fread(data,_size,1,file);
data[_size] ='\0';
SetWindowText(hEdit,data);
fclose(file);
}
void open_file(HWND hWnd)
{
OPENFILENAME ofn;
ZeroMemory(&ofn,sizeof(OPENFILENAME));
char file_name[100];
//the memory allocated to the the ofn struct
ofn.lStructSize = (sizeof(OPENFILENAME));
//the owner of the dialog
ofn.hwndOwner = hWnd;
//the path of the file being open
ofn.lpstrFile = file_name;
ofn.lpstrFile[0] = '\0';
//the max length being allocated to the path
ofn.nMaxFile = 100;
ofn.lpstrFilter = "All file\0*.*\0Text files\0*.txt\0C++ files\0*.cpp\0";
ofn.nFilterIndex = 1;
//creates an openfile dialog based on the kind of structure passed in as an argument
GetOpenFileName(&ofn);
SetWindowText(hCurrentPath,ofn.lpstrFile);
// MessageBox(NULL,ofn.lpstrFile,NULL,MB_OK);
display_file(ofn.lpstrFile);
}
void write_file(char* path)
{
FILE *file;
//this function helps us open and access the file passed in
file = fopen(path,"w");
int _size = GetWindowTextLength(hEdit);
char *data = new char[_size+1];
GetWindowText(hEdit,data,_size+1);
fwrite(data,_size+1,1,file);
fclose(file);
}
void save_file(HWND hWnd)
{
OPENFILENAME ofn;
ZeroMemory(&ofn,sizeof(OPENFILENAME));
char file_name[100];
//the memory allocated to the the ofn struct
ofn.lStructSize = (sizeof(OPENFILENAME));
//the owner of the dialog
ofn.hwndOwner = hWnd;
//the path of the file being open
ofn.lpstrFile = file_name;
ofn.lpstrFile[0] = '\0';
//the max length being allocated to the path
ofn.nMaxFile = 100;
ofn.lpstrFilter = "All file\0*.*\0Text files\0*.txt\0C++ files\0*.cpp\0";
ofn.nFilterIndex = 1;
//creates an openfile dialog based on the kind of structure passed in as an argument
GetSaveFileName(&ofn);
write_file(ofn.lpstrFile);
}
LRESULT CALLBACK DialogProcedure(HWND hWnd,UINT msg,WPARAM wp,LPARAM lp)
{
switch(msg)
{
case WM_CREATE:
AddDialogButton(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd,msg,wp,lp);
}
return 0;
}
void replacerDialog(HINSTANCE hInst)
{
WNDCLASSW dialog = {0};
dialog.hbrBackground = (HBRUSH)COLOR_WINDOW;
dialog.hCursor = LoadCursor(NULL,IDC_ARROW);
dialog.hInstance = hInst;
dialog.lpszClassName = L"mywindowdialog";
dialog.lpfnWndProc = DialogProcedure;
RegisterClassW(&dialog);
}
void displayDialog(HWND hWnd)
{
CreateWindowW(L"mywindowdialog",L"Replacer",WS_VISIBLE|WS_MINIMIZEBOX|WS_SYSMENU,50,50,300,300,hWnd,NULL,NULL,NULL);
}
void replacer(HWND hWnd)
{
char oword[100];
char nword[100];
wchar_t data[100000];
GetWindowText(hOldWord,oword,100);
GetWindowText(hNewWord,nword,100);
GetWindowText(hEdit,data,100000);
size_t startpos = data.find(oword);
data.replace(startpos,oword.length(),nword);
}
void AddDialogButton(HWND hWnd)
{
CreateWindowW(L"Static",L"Please enter the old word:",WS_CHILD|WS_VISIBLE,2,2,250,25,hWnd,NULL,NULL,NULL);
hOldWord = CreateWindowW(L"Edit",L"",WS_CHILD|WS_VISIBLE|WS_BORDER,10,20,250,30,hWnd,NULL,NULL,NULL);
CreateWindowW(L"Static",L"Please enter the new word:",WS_CHILD|WS_VISIBLE,2,100,250,25,hWnd,NULL,NULL,NULL);
hNewWord = CreateWindowW(L"Edit",L"",WS_CHILD|WS_VISIBLE|WS_BORDER,10,125,250,30,hWnd,NULL,NULL,NULL);
CreateWindowW(L"Button",L"Replace",WS_VISIBLE|WS_CHILD,220,220,70,40,hWnd,NULL,NULL,NULL);
}
LRESULT CALLBACK WindowProcedure(HWND hWnd,UINT msg,WPARAM wp,LPARAM lp)
{
switch(msg)
{
case WM_KEYDOWN:
if (wp == VK_ESCAPE)
{
MessageBoxW(NULL,L"You just left clicked", NULL,MB_OK);
}
//The WM_COMMAND is sent to the windowproc when a button or menu is clicked
case WM_COMMAND:
//WPARAM is an argument that represents the IDs of menus and button
switch(wp)
{
case SEARCH_MENU_REPLACE:
displayDialog(hWnd);
break;
case FILE_MENU_SAVE:
save_file(hWnd);
break;
case FILe_MENU_OPEN:
open_file(hWnd);
break;
case FILE_MENU_EXIT:
messagebox_id = MessageBoxW(NULL,L"Are you sure?",L"Attention",MB_YESNO|MB_ICONEXCLAMATION);
if(messagebox_id == IDYES)
{
DestroyWindow(hWnd);
}
break;
}
break;
//WM_CREATE function is called when evr the window is created ,this is to initiate all of the components such as buttons and menus
case WM_CREATE:
AddControls(hWnd);
AddMenu(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hWnd,msg,wp,lp);
}
}
void AddMenu(HWND hWnd)
{
hMenu = CreateMenu();
HMENU hFileMEnu = CreateMenu();
HMENU hSearchMenu =CreateMenu();
AppendMenu(hMenu,MF_POPUP,(UINT_PTR)hFileMEnu,"FILE");
AppendMenu(hMenu,MF_STRING,NULL,"EDIT");
AppendMenu(hMenu,MF_STRING,NULL,"VIEW");
AppendMenu(hMenu,MF_POPUP,(UINT_PTR)hSearchMenu,"SEARCH");
AppendMenu(hMenu,MF_STRING,(UINT_PTR)FILE_MENU_BUILD,"BUILD");
AppendMenu(hMenu,MF_STRING,NULL,"HELP");
//sub menus under the file menu
AppendMenu(hFileMEnu,MF_STRING,NULL,"NEW");
AppendMenu(hFileMEnu,MF_STRING,(UINT_PTR)FILe_MENU_OPEN,"OPEN");
AppendMenu(hFileMEnu,MF_STRING,(UINT_PTR)FILE_MENU_SAVE,"SAVE");
AppendMenu(hFileMEnu,MF_STRING,FILE_MENU_EXIT,"EXIT");
AppendMenu(hSearchMenu,MF_STRING,NULL,"FIND");
AppendMenu(hSearchMenu,MF_STRING,(UINT_PTR)SEARCH_MENU_REPLACE,"REPLACE");
AppendMenu(hSearchMenu,MF_STRING,NULL,"GO TO");
//this is used to declare where and what menu is to cretaed
//SetMenu(handler(usually window handler),what menu is being set);
SetMenu(hWnd,hMenu);
}
void AddControls(HWND hWnd)
{
hCurrentPath = CreateWindowW(L"Static",NULL,WS_CHILD|WS_VISIBLE|WS_BORDER,750,2,200,20,hWnd,NULL,NULL,NULL);
hEdit = CreateWindowW(L"Edit",NULL,WS_CHILD|WS_VISIBLE|WS_BORDER|WS_VSCROLL|ES_MULTILINE,5,25,980,550,hWnd,NULL,NULL,NULL);
}
I tried using the find() function to find the starting position of the word to be replaced then used the replace() function to replace the old word with the new word but all am getting is errors.
Below is the block for the replacer.
void replacer()
{
char oword[100];
char nword[100];
wchar_t data[100000];
GetWindowText(hOldWord,oword,100);
GetWindowText(hNewWord,nword,100);
GetWindowText(hEdit,data,100000);
size_t startpos = data.find(oword);
data.replace(startpos,oword.length(),nword);
}

I modified the code, and it runs well like this:
void replacer(HWND hWnd)
{
char nword[100];
std::string data;
std::string oword;
GetWindowText(hOldWord, (LPSTR)oword.c_str(), 100);
GetWindowText(hNewWord, nword, 100);
GetWindowText(hEdit, (LPSTR)data.c_str(), 100000);
size_t startpos = data.find(oword);
data.replace(startpos, oword.length(), nword);
}

Related

Why is D3Dcompiler_43.dll Loaded and Unloaded every frame (huge performance hit), but it only happens when I have two windows of different sizes open?

Why is D3Dcompiler_43.dll Loaded and Unloaded every frame?
Why does my two window direct-X 11 application drop from 2000 Hz to 12 Hz when I resize one of the windows?
In simplified sample I have attached code from, it starts with two identical sized windows at 2000 Hz, but if I change the size of either one, the frame rate of both goes to 12 Hz.
If I minimize either one, I get back to full speed, 4000Hz with one window.
When it is running at 12 Hz, I get the following Output Trace EVERY FRAME:
'Galaxies.exe' (Win32): Loaded 'C:\Windows\System32\D3Dcompiler_43.dll'
'Galaxies.exe' (Win32): Unloaded 'C:\Windows\System32\D3Dcompiler_43.dll'
This trace comes out when I call IDGXISwapChain->Present().
This trace does not come out when running 2000Hz.
I do not expect to need D3Dcompiler_43.dll at all, since I build my shaders at compile time, not run time. But if it did need it, then it should load it and keep it, not load each frame.
And if I make the window sizes match again, or minimize one, then the trace stops.
C++, Directx 11
My basic template is based on the Microsoft Sample "SimpleTexturePC".
Main changes from that template:
compile textures into program rather than reading at run time
compile shaders into program rather than reading at run time
extend DeviceResources to be able to support more than one window
by making arrays for all the resources, such as RenderTargetView
Extending Main.cpp to create more than one window, and have a WinProc for each.
Each of these unique WinProcs then calls a WinProcCommon with an "index" that identifies the window.
Adding a second camera for use on 2nd window
Adding a trace to the main application "Galaxies.cpp" so I could see the FPS.
(the rest of the main application behavior is not in simplified sample).
Main.cpp
//
// Main.cpp
//
#include ...
namespace
{
std::unique_ptr<Galaxies> g_game_p;
};
LPCWSTR g_szAppName0 = L"World1";
LPCWSTR g_szAppName1 = L"World2";
LPCWSTR g_szAppName2 = L"World3";
LRESULT CALLBACK WndProcWorld1(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK WndProcWorld2(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK WndProcWorld3(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK WndProcCommon(UINT, HWND, UINT, WPARAM, LPARAM);
// Entry point
int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
if (!XMVerifyCPUSupport())
return 1;
HRESULT hr = CoInitializeEx(nullptr, COINITBASE_MULTITHREADED);
if (FAILED(hr))
return 1;
g_game_p = std::make_unique<Galaxies>();
int border = getInvisableBorderWidth();
// Register / create window 1
{
// Register class
WNDCLASSEXW wcex = {};
wcex.cbSize = sizeof(WNDCLASSEXW);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProcWorld1;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIconW(hInstance, L"IDI_ICON1");
wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW);
wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
wcex.lpszClassName = L"WindowClass1";
wcex.hIconSm = LoadIconW(wcex.hInstance, L"IDI_ICON1");
if (!RegisterClassExW(&wcex)) // W implies unicode version.
return 1;
// Create window
int w, h;
g_game_p->GetDefaultWindowSize(w, h);
HWND hwnd = CreateWindowExW(0, wcex.lpszClassName, g_szAppName0, WS_OVERLAPPEDWINDOW,
50 - border, 50, w, h, nullptr, nullptr, hInstance, nullptr);
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(g_game_p.get()));
if (!hwnd)
return 1;
g_game_p->Initialize(kGameWindow1, hwnd, w, h); // this chooses non-fullscreen location, though we will go full screen in a sec...
ShowWindow(hwnd, SW_SHOWNORMAL);
}
// Register / create window 2
{
// Register class
WNDCLASSEXW wcex = {};
wcex.cbSize = sizeof(WNDCLASSEXW);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProcWorld2;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIconW(hInstance, L"IDI_ICON2");
wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW);
wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
wcex.lpszClassName = L"WindowClass2";
wcex.hIconSm = LoadIconW(wcex.hInstance, L"IDI_ICON2");
if (!RegisterClassExW(&wcex)) // W implies unicode version.
return 1;
// Create window
int w, h;
g_game_p->GetDefaultWindowSize(w, h);
HWND hwnd = CreateWindowExW(0, wcex.lpszClassName, g_szAppName1, WS_OVERLAPPEDWINDOW,
100 - border, 100, w + 00, h + 00, nullptr, nullptr, hInstance, nullptr);
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(g_game_p.get()));
if (!hwnd)
return 1;
g_game_p->Initialize(kGameWindow2, hwnd, w, h);
ShowWindow(hwnd, SW_SHOWNORMAL);
}
// Main message loop
MSG msg = {};
while (WM_QUIT != msg.message)
{
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
g_game_p->Tick();
}
}
g_game_p.reset();
CoUninitialize();
return static_cast<int>(msg.wParam);
}
// First parameter "index" used to differentiate the three windows.
LRESULT CALLBACK WndProcCommon(UINT index, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
WindowStruct& winInfo = g_deviceResources_p->GetWindowStruct(index);
auto galaxies_p = reinterpret_cast<Galaxies*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
switch (message)
{
case WM_PAINT:
if (winInfo.in_sizemove && galaxies_p)
{
RECT rc;
GetWindowRect(hWnd, &rc);
galaxies_p->OnWindowSizeChanged(index, rc.right - rc.left, rc.bottom - rc.top);
galaxies_p->Tick();
}
else
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
}
break;
case WM_MOVE:
if (galaxies_p)
{
galaxies_p->OnWindowMoved(index);
}
break;
case WM_SIZE:
if (wParam == SIZE_MINIMIZED)
{
if (!winInfo.minimized)
{
winInfo.minimized = true;
if (!winInfo.in_suspend && galaxies_p)
galaxies_p->OnSuspending();
winInfo.in_suspend = true;
}
}
else if (winInfo.minimized)
{
winInfo.minimized = false;
if (winInfo.in_suspend && galaxies_p)
galaxies_p->OnResuming();
winInfo.in_suspend = false;
}
else if (!winInfo.in_sizemove && galaxies_p)
{
RECT rc;
GetWindowRect(hWnd, &rc);
galaxies_p->OnWindowSizeChanged(index, rc.right - rc.left, rc.bottom - rc.top);
}
break;
case WM_ENTERSIZEMOVE:
winInfo.in_sizemove = true;
break;
case WM_EXITSIZEMOVE:
winInfo.in_sizemove = false;
if (galaxies_p)
{
RECT rc;
GetWindowRect(hWnd, &rc);
galaxies_p->OnWindowSizeChanged(index, rc.right - rc.left, rc.bottom - rc.top);
}
break;
case WM_GETMINMAXINFO:
if (lParam)
{
auto info = reinterpret_cast<MINMAXINFO*>(lParam);
info->ptMinTrackSize.x = 320;
info->ptMinTrackSize.y = 200;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case ... mouse cases
Mouse::ProcessMessage(message, wParam, lParam);
break;
case WM_KEYDOWN:
case WM_KEYUP:
case WM_SYSKEYUP:
Keyboard::ProcessMessage(message, wParam, lParam);
break;
case WM_MENUCHAR:
return MAKELRESULT(0, MNC_CLOSE);
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
// Windows procedure x3
LRESULT CALLBACK WndProcWorld1(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return WndProcCommon(kGameWindow1, hWnd, message, wParam, lParam);
}
LRESULT CALLBACK WndProcWorld2(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return WndProcCommon(kGameWindow2, hWnd, message, wParam, lParam);
}
LRESULT CALLBACK WndProcWorld3(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return WndProcCommon(kGameWindow3, hWnd, message, wParam, lParam);
}
// Exit helper
void ExitGame() noexcept
{
PostQuitMessage(0);
}
Galaxies.cpp
//
// Galaxies.cpp
//
#include ...
// Global variables
std::unique_ptr<DX::StepTimer> g_timer_p;
std::unique_ptr<DX::DeviceResources> g_deviceResources_p;
std::unique_ptr<DirectX::CommonStates> g_states_p;
std::unique_ptr<padInput> g_input_p;
std::unique_ptr<Camera> g_camera_p[2];
std::unique_ptr<HudText> g_text_p;
Galaxies::Galaxies() noexcept(false)
{
g_deviceResources_p = std::make_unique<DX::DeviceResources>(DXGI_FORMAT_B8G8R8A8_UNORM_SRGB);
g_deviceResources_p->RegisterDeviceNotify(this);
}
void Galaxies::Initialize(UINT index, HWND window, int width, int height)
{
static int once = true;
if (once)
{
g_deviceResources_p->CreateDeviceResources();
once = false;
}
switch (index)
{
case kGameWindow1:
{
g_timer_p = std::make_unique<DX::StepTimer>();
g_input_p = std::make_unique<padInput>();
g_camera_p[0] = std::make_unique<Camera>();
g_camera_p[1] = std::make_unique<Camera>();
g_text_p = std::make_unique<HudText>();
// PER OBJECT INITIALIZE
g_camera_p[0]->Initialize(0);
g_camera_p[1]->Initialize(1);
g_input_p ->Initialize();
g_text_p ->Initialize();
g_deviceResources_p->SetWindow(index, window, width, height);
g_deviceResources_p->CreateWindowSizeDependentResources(index);
OnDeviceRestored();
break;
}
case kGameWindow2:
case kGameWindow3:
default:
{
g_deviceResources_p->SetWindow(index, window, width, height);
g_deviceResources_p->CreateWindowSizeDependentResources(index);
break;
}
}
}
void Galaxies::GetDefaultWindowSize(int& width, int& height) const noexcept
{
...
}
void Galaxies::OnDeviceLost()
{
g_states_p.reset();
m_spPerFrameConstantBuffer.Reset();
g_text_p->OnDeviceLost();
}
void Galaxies::OnDeviceRestored()
{
CreateDeviceDependentResources();
CreateWindowSizeDependentResources(0);
CreateWindowSizeDependentResources(1);
WindowSizeChangeConfirmed(0);
WindowSizeChangeConfirmed(1);
g_text_p->OnDeviceRestored();
}
void Galaxies::OnSuspending()
{
}
void Galaxies::OnResuming()
{
g_timer_p->ResetElapsedTime();
}
void Galaxies::OnWindowMoved(UINT index)
{
auto r = g_deviceResources_p->GetOutputSize(index);
g_deviceResources_p->WindowSizeChanged(index, r.width, r.height);
}
// Pass in CURRENT (Last known) window size (icluding frame), so we can compare that with current size
// as read in deviceResources.
void Galaxies::OnWindowSizeChanged(UINT index, int width, int height)
{
// returns false if size unchanged
if (g_deviceResources_p->WindowSizeChanged(index, width, height))
{
CreateWindowSizeDependentResources(0);
WindowSizeChangeConfirmed(index);
}
}
void Galaxies::Tick()
{
UpdateRenderGPUTextures();
g_timer_p->Tick([&]()
{
UpdateInput();
UpdateCameras();
UpdateWorld();
});
RenderWorld(0);
if (!g_deviceResources_p->isWindowMinimized(1))
{
RenderWorld(1);
}
}
void Galaxies::Clear(int index)
{
// Clear the views.
auto context = g_deviceResources_p->GetD3DDeviceContext();
auto renderTargetView = g_deviceResources_p->GetRenderTargetView(index);
auto depthStencilView = g_deviceResources_p->GetDepthStencilView(index);
context->ClearRenderTargetView(renderTargetView, Colors::Black);
context->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
}
void Galaxies::CreateDeviceDependentResources()
{
auto device = g_deviceResources_p->GetD3DDevice();
g_states_p = std::make_unique<CommonStates>(device);
// Create constant buffers.
D3D11_BUFFER_DESC bufferDesc = {};
bufferDesc.Usage = D3D11_USAGE_DYNAMIC;
bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
bufferDesc.MiscFlags = 0;
bufferDesc.ByteWidth = sizeof(PerFrameConstantBuffer);
DX::ThrowIfFailed(device->CreateBuffer(&bufferDesc, nullptr, m_spPerFrameConstantBuffer.ReleaseAndGetAddressOf()));
}
// Allocate all memory resources that change on a window SizeChanged event.
void Galaxies::CreateWindowSizeDependentResources(UINT index)
{
// TODO: Initialize windows-size dependent objects here.
}
void Galaxies::UpdateRenderGPUTextures()
{
// Don't try to render anything before the first Update.
if (g_timer_p->GetFrameCount() == 0)
{
return;
}
}
void Galaxies::UpdateInput()
{
g_input_p->Update();
if (g_input_p->isKeyDownEdge(escape))
{
ExitGame();
}
}
void Galaxies::UpdateCameras()
{
g_camera_p[0]->Update();
// g_camera_p[1]->Update();
}
// Updates the world.
void Galaxies::UpdateWorld()
{
}
void Galaxies::RenderWorld(int index) // index 0, 1. not 2 (not edit window)
{
if (g_timer_p->GetFrameCount() == 0)
{
return;
}
Clear(index);
// Update Constants Buffer with per-frame variables.
// Though I now do this up to 3 times per frame - once per window.
auto context = g_deviceResources_p->GetD3DDeviceContext();
auto d3dBuffer = m_spPerFrameConstantBuffer.Get();
// Exclude 3rd window for now
if (index != 2)
{ // PRE-LOCK
MapGuard mappedResource(context, d3dBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0);
PerFrameConstantBuffer* data = reinterpret_cast<PerFrameConstantBuffer*>(mappedResource.get());
g_camera_p[index]->GetPerFrameData(data);
data->frameTime = g_timer_p->GetElapsedSeconds();
if (g_input_p->isButtonToggleSet(leftShoulder))
{
data->frameTime *= 5;
}
data->totalTime = g_timer_p->GetTotalSeconds();
int fps = (int)g_timer_p->GetFramesPerSecond();
char buffer[TEXT_NUM_OF_CHAR];
memset(buffer, 127, sizeof(buffer));
if (index == 0)
{
snprintf(&buffer[0 * TEXT_NUM_CHAR_PER_ROW], TEXT_NUM_CHAR_PER_ROW + 1, "Window 1 ");
}
else
{
snprintf(&buffer[0 * TEXT_NUM_CHAR_PER_ROW], TEXT_NUM_CHAR_PER_ROW + 1, "Window 2 ");
}
snprintf(&buffer[TEXT_NUM_CHAR_PER_ROW], TEXT_NUM_CHAR_PER_ROW + 1, "Galaxies V0.01 ");
snprintf(&buffer[2 * TEXT_NUM_CHAR_PER_ROW], TEXT_NUM_CHAR_PER_ROW + 1, " FPS = %d ", fps);
for (int i = 0; i < TEXT_NUM_OF_CHAR; i++)
{
data->alpha[4 * i] = buffer[i] - 0x20; // 0x20 is the first ascii char in our texture atlas. It is " "
}
} // UNLOCK (in mappedResource destructor)
context->VSSetConstantBuffers(CONSTANTS_PER_FRAME, 1, &d3dBuffer);
context->PSSetConstantBuffers(CONSTANTS_PER_FRAME, 1, &d3dBuffer);
auto renderTargetView = g_deviceResources_p->GetRenderTargetView(index);
auto depthStencilView = g_deviceResources_p->GetDepthStencilView(index);
context->OMSetRenderTargets(1, &renderTargetView, depthStencilView);
// Set the viewport.
auto viewport = g_deviceResources_p->GetScreenViewport(index);
context->RSSetViewports(1, &viewport);
if (index != 2)
{
g_text_p->Render();
}
g_deviceResources_p->Present(index);
}
void Galaxies::WindowSizeChangeConfirmed(UINT index)
{
auto size = g_deviceResources_p->GetOutputSize(index);
switch (index)
{
case (kGameWindow1):
g_camera_p[0]->OnWindowSizeChanged(size.width, size.height);
g_text_p ->OnWindowSizeChanged(size.width, size.height);
break;
case (kGameWindow2):
g_camera_p[1]->OnWindowSizeChanged(size.width, size.height);
break;
case (kGameWindow3):
break;
default:
break;
}
}
DeviceResources.cpp
//
// DeviceResources.cpp
//
#include ...
using namespace DirectX;
using namespace DX;
using Microsoft::WRL::ComPtr;
DeviceResources::DeviceResources(
DXGI_FORMAT backBufferFormat,
DXGI_FORMAT depthBufferFormat,
UINT backBufferCount,
D3D_FEATURE_LEVEL minFeatureLevel,
unsigned int flags) noexcept :
m_backBufferFormat{ backBufferFormat },
m_depthBufferFormat{ depthBufferFormat },
m_backBufferCount{backBufferCount},
m_d3dMinFeatureLevel(minFeatureLevel),
m_window(),
m_d3dFeatureLevel(D3D_FEATURE_LEVEL_9_1),
m_colorSpace(DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709),
m_options(flags | c_FlipPresent | c_AllowTearing),
m_deviceNotify(nullptr)
{
m_windowCount = 0;
for (int index = 0; index < c_MaxWindows; index++)
{
m_window[index] = nullptr;
m_WindowStruct[index] = WindowStruct();
m_screenViewport[index] = { 100, 100, 800, 600, 0, 1 };
}
}
void DeviceResources::CreateDeviceResources()
{
UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
CreateFactory();
...
// Determine feature levels
...
ComPtr<IDXGIAdapter1> adapter;
GetHardwareAdapter(adapter.GetAddressOf());
// Create the Direct3D 11 API device / context.
ComPtr<ID3D11Device> device;
ComPtr<ID3D11DeviceContext> context;
HRESULT hr = E_FAIL;
if (adapter)
{
hr = D3D11CreateDevice(
adapter.Get(),
D3D_DRIVER_TYPE_UNKNOWN,
nullptr,
creationFlags,
s_featureLevels,
featLevelCount,
D3D11_SDK_VERSION,
device.GetAddressOf(),
&m_d3dFeatureLevel,
context.GetAddressOf()
);
}
if (FAILED(hr))
{
// fall back to WARP device.
...
}
ThrowIfFailed(hr);
ThrowIfFailed(device.As(&m_d3dDevice));
ThrowIfFailed(context.As(&m_d3dContext));
}
// recreate every time the window size is changed.
void DeviceResources::CreateWindowSizeDependentResources(UINT index)
{
if (!m_window[index])
{
throw std::exception("need valid window handle");
}
// Clear the previous window size specific context.
ID3D11RenderTargetView* nullViews[] = { nullptr };
m_d3dContext->OMSetRenderTargets(_countof(nullViews), nullViews, nullptr);
m_d3dRenderTargetView[index].Reset();
m_d3dDepthStencilView[index].Reset();
m_renderTargetTexture[index].Reset();
m_depthStencilTexture[index].Reset();
m_d3dContext->Flush();
// Determine the render target size in pixels.
const UINT backBufferWidth = std::max<UINT>(static_cast<UINT>(m_WindowStruct[index].currentPos.width), 1u);
const UINT backBufferHeight = std::max<UINT>(static_cast<UINT>(m_WindowStruct[index].currentPos.height), 1u);
const DXGI_FORMAT backBufferFormat = (m_options & (c_FlipPresent | c_AllowTearing | c_EnableHDR)) ? NoSRGB(m_backBufferFormat) : m_backBufferFormat;
if (m_swapChain[index])
{
// If the swap chain already exists, resize it.
HRESULT hr = m_swapChain[index]->ResizeBuffers(
m_backBufferCount,
backBufferWidth,
backBufferHeight,
backBufferFormat,
(m_options & c_AllowTearing) ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0u
);
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
{
...
}
else
{
ThrowIfFailed(hr);
}
}
else
{
// Create a descriptor for the swap chain.
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
swapChainDesc.Width = backBufferWidth;
swapChainDesc.Height = backBufferHeight;
swapChainDesc.Format = backBufferFormat;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = m_backBufferCount;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
swapChainDesc.SwapEffect = (m_options & (c_FlipPresent | c_AllowTearing | c_EnableHDR)) ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
swapChainDesc.Flags = (m_options & c_AllowTearing) ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0u;
DXGI_SWAP_CHAIN_FULLSCREEN_DESC fsSwapChainDesc = {};
fsSwapChainDesc.Windowed = TRUE;
// Create a SwapChain
ThrowIfFailed(m_dxgiFactory->CreateSwapChainForHwnd(
m_d3dDevice.Get(),
m_window[index],
&swapChainDesc,
&fsSwapChainDesc,
nullptr, m_swapChain[index].ReleaseAndGetAddressOf()
));
ThrowIfFailed(m_dxgiFactory->MakeWindowAssociation(m_window[index], DXGI_MWA_NO_ALT_ENTER));
}
// Create a render target view of the swap chain back buffer.
ThrowIfFailed(m_swapChain[index]->GetBuffer(0, IID_PPV_ARGS(m_renderTargetTexture[index].ReleaseAndGetAddressOf())));
CD3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc(D3D11_RTV_DIMENSION_TEXTURE2D, m_backBufferFormat);
ThrowIfFailed(m_d3dDevice->CreateRenderTargetView(
m_renderTargetTexture[index].Get(),
&renderTargetViewDesc,
m_d3dRenderTargetView[index].ReleaseAndGetAddressOf()
));
if (m_depthBufferFormat != DXGI_FORMAT_UNKNOWN)
{
// Create a depth stencil view for use with 3D rendering if needed.
CD3D11_TEXTURE2D_DESC depthStencilDesc(
m_depthBufferFormat,
backBufferWidth,
backBufferHeight,
1,
1,
D3D11_BIND_DEPTH_STENCIL
);
ThrowIfFailed(m_d3dDevice->CreateTexture2D(
&depthStencilDesc,
nullptr,
m_depthStencilTexture[index].ReleaseAndGetAddressOf()
));
CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc(D3D11_DSV_DIMENSION_TEXTURE2D);
ThrowIfFailed(m_d3dDevice->CreateDepthStencilView(
m_depthStencilTexture[index].Get(),
&depthStencilViewDesc,
m_d3dDepthStencilView[index].ReleaseAndGetAddressOf()
));
}
// Set the 3D rendering viewport
m_screenViewport[index] = CD3D11_VIEWPORT(
0.0f,
0.0f,
static_cast<float>(backBufferWidth),
static_cast<float>(backBufferHeight)
);
}
void DeviceResources::SetWindow(UINT index, HWND window, int width, int height) noexcept
{
m_window[index] = window;
int indent = 50 * (index + 1);
RECTxywh windowPos = { indent - getInvisableBorderWidth(), indent, width, height };
m_WindowStruct[index].setWindowedByWindowPos(windowPos, 0, true);
}
bool DeviceResources::WindowSizeChanged(UINT index, int width, int height)
{
RECTxywh newRc = { 0, 0, width, height };
RECTxywh oldRc = { 0, 0, m_WindowStruct[index].currentPos.width, m_WindowStruct[index].currentPos.height };
if (newRc == oldRc)
{
// i.e. size didnt actually change
return false;
}
m_WindowStruct[index].setWindowedByWindowPos(newRc, 0, false);
CreateWindowSizeDependentResources(index);
return true;
}
// Recreate all device resources
void DeviceResources::HandleDeviceLost(UINT index)
{
if (m_deviceNotify)
{
m_deviceNotify->OnDeviceLost();
}
m_d3dDepthStencilView[index].Reset();
m_d3dRenderTargetView[index].Reset();
m_renderTargetTexture[index].Reset();
m_depthStencilTexture[index].Reset();
m_swapChain[index].Reset();
m_d3dContext.Reset();
m_d3dDevice.Reset();
m_dxgiFactory.Reset();
CreateDeviceResources();
CreateWindowSizeDependentResources(index);
if (m_deviceNotify)
{
m_deviceNotify->OnDeviceRestored();
}
}
int DeviceResources::getNumberOfMonitors()
{
ComPtr<IDXGIAdapter1> adapter;
GetHardwareAdapter(adapter.GetAddressOf());
IDXGIOutput* output = NULL;
int count = 0;
for (int i = 0; DXGI_ERROR_NOT_FOUND != adapter->EnumOutputs(i, &output); ++i)
{
count++;
}
return count;
}
RECTxywh DeviceResources::getMonitorSize(int monitor)
{
RECT position = getMonitorPos(monitor);
RECTxywh size(0, 0, position.right - position.left, position.bottom - position.top);
return size;
}
// 1 based index into monitors
RECT DeviceResources::getMonitorPos(int monitor)
{
ComPtr<IDXGIAdapter1> adapter;
GetHardwareAdapter(adapter.GetAddressOf());
RECT pos = {};
IDXGIOutput* output = NULL;
int count = -1;
if ( DXGI_ERROR_NOT_FOUND != adapter->EnumOutputs(monitor, &output) )
{
DXGI_OUTPUT_DESC outputDesc;
HRESULT hr = output->GetDesc(&outputDesc);
pos = outputDesc.DesktopCoordinates;
}
return pos;
}
RECT DeviceResources::getWindowPos(int index)
{
RECT windowRect;
HWND window = m_window[index];
GetWindowRect(window, &windowRect);
return windowRect;
}
void DeviceResources::setWindowPosition(int index, RECTxywh pos)
{
HWND hWnd = m_window[index];
SetWindowPos(hWnd, HWND_TOP, pos.left, pos.top, pos.width, pos.height, SWP_FRAMECHANGED)
ShowWindow(hWnd, SW_SHOWNORMAL)
}
bool DeviceResources::isWindowMinimized(int index)
{
return IsIconic(m_window[index]);
}
// Present the contents of the swap chain to the screen.
void DeviceResources::Present(int index)
{
HRESULT hr = E_FAIL;
if (m_options & c_AllowTearing)
{
hr = m_swapChain[index]->Present(0, DXGI_PRESENT_ALLOW_TEARING);
Print(L"TRACE: Present Present %i \n", index);
}
else
{
hr = m_swapChain[index]->Present(1, 0);
}
m_d3dContext->DiscardView(m_d3dRenderTargetView[index].Get());
if (m_d3dDepthStencilView[index])
{
// Discard the contents of the depth stencil.
m_d3dContext->DiscardView(m_d3dDepthStencilView[index].Get());
}
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
{
HandleDeviceLost(index);
}
else
{
ThrowIfFailed(hr);
if (!m_dxgiFactory->IsCurrent())
{
CreateFactory();
}
}
}
void DeviceResources::CreateFactory()
{
ThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(m_dxgiFactory.ReleaseAndGetAddressOf())));
}
void DeviceResources::GetHardwareAdapter(IDXGIAdapter1** ppAdapter)
{
...
}

Remove focus from SAVE button in OPENFILENAME win32?

Problem:
If the user holds the "enter" keyboard button and opens OPENFILENAME Save As Dialog, it will automatically save the file - dialog only blinks.
Desired result:
The user holds the "enter" keyboard button, opens OPENFILENAME Save As Dialog, nothing happens. He needs to click on the Save button or click again the "enter" keyboard button to save a file.
My current code:
OPENFILENAME ofn;
TCHAR szFile[260] = { 't','e','s','t'}; // example filename
// Initialize OPENFILENAME
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hWnd;
ofn.lpstrFile = szFile;
ofn.nMaxFile = sizeof(szFile);
//Files like: (ALL - *.*), (Text - .TXT)
ofn.lpstrFilter = _T("All\0*.*\0Text\0*.TXT\0");
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
if (GetSaveFileName(&ofn) == TRUE)
{
// file saved
}
Possible solution:
When ofn.lpstrFile is empty do nothing; Can't save file when there
is no filename
When ofn.lpstrFile has suggested filename then turn off focus on "Save" button or somehow ignore button enter holding.
I was trying to do that but failed, I am a beginner in CPP :(
Thanks for help
The easy solution to prevent data loss is to add the OFN_OVERWRITEPROMPT flag. This does not prevent the issue from happening if the suggested name does not already exist as a file.
To actually interact with the dialog you need OFN_ENABLEHOOK and a hook function. When you receive WM_NOTIFY, you can handle CDN_FILEOK to block the suggested name if not enough time has passed or maybe it is possible to change the focus in CDN_INITDONE.
Either way, you have to be mindful of the fact that you are changing how a common dialog works and this might anger some users.
Here is one way to do it. The actual delay to return the dialog to normal is something you have to decide for yourself.
const int btnid = 1337;
void CALLBACK resetsavedlgdefpush(HWND hWnd, UINT Msg, UINT_PTR idEvent, DWORD Time)
{
KillTimer(hWnd, idEvent);
HWND hDlg = GetParent(hWnd);
UINT id = LOWORD(SendMessage(hDlg, DM_GETDEFID, 0, 0));
if (id == btnid)
{
SendMessage(hDlg, DM_SETDEFID, IDOK, 0);
}
}
UINT_PTR CALLBACK mysavehook(HWND hWndInner, UINT Msg, WPARAM wParam, LPARAM lParam)
{
if (Msg == WM_NOTIFY)
{
OFNOTIFY*pOFN = (OFNOTIFY*) lParam;
if (pOFN->hdr.code == CDN_INITDONE)
{
HWND hDlg = GetParent(hWndInner);
CreateWindowEx(0, TEXT("BUTTON"), 0, BS_DEFPUSHBUTTON|BS_TEXT|WS_CHILD|WS_VISIBLE, 0, 0, 0, 0, hWndInner, (HMENU) btnid, 0, 0);
SendMessage(hDlg, DM_SETDEFID, btnid, 0);
PostMessage(hDlg, DM_SETDEFID, btnid, 0);
int keydelay = 0;
SystemParametersInfo(SPI_GETKEYBOARDDELAY, 0, &keydelay, 0);
SetTimer(hWndInner, 0, (250 * ++keydelay) * 5, resetsavedlgdefpush);
}
}
return 0;
}
...
ofn.Flags = OFN_PATHMUSTEXIST|OFN_EXPLORER|OFN_OVERWRITEPROMPT|OFN_ENABLESIZING|OFN_ENABLEHOOK;
ofn.lpfnHook = mysavehook;
MessageBox(ofn.hwndOwner, TEXT("Hold enter to test..."), 0, 0);
if (GetSaveFileName(&ofn) == TRUE) ...

Safe cancelling of CopyFileEx process

I've created a dialogbox with progress bar and a cancel button using CreateDialogParam to show status while copying several files (using CopyFileEx).
How do I cancel the process using CopyFileEx correctly, starting from pressing the cancel button in dialogbox? Is there anyway I can do it without using global variable? And How do I correctly handle the returned PROGRESS_CANCEL? I have provided questions in the code below to make clearer what help do I need.
//copy function
BOOL copy(HWND &hWnd, std::vector <FILECONSOLIDATEPARAMS> &vec)
{
//pass vector as lparam to dialogbox proc
LPARAM lp = reinterpret_cast<LPARAM>(&vec);
HWND hCopy = CreateDialogParam(GetModuleHandle(NULL),
MAKEINTRESOURCE(IDD_DIALOG1),
hwndmain, (DLGPROC)dlgboxcopyproc, lp);
static HWND hIDC_STATIC, hIDC_STATIC4;
hIDC_STATIC = GetDlgItem(hCopy, IDC_STATIC);
hIDC_STATIC4 = GetDlgItem(hCopy, IDC_STATIC4);
LPBOOL pbCancel = FALSE;
size_t s;
for (s = 0; s != vec.size(); s++)
{
SendMessage(hIDC_STATIC, WM_SETTEXT, 0, (LPARAM)vec[s].filename);
SendMessage(hIDC_STATIC4, WM_SETTEXT, 0,(LPARAM)vec[s].destination);
BOOL b = CopyFileEx(vec[s].filename, vec[s].destination,
&CopyProgressRoutine,(LPVOID)hCopy,pbCancel, NULL);
//how to catch and process PROGRESS_CANCEL?
if (!b)
{
DWORD dw = GetLastError();
ShowErrMsg(dw);
}
}
PostMessage(hCopy, WM_DESTROY, 0, 0);
return TRUE;
}
//dialogbox procedure
INT_PTR CALLBACK dlgboxcopyproc(HWND hWndDlg,UINT Msg,WPARAM wParam,LPARAM
lParam)
{
//translate passed lparam back to vector
std::vector<FILECONSOLIDATEPARAMS>& vect =
*reinterpret_cast<std::vector<FILECONSOLIDATEPARAMS>*>(lParam);
INITCOMMONCONTROLSEX _icex;
_icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
_icex.dwICC = ICC_PROGRESS_CLASS;
InitCommonControlsEx(&_icex);
static HWND hParent;
static HWND hIDCancel;
static HWND hIDC_PROGRESS1;
static HWND hIDC_STATIC;
hParent = GetParent(hWndDlg);
hIDCancel = GetDlgItem(hWndDlg, IDCANCEL);
hIDC_PROGRESS1 = GetDlgItem(hWndDlg, IDC_PROGRESS1);
switch (Msg)
{
case WM_INITDIALOG:
{
SendMessage(hIDC_PROGRESS1, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
}
return (INT_PTR)TRUE;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDCANCEL:
EndDialog(hWndDlg, FALSE); //how to make pbCancel = TRUE?
return (INT_PTR)TRUE;
}
}
break;
case WM_DESTROY:
{
DestroyWindow(hWndDlg);
}
}
return FALSE;
}
//copyprogressroutine callback function
DWORD CALLBACK CopyProgressRoutine(LARGE_INTEGER TotalFileSize,
LARGE_INTEGER TotalBytesTransferred, LARGE_INTEGER StreamSize,
LARGE_INTEGER StreamBytesTransferred, DWORD dwStreamNumber, DWORD
dwCallbackReason, HANDLE hSourceFile, HANDLE hDestinationFile, LPVOID
lpData)
{
HWND hWndDlg = (HWND)lpData;
static HWND hwndIDC_PROGRESS1;
hwndIDC_PROGRESS1 = GetDlgItem(hWndDlg, IDC_PROGRESS1);
DOUBLE Percentage = ((DOUBLE)TotalBytesTransferred.QuadPart /
(DOUBLE)TotalFileSize.QuadPart) * 100;
switch (dwCallbackReason)
{
case CALLBACK_CHUNK_FINISHED:
SendMessage(hwndIDC_PROGRESS1, PBM_SETPOS, (WPARAM) Percentage, 0);
break;
case CALLBACK_STREAM_SWITCH:
Percentage = 0;
break;
}
return PROGRESS_CONTINUE; //how to make conditional return PROGRESS_CANCEL?
}
code like
LPBOOL pbCancel = FALSE;
CopyFileEx(, pbCancel, )
senseless. really we simply pass 0 in place pbCancel and have no ability cancel operation.
we need alocate some variable (let name it bCancel) of type BOOL and pass pointer of this variable to CopyFileEx
something like this:
BOOL bCancel = FALSE;
CopyFileEx(, &bCancel, )
the CopyFileEx will be periodically query value of this variable by passed pointer and if it became true - break operation and return ERROR_REQUEST_ABORTED error.
the next - CopyFileEx not return until operation is complete - this is synchronous api - as result it can not be called from GUI thread (or it simply block GUI). need call it from separate thread.
so basic solution - allocate some data structure, here place BOOL bCancel, and other data, which we will be use during copy. we will access this data structure from 2 threads - gui thread (from dialog procedure) and from separate thread, which will call CopyFileEx. for correct implement this - need use reference counting on structure. the lpProgressRoutine need post messages to gui thread for notify it about progress (gui thread can move progress bars on this notification). dialog can containing for example Cancel button. when user click it - GUI thread simply set bCancel = TRUE, as result CopyFileEx abort operation on next chunk. for start copy - need start new thread, which call CopyFileEx. based on required logic - can do this from WM_INITDIALOG or say when user press some button in dialog
basic code:
struct CopyDlg
{
enum {
WM_COPYRESULT = WM_APP, WM_PROGRESS
};
struct ProgressData {
LARGE_INTEGER TotalFileSize;
LARGE_INTEGER TotalBytesTransferred;
LARGE_INTEGER StreamSize;
LARGE_INTEGER StreamBytesTransferred;
DWORD dwStreamNumber;
};
PCWSTR m_lpExistingFileName, m_lpNewFileName;
HWND m_hwnd, m_hwndFile, m_hwndStream;
ULONG m_shift;
LONG m_dwRefCount;
LONG m_hwndLock;
BOOL m_bCancel;
CopyDlg()
{
m_dwRefCount = 1;
}
void AddRef()
{
InterlockedIncrement(&m_dwRefCount);
}
void Release()
{
if (!InterlockedDecrement(&m_dwRefCount))
{
delete this;
}
}
void LockWnd()
{
InterlockedIncrement(&m_hwndLock);
}
void UnlockWnd()
{
if (!InterlockedDecrement(&m_hwndLock))
{
// want m_hwnd be valid at PostMessage(p->m_hwnd,) time
EndDialog(m_hwnd, 0);
}
}
void OnProgress(DWORD dwCallbackReason, ProgressData* p)
{
if (dwCallbackReason == CALLBACK_STREAM_SWITCH)
{
if (p->dwStreamNumber == 1)
{
m_shift = 0;
LONGLONG QuadPart = p->TotalFileSize.QuadPart;
while (QuadPart > MAXLONG)
{
m_shift++;
QuadPart >>= 1;
}
SendMessage(m_hwndFile, PBM_SETRANGE32, 0, (LPARAM)QuadPart);
SendMessage(m_hwndFile, PBM_SETPOS, 0, 0);
}
SendMessage(m_hwndStream, PBM_SETRANGE32, 0, (LPARAM)(p->StreamSize.QuadPart >> m_shift));
SendMessage(m_hwndStream, PBM_SETPOS, 0, 0);
}
else
{
SendMessage(m_hwndStream, PBM_SETPOS, (LPARAM)(p->StreamBytesTransferred.QuadPart >> m_shift), 0);
SendMessage(m_hwndFile, PBM_SETPOS, (LPARAM)(p->TotalBytesTransferred.QuadPart >> m_shift), 0);
}
}
ULONG StartCopy(PCWSTR lpExistingFileName, PCWSTR lpNewFileName)
{
m_bCancel = FALSE;
m_lpExistingFileName = lpExistingFileName;
m_lpNewFileName = lpNewFileName;
LockWnd();
AddRef();
if (HANDLE hThread = CreateThread(0, 0, reinterpret_cast<PTHREAD_START_ROUTINE>(CopyThread), this, 0, 0))
{
CloseHandle(hThread);
return NOERROR;
}
Release();
UnlockWnd();
return GetLastError();
}
static INT_PTR CALLBACK _DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_INITDIALOG)
{
SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lParam);
}
if (CopyDlg* p = reinterpret_cast<CopyDlg*>(GetWindowLongPtrW(hwndDlg, DWLP_USER)))
{
p->AddRef();
INT_PTR r = p->DialogProc(hwndDlg, uMsg, wParam, lParam);
p->Release();
return r;
}
return 0;
}
INT_PTR DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_NCDESTROY:
Release();
break;
case WM_DESTROY:
m_bCancel = TRUE;
break;
case WM_COMMAND:
switch (wParam)
{
case MAKEWPARAM(IDCANCEL, BN_CLICKED):
m_bCancel = TRUE;
break;
}
break;
case WM_CLOSE:
m_bCancel = TRUE;
UnlockWnd();
ShowWindow(hwndDlg, SW_HIDE);//for not get wm_close twice
break;
case WM_COPYRESULT:
UnlockWnd();
// lParam == error code from CopyFileExW
DbgPrint("CopyFileExW=%u\n", (ULONG)lParam);
break;
case WM_PROGRESS:
OnProgress((DWORD)wParam, reinterpret_cast<ProgressData*>(lParam));
delete (void*)lParam;
break;
case WM_INITDIALOG:
AddRef();
m_hwnd = hwndDlg;
m_hwndStream = GetDlgItem(hwndDlg, IDC_PROGRESS1);
m_hwndFile = GetDlgItem(hwndDlg, IDC_PROGRESS2);
m_hwndLock = 1;
StartCopy(L"**", L"**");
break;
}
return 0;
}
static ULONG CALLBACK CopyThread(CopyDlg* p)
{
PostMessage(p->m_hwnd, WM_COPYRESULT, 0, CopyFileExW(
p->m_lpExistingFileName, p->m_lpNewFileName,
reinterpret_cast<LPPROGRESS_ROUTINE>(CopyProgressRoutine),
p, &p->m_bCancel, 0) ? NOERROR : GetLastError());
p->Release();
return 0;
}
static DWORD CALLBACK CopyProgressRoutine(
__in LARGE_INTEGER TotalFileSize,
__in LARGE_INTEGER TotalBytesTransferred,
__in LARGE_INTEGER StreamSize,
__in LARGE_INTEGER StreamBytesTransferred,
__in DWORD dwStreamNumber,
__in DWORD dwCallbackReason,
__in HANDLE /*hSourceFile*/,
__in HANDLE /*hDestinationFile*/,
__in_opt CopyDlg* p
)
{
switch(dwCallbackReason)
{
case CALLBACK_CHUNK_FINISHED:
case CALLBACK_STREAM_SWITCH:
if (ProgressData* data = new ProgressData)
{
data->TotalFileSize = TotalFileSize;
data->TotalBytesTransferred = TotalBytesTransferred;
data->StreamSize = StreamSize;
data->StreamBytesTransferred = StreamBytesTransferred;
data->dwStreamNumber = dwStreamNumber;
if (!PostMessage(p->m_hwnd, WM_PROGRESS, dwCallbackReason, (LPARAM)data))
{
delete data;
return PROGRESS_CANCEL;
}
}
break;
}
// for debugging
//Sleep(3000);
//MessageBoxW(0,0,0,0);
return PROGRESS_CONTINUE;
}
};
if (CopyDlg* p = new CopyDlg)
{
DialogBoxParamW((HINSTANCE)&__ImageBase, MAKEINTRESOURCE(IDD_DIALOG1), HWND_DESKTOP, CopyDlg::_DialogProc, (LPARAM)p);
p->Release();
}

Weird array behavior in classes along with Windows DCs (C++)?

I'm working on creating a text based Windows game, and I am having a problem (I guess) with arrays not working the same within a class scope as within the main function. As far as I can tell it is some kind of interaction between a larger array class member (or large total amount of variables) and Windows creating a DC or other Windows API calls and/or variables.
What I want to do is a have a class called Map that contains a two dimensional array of Tiles. Tile is just a simple struct with basic tile information. I would like to make the array 256 x 256. This shouldn't be a problem as far as I can figure. Each Tile should be 32 bytes. That's 2 MB total for the array.
However, the game crashes when I declare a variable of the Map class in the main function, and then do things with Windows DCs. The return value seems to vary, In the current form, it usually returns 255, but I have also gotten "process terminated with status -1073741571". A 128 x 128 array does work in the class though. It also works fine if I remove either the array or the code in DisplayScreen. And as I implied, it also works if I just move the array of Tiles to the main function.
I'm honestly baffled. I have no idea what the difference would be. Nothing is going out of scope. Doesn't matter if it is a public or private member. Non dynamic class members should all get declared on the stack and it shouldn't work any differently in a class versus otherwise, right?
For other information, I am using Code::Blocks with the Min GW compiler. Everything is up to date. I am running Windows 10. My computer specs shouldn't be an issue either, but if it matters, I have 16 GB memory and a 4Ghz Athlon FX 8 core processor.
Edit: Here is the full code, so nothing is left out
Game.h:
#ifndef GAME_H_INCLUDED
#define GAME_H_INCLUDED
struct Tile
{
char chr[2];
int r[2], b[2], g[2];
bool solid;
bool translucent;
int opacity;
};
class Map
{
Tile tileMap[256][256];
public:
Map();
};
Map::Map()
{
int i, j;
for(i=0;i<256;i++)
{
for(j=0;j<256;j++)
{
tileMap[i][j].chr[0] = 'X';
tileMap[i][j].b[0] = 255;
tileMap[i][j].r[0] = 255;
tileMap[i][j].g[0] = 255;
tileMap[i][j].chr[1] = ' ';
tileMap[i][j].b[1] = 0;
tileMap[i][j].r[1] = 0;
tileMap[i][j].g[1] = 0;
tileMap[i][j].solid = false;
tileMap[i][j].translucent = false;
tileMap[i][j].opacity = 255;
}
}
}
main.cpp:
#include <windows.h>
#include "Game.h"
#define FRAMERATE 60
//Function declarations
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
void DisplayScreen(HWND pWnd, Map &pMap);
//Make the class name into a global variable
char strClassName[ ] = "GameApp";
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpstrArgument,
int nCmdShow)
{
HWND hWnd; //This is the handle for our window
MSG messages; //Here messages to the application are saved
WNDCLASSEX wndClassEx; //Data structure for the windowclass
Map test;
DWORD sysTimer;
DWORD sysPrevTime = 0;
DWORD timerDelta = 1000 / FRAMERATE;
//Get a handle for the whole screen
HDC hDC = GetDC(NULL);
//Initalize the Window structure
wndClassEx.hInstance = hThisInstance;
wndClassEx.lpszClassName = strClassName;
wndClassEx.lpfnWndProc = WindowProcedure;
wndClassEx.style = CS_DBLCLKS;
wndClassEx.cbSize = sizeof (WNDCLASSEX);
wndClassEx.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wndClassEx.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wndClassEx.hCursor = LoadCursor (NULL, IDC_ARROW);
wndClassEx.lpszMenuName = NULL; //No menu
wndClassEx.cbClsExtra = 0;
wndClassEx.cbWndExtra = 0;
wndClassEx.hbrBackground = CreateSolidBrush(RGB(0,0,0));
//Register the window class, and if it fails quit the program
if (!RegisterClassEx (&wndClassEx))
return 0;
//Create Window with registered window class
hWnd = CreateWindowEx (
0,
strClassName, //Class name
"Game Test", //Title Text
WS_OVERLAPPEDWINDOW, //default window type
0, //X pos of window at top left
0, //Y pos of window at top left
GetDeviceCaps(hDC, HORZRES), //Set window width to screen width
GetDeviceCaps(hDC, VERTRES), //Set window height to screen height
HWND_DESKTOP, //Child-window to desktop
NULL, //No menu
hThisInstance, //Program Instance handler
NULL); //No Window Creation data
//Removes borders from the window
SetWindowLong(hWnd, GWL_STYLE, WS_POPUP);
//Make the window visible on the screen
ShowWindow (hWnd, nCmdShow);
//Run the message and game loop
while (true)
{
while(PeekMessage(&messages,NULL,0,0, PM_REMOVE))
{
if (messages.message == WM_QUIT)
{
ReleaseDC(NULL, hDC);
DestroyWindow(hWnd);
return 0;
}
TranslateMessage(&messages);
DispatchMessage(&messages);
}
sysTimer = timeGetTime();
if (sysTimer >= (sysPrevTime + timerDelta) )
{
sysPrevTime = sysTimer;
DisplayScreen(hWnd, test);
}
}
}
//This function is called by the Windows function DispatchMessage()
LRESULT CALLBACK WindowProcedure (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage (0); //Send WM_QUIT to the message queue
break;
default:
return DefWindowProc (hWnd, message, wParam, lParam);
}
return 0;
}
void DisplayScreen(HWND pWnd, Map &pMap)
{
HDC hDC = GetWindowDC(pWnd);
HDC hdcBuf = CreateCompatibleDC(hDC);
HBITMAP hbmBuf = CreateCompatibleBitmap(hDC, 800, 600);
HFONT hMapFont = CreateFont(17,11,0,0,400,FALSE,FALSE,FALSE,ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY,DEFAULT_PITCH | FF_MODERN,"Lucida Console");
HFONT hTxtFont = CreateFont(17,11,0,0,400,FALSE,FALSE,FALSE,ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY,DEFAULT_PITCH | FF_MODERN,"Lucida Console");
SelectObject(hdcBuf, hbmBuf);
SelectObject(hdcBuf, hMapFont);
SetBkColor(hdcBuf, RGB(0,0,0));
SetTextColor(hdcBuf, RGB(255,255,255));
//Draw to the buffer
TextOut(hdcBuf, 10, 10, "Hello World #", 15);
//Tranfers the buffer to the Screen
BitBlt(hDC, 100, 100, 800, 600, hdcBuf, 0, 0, SRCCOPY);
//Release all object handles
DeleteObject(hTxtFont);
DeleteObject(hMapFont);
DeleteObject(hbmBuf);
DeleteDC(hdcBuf);
ReleaseDC(pWnd, hDC);
}
It crashes with even one instance of something creating a DC. It works fine otherwise creating and destroying the DCs and displaying the bitmap over and over again even if I leave it for an hour. Once I create that class with the large array in it though, it just dies.
I actually used to have the Display function as a class function and I moved it out because I thought that was the problem, but it wasn't.
Interestingly, if I change the declaration from 'Map test;' to 'Map* test = new Map;' and change the rest of the program appropriately, it works. Honestly though, doing that just seems kind of dumb, and I think that would slow everything down if I don't have a good reason to put everything on the heap. Plus, I don't like bandages. If there is a problem I'd rather fix it.
Any ideas?
You have a stack overflow (the condition, not the website).
The problem can be reproduced in this program:
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
Map test;
return 0;
}
It fails because it reaches stack limit.
Also tileMap[i][j].chr[2] is out of bound. It is declared as char chr[2]; valid index is 0 and 1. It can only go up to tileMap[i][j].chr[1]
Ditto b[], r[], and g[]
Change the Map class so that it allocates memory on heap and fix chr:
class Map
{
//Tile tileMap[256][256];
Tile **tileMap;
public:
Map();
~Map();
};
Map::Map()
{
int i, j;
tileMap = new Tile*[256];
for (i = 0; i < 256; i++)
tileMap[i] = new Tile[256];
for (i = 0; i<256; i++)
{
for (j = 0; j<256; j++)
{
//tileMap[i][j].chr[1] = 'X';
tileMap[i][j].chr[0] = 'X'; //<== meant to be 0?
tileMap[i][j].b[0] = 255;
tileMap[i][j].r[0] = 255;
tileMap[i][j].g[0] = 255;
//tileMap[i][j].chr[2] = ' ';
tileMap[i][j].chr[1] = ' '; //<== meant to be 1?
tileMap[i][j].b[1] = 0;
tileMap[i][j].r[1] = 0;
tileMap[i][j].g[1] = 0;
tileMap[i][j].solid = false;
tileMap[i][j].translucent = false;
tileMap[i][j].opacity = 255;
}
}
}
Map::~Map()
{
int i = 0;
for (i = 0; i < 256; i++)
delete[]tileMap[i];
delete[]tileMap;
}

Print text and images in C++ (WinAPI or QT)

In a basic program, I need to know how to make a text display widget and image display that can both be changed to different strings and images on command. These will display on a basic GUI.
Any specific help would be tremendously appreciated as I have been stuck on this for more than 10 weeks! Asking online here is my last resort.
I am making a basic program that asks questions (which is my text I want to print) and images for the questions come up underneath it. I have successfully made this program in a console command window (the code I will share below) but this of course meant no images could be displayed, so I am having to remake it in a GUI that supports images.
This is my first project ever done in C++, and only know the basics (the full extent of my limited knowledge got me through making that console command window program without help).
I first used WinAPI as it came with my computer in microsoft visual studio, and tried many different suggestions by other's similar questions already answered, but always either had one of two problems; 1. The code they supplied had many errors of which most read "_ is undefined" or wasn't imported properly, or 2. created basic text successfully but didn't specify how to change it after it had been created (I have had no successful image prints so far). I have tried 3 question/answers from cplusplus.com and 3 from stack overflow (links will be below), and all of them have had these 2 problems that are created from my lack of C++ bug fixing skills.
Suggestions using WinAPI would be prefferred over QT as I have no idea what I am doing in Qt and get double digit numbers worth of errors when I import code (even though I import the correct directories), whereas WinAPI doesn't get importing errors.
Code for command console program:
//G-Learning
//#author: James Monk
//#completed: 7/6/16
//#version 1.0
//These are the libraries (external files) to include at the start.
#include <cstdio>
#include <windows.h>
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <string>
using namespace std;
//Defining the [global] variables that will be used throughout the program
int running = 1;
int menuSelection;
int questionsLeft = 5;
int questionTextPicked;
int questionImagePicked;
int questionRandomised;
int score = 0;
int userInput;
int userInputDummy;
string stringPointer;
int intPointer;
string questionText[10] = {
"Would this most likely be, (1) an enemy (2) a player?\n",
"Is this (1) how many hearts the player has inside their body, or (2) a number of lives the player has?\n",
"Is this (1) a health bar, or (2) a set of red lights?\n",
"Is this (1) a money counter, or (2) a yellow ball counter?\n",
"Would this be a good object to touch with your character? (1) no or (2) yes?\n",
"What would this object likely have in it? (1) rewards, or (2) punishments\n",
"What does 'Game Over' mean? (1) your session has ended, or (2) the game is no longer playable\n",
"What would an icon like this likely be for? (1) show wheels, or (2) options\n",
"In a racing game, what would this be for? (1) health bar, or (2) fuel tank meter\n",
"What would this button likely do? (1) exit or cancel, or (2) mark a spot with an x\n" };
//Defining what happens with the different functions
void introduction() {
printf("\nG-Learning is a program built to teach people who know little about games the basic features of them. \n\n\
Questions will be asked, and you will need to answer them by choosing the correct answer.\n\
You will need to press 1, 2, or 3 followed by enter to choose.\n\n\
Press any number key followed by enter to return to the main menu.\n\n");
cin >> userInputDummy;
menuSelection = 0;
}
void start() {
printf("\nThe questions will now start, good luck!\n\n");
while (questionsLeft > 0) {
questionTextPicked = (rand() % 10);
if (questionTextPicked == 0) {
questionRandomised = (rand() % 4);
questionImagePicked = (7 + questionRandomised);
}
else if (questionTextPicked == 4) {
questionRandomised = (rand() % 3);
questionImagePicked = (11 + questionRandomised);
}
else {
questionImagePicked = questionTextPicked;
}
printf("after calculations, questionTextPicked is %d, questionRandomised is %d, and questionImagePicked is %d\n\n", questionTextPicked, questionRandomised, questionImagePicked);
//answering questions should be here
stringPointer = questionText[questionTextPicked];
intPointer = questionAnswer[questionImagePicked];
printf("answer is %d\n\n", intPointer);
printf("%s\n", stringPointer, intPointer);
printf("answer is %d\n\n", intPointer);
cin >> userInput;
if (userInput == questionAnswer[questionImagePicked]) {
printf("\nCorrect!\n\n");
score++;
}
else {
printf("\nIncorrect answer.\n\n");
}
questionsLeft--;
if (questionsLeft > 0) {
printf("%d questions to go!\n\n", questionsLeft);
}
if (questionsLeft == 0) {
printf("All questions have been answered, you scored %d/5.\n\nReturning you to the main menu\n\n", score);
score = 0;
}
} //end of start's while loop
menuSelection = 0;
} //end of start's function
void exit() {
menuSelection = 0;
running = 0;
}
//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//Main function, where everything starts
int main(int argc, char ** argv) {
while (running == 1) {
//Welcoming the user to the program, and asking them what they want to do (starts functions)
printf("welcome to G-Learning! Press a key to get started.\n1: Instructions\n2: Start\n3: Exit\n\n");
questionsLeft = 5; //Resetting this so that the start function can begin again
cin >> menuSelection;
if (menuSelection == 1) {
introduction();
}
else if (menuSelection == 2) {
start();
}
else if (menuSelection == 3) {
exit();
}
else {
printf("Invalid input, please use the 1, 2, or 3 key.");
}
}
return 0;
return EXIT_SUCCESS;
} //end of main function
Code for my best working WinAPI iteration (can print text, but not again on command; also without image functionality. Would like to know how to improve this one!):
//These are the libraries (external files) to include at the start.
#include <cstdio>
#include <windows.h>
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <string>
using namespace std;
int textHorizontal = 10;
int textVertical = 10;
//Variables used in making the program window
int numberInput;
char charictorInput;
string stringInput;
const char g_szClassName[] = "myWindowClass";
HINSTANCE hInstance;
// Function to get the size of the text
int GetTextSize(LPSTR a0)
{
for (int iLoopCounter = 0; ; iLoopCounter++)
{
if (a0[iLoopCounter] == '\0')
return iLoopCounter;
}
}
LPSTR TextArray[] = {
"Hello World"
};
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
TextOut(hdc,
// Location of the text
textHorizontal,
textVertical,
// Text to print
TextArray[0],
// Size of the text, my function gets this for us
GetTextSize(TextArray[0]));
EndPaint(hwnd, &ps);
}
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
int WINAPI WinMain(HINSTANCE hInstanace, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX WindowClass;
WindowClass.cbClsExtra = 0;
WindowClass.cbWndExtra = 0;
WindowClass.cbSize = sizeof(WNDCLASSEX);
WindowClass.lpszClassName = "1";
WindowClass.lpszMenuName = NULL;
WindowClass.lpfnWndProc = WndProc;
WindowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WindowClass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
WindowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WindowClass.style = 0;
WindowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
RegisterClassEx(&WindowClass);
HWND hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,
"1",
"G-Learning by James Monk",
WS_OVERLAPPEDWINDOW,
315, 115,
1080, 720,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hwnd, SW_SHOWNORMAL);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if (VK_ESCAPE == msg.wParam)
break;
}
return 0;
}
I am limited to only 2 links, so to view the 3 cplusplus.com pages I tried and the 3 stack overflow pages I tried, the links to them are on a google document here:
https://docs.google.com/document/d/1IX2hxzAVka3UmVkaAgv-gXv_cwwmP3FkTYQuFWrrqyE/edit?usp=sharing
How I installed QT into Microsoft Visual Studio:
https://www.youtube.com/watch?v=P6Mg8FpFPS8
Thank you for reading through my issue and even more in advance for helping!
HINSTANCE hInstance;
int WINAPI WinMain(HINSTANCE hInstanace...
CreateWindowEx(... hInstance ...)
You have spelling errors here. hInstanace and hInstance are not the same. Visual Studio should give you warnings. Set the warning level to 4. Address all the warnings and fix them. Only in rare cases is it okay to ignore warnings.
Moreover, in declaration of WNDCLASSEX WindowClass; you missed initializing hInstance, so the code will go nowhere. In C++ 14 you can do this
WNDCLASSEX WindowClass = {0}
This will initialize all members to zero. Try to always do this when declaring data on stack. Also avoid putting random code in to message loop.
#include <cstdio>
#include <iostream>
#include <windows.h>
Above header files are for C input/output, C++ input/output, and WinAPI. Usually you don't need them all. Pick one.
LPSTR TextArray[] = {
"Hello World"
};
Above is a character array, or just "text". If you access TextArray[0] it gives you the character 'H'
int GetTextSize(LPSTR a0)
{
for (int iLoopCounter = 0; ; iLoopCounter++)
{
if (a0[iLoopCounter] == '\0')
return iLoopCounter;
}
}
Above code is the equivalent of strlen. Your code is all over the place. You have C++14 classes like std::string, C header files, useless functions like GetTextSize which is mostly for learning C/C++, more advanced WinAPI, and some mention of Qt cross development. I recommend you spend more time with a C++ book. Here is example of what you are trying to do:
#include <windows.h>
#include <string>
#include <vector>
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HWND combobox;
static std::vector<std::string> vec = {
"Would this most likely be, (1) an enemy (2) a player?\n",
"Is this (1) how many hearts the player has inside their body, or (2) a number of lives the player has?\n",
"Is this (1) a health bar, or (2) a set of red lights?\n",
"Is this (1) a money counter, or (2) a yellow ball counter?\n",
"Would this be a good object to touch with your character? (1) no or (2) yes?\n",
"What would this object likely have in it? (1) rewards, or (2) punishments\n",
"What does 'Game Over' mean? (1) your session has ended, or (2) the game is no longer playable\n",
"What would an icon like this likely be for? (1) show wheels, or (2) options\n",
"In a racing game, what would this be for? (1) health bar, or (2) fuel tank meter\n",
"What would this button likely do? (1) exit or cancel, or (2) mark a spot with an x\n"
};
switch (msg)
{
case WM_CREATE:
combobox = CreateWindow("ComboBox", 0, CBS_DROPDOWNLIST | CBS_HASSTRINGS | WS_CHILD | WS_OVERLAPPED | WS_VISIBLE, 0, 100, 700, 30, hwnd, HMENU(100), 0, 0);
for (auto line : vec) SendMessage(combobox, CB_ADDSTRING, 0, LPARAM(line.c_str()));
break;
case WM_KEYDOWN:
if (wParam == VK_ESCAPE)
DestroyWindow(hwnd);
break;
case WM_COMMAND:
if (HIWORD(wParam) == CBN_SELCHANGE)
InvalidateRect(hwnd, NULL, TRUE);
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
int sel = SendMessage(combobox, CB_GETCURSEL, 0, 0);
if (sel < 0) sel = 0;
TextOut(hdc, 0, 0, vec[sel].c_str(), vec[sel].size());
EndPaint(hwnd, &ps);
break;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wcx = { 0 };
wcx.cbSize = sizeof(WNDCLASSEX);
wcx.lpszClassName = "ClassName";
wcx.lpfnWndProc = WndProc;
wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcx.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
wcx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
RegisterClassEx(&wcx);
HWND hwnd = CreateWindowEx(0, wcx.lpszClassName, "G-Learning by James Monk", WS_VISIBLE|WS_OVERLAPPEDWINDOW, 0,0,800,600, NULL, NULL, hInstance, NULL);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}