wchar_t **WinList Dynamic pointer array to character array - c++

I'm having issues trying to store wchar_t character arrays in a global array,
below is the code for what i want to do: -
wchar_t **WinList //Global array store
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
int NumMembers;
if (WinList == nullptr)
{
NumMembers = 0;
}
else
{
NumMembers = (sizeof(**WinList) / sizeof(wchar_t));
}
wchar_t class_name[300];
GetClassName(hwnd, class_name, 300);
WinList = new wchar_t * [NumMembers + 1];
WinList[NumMembers] = class_name;
return TRUE;
}
The error:
Unhandled exception at 0x765CE2C3 (usp10.dll) in Win32Project4.exe: 0xC0000005: Access violation reading location 0xCDCDCDCD." is occuring below at the TextOut function, WinList = 0x002802a0 {0xcdcdcdcd <Error reading characters of string.>} : -
case WM_PAINT:
if (WinList != nullptr)
{
PAINTSTRUCT ps;
HDC hDC = BeginPaint(hwnd, &ps);
for (int iLoop = 0; iLoop != sizeof(WinList); iLoop++)
{
TextOut(hDC, 5, iLoop*10, WinList[iLoop], (sizeof(WinList[iLoop]) / sizeof(wchar_t)));
}
}
break;
I have tried various variations of functions and code using things like malloc and mcscpy. I seem to however be misunderstand the scope of the pointer I think. I do not seem to be able to get my head around it. Any explanation would be much appreciated. I'm using VS 2013, and this is more of a learning concept rather than is there a better way. However I would also appreciate the 'better way' solution.
Regards,
HonkeyPig

Your main problem is that you store result of the call-back function in local variable that is immediately discarded on return..
Besides that
(sizeof(**WinList) / sizeof(wchar_t))
is exactly sizeof(pointer)/2 that is 2 on a 32 bit architecture....

Related

Win32 Scard.h c++ - having issues with the api [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 months ago.
Improve this question
I'm trying to look into smart card reading and I've immediately encountered an issue that I'm struggling with. I've called the SCardEstablishContext and I'm now trying to list the cards readers. I'm getting success and Its telling me there are 89 bytes worth of string data but the string isn't being written out to me. I'm not sure what the issue could be, my code is pretty much identical to the example code on msdn only I've gotten some memory using virtualalloc for the string to.
I've tried changing types and connecting, disconnecting smart card reader, restarting the system etc etc stepping through in the debugger for each and every change attempted. Same issue, either in getting 89 empty bytes or im hitting my asserts for not succeeding at getting the context or so on.
#include <Windows.h>
#include <stdint.h>
#include <winscard.h>
#include <stdio.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef uint32_t b32;
typedef int8_t i8;
typedef int16_t i16;
typedef int32_t i32;
typedef int64_t i64;
#define l_persist static
#define gvar static
#define internal static
#define KiloBytes(Value) ((Value) * 1024LL)
#define MegaBytes(Value) (KiloBytes(Value) * 1024LL)
#if INTERNAL
#define Assert(exp) if (!(exp)) {*((u8*)0) = 0;}
#define AssertWithMessage(exp, message) if (!(exp)) {OutputDebugString("\nAssertion failed: "); OutputDebugString(message); OutputDebugString("\n"); Assert(exp);}
#else
#define Assert(exp)
#define AssertWithMessage(exp, message)
#endif
#define U32_MAX 0xFFFFFFFF
b32 G_IsRunning = true;
LRESULT CALLBACK MainWindowCallback(HWND Window, UINT Message, WPARAM WParam, LPARAM LParam)
{
LRESULT Result = 0;
switch(Message)
{
case WM_CLOSE:
case WM_QUIT:
case WM_DESTROY:
{
G_IsRunning = false;
} break;
default:
{
Result = DefWindowProc(Window, Message, WParam, LParam);
}
}
return Result;
}
void MessagePump(HWND Window)
{
MSG Message = {};
u32 InputCount = 0;
while(PeekMessage(&Message, Window, 0, 0, PM_REMOVE))
{
switch(Message.message)
{
case WM_QUIT:
{
G_IsRunning = false;
} break;
default:
{
TranslateMessage(&Message);
DispatchMessage(&Message);
} break;
}
}
}
INT CALLBACK
WinMain(HINSTANCE Instance, HINSTANCE PrevInstance, LPSTR CommandLine, INT ShowCommand)
{
WNDCLASS WindowClass = {};
WindowClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
WindowClass.lpfnWndProc = MainWindowCallback;
WindowClass.hInstance = Instance;
WindowClass.lpszClassName = "MainWindowClass";
if (RegisterClass(&WindowClass))
{
HWND Window = CreateWindowEx(0,WindowClass.lpszClassName, "Main Window", WS_OVERLAPPEDWINDOW|WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,0,0,Instance, 0);
if (Window)
{
SCARDCONTEXT CardContext = U32_MAX;
LONG CardContextSuccess = SCardEstablishContext(SCARD_SCOPE_USER, 0, 0, &CardContext);
Assert(CardContextSuccess == SCARD_S_SUCCESS);
u8 *Memory = (u8*)VirtualAlloc(0, KiloBytes(1), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
u8 *MemoryHead = Memory;
LPSTR ReadersList = (char*)MemoryHead;
LPSTR ReadersListWip = 0;
DWORD ReadersListSize = 0;
LONG CardReadersListStatus = SCardListReadersA(CardContext, 0, (LPSTR)&ReadersList, &ReadersListSize);
Assert(ReadersList);
Assert(ReadersListSize);
switch(CardReadersListStatus)
{
case SCARD_S_SUCCESS:
{
ReadersListWip = ReadersList;
while ( '\0' != *ReadersListWip )
{
printf("Reader: %S\n", (wchar_t*)ReadersListWip );
// Advance to the next value.
ReadersListWip = ReadersListWip + wcslen((wchar_t *)ReadersListWip) + 1;
}
} break;
case SCARD_E_NO_READERS_AVAILABLE:
{
AssertWithMessage(CardReadersListStatus == SCARD_S_SUCCESS, "There were no card readers available");
G_IsRunning = false;
} break;
case SCARD_E_READER_UNAVAILABLE:
{
AssertWithMessage(CardReadersListStatus == SCARD_S_SUCCESS, "The card reader was unavailable");
G_IsRunning = false;
} break;
default:
{
AssertWithMessage(CardReadersListStatus == SCARD_S_SUCCESS, "Some other issue with card reader listing");
G_IsRunning = false;
}
}
while(G_IsRunning)
{
MessagePump(Window);
LPSCARDHANDLE CardHandle = 0;
DWORD ActiveProtocol = 0;
LONG CardConnectStatus = SCardConnectA(CardContext, ReadersList, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, (LPSCARDHANDLE)&CardHandle, &ActiveProtocol);
Assert(CardConnectStatus == SCARD_S_SUCCESS);
}
}
}
return 0;
}
Above is the code as it stands after my last batch of tests. I am quite rusty but I can't see why I'm getting a size back but not getting the strings.
Is there an alternative api for card reading?
I recognize that the loop is no good at the end there that was an artefact left from some previous efforts earlier on. I'm stepping through it anyway so I'm ignoring it for now.
Thanks to Raymond Chen's comments I've realised my errors and can progress in learning the SCARD api. Mostly my mistake, but I feel that the documentation on MSDN could have been clearer. Particularly in regards to the third argument to SCardListReaders() which is an in/out parameter. I did not realise that setting the parameter to zero would return the size and then would require a second call to the same function with the buffer of sufficient length. I failed to notice the SCARD_AUTOALLOCATE section of the documentation. Not entirely sure how I manage to overlook that but I somehow did. I found this function quite confusing for those reasons.
Credit for helping me realise my errors goes to the infamous Raymond Chen.
Below I've written some annotated demonstration code for anyone in future who might find the api confusing as I found earlier this evening.
LPSTR ReadersList; //im no longer initializing to zero here because a null argument tells the function to just return the size of the string(s).
#define one_call_version 0
#if one_call_version
DWORD ReadersListSize = SCARD_AUTOALLOCATE; //passing this will cause the function to allocate some memory for you and return the strings inside that block of memory.
LONG CardReadersListStatus = SCardListReadersA(CardContext, 0, (LPSTR)&ReadersList, &ReadersListSize);
//ReadersListSize now points to a populate block of memory that needs to be frees via SCardFreeMemory or process termination.
#else //ReadersList = (LPSTR)calloc(ReadersListSize, sizeof(char)); //ReadersList = (LPSTR)malloc(ReadersListSize);
DWORD ReadersListSize = 0;
LONG CardReadersListStatus = SCardListReadersA(CardContext, 0, 0, &ReadersListSize); //1ST// call with null 3rd argument will just get the size of the readers list string
//ReadersListSize should now be modified to contain the minimum required size of memory allocation to contain the string(s) in bytes.
ReadersList = (LPSTR)VirtualAlloc(0, ReadersListSize, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
CardReadersListStatus = SCardListReaders(CardContext, 0, ReadersList, &ReadersListSize); //2ND// call with the buffer of sufficient size for the string(s) as 3rd argument should populate the buffer
#endif //Should now have the ReadersList populated with the names of the connected smart card reader devices.

DirectSound crashes due to a read access violation when calling IDirectSoundBuffer8::Play (inside LFQueuePut, a dsound.dll internal function)

I am working on a game, and am sporadically observing crashes inside of dsound.dll.
This happens right after creating a IDirectSoundBuffer8 audio buffer, when calling the Play method on it. At this point I haven't written to the buffer or done anything to the sound system besides creating the audio device, setting the cooperative level, creating the audio buffer and starting to play.
All values returned by DirectSound indicate success, and even when I explicitely query the buffer for things like DSERR_BUFFERLOST, no sign of error is indicated.
This is the callstack:
After hunting this bug down by process of elimination, it seems to be a Windows/Driver issue. In short: DirectSound may crash your application if you reserve 10 TiB of address space. I'm using this address space for a debug allocator that helps hunting down use-after frees, and for some reason DirectSound seems to interact with this allocation.
I was able to produce the following repro, that crashes about every other execution (although I have also seen crash rates as low as 5% in my application). I was able to reproduced this on 2 PCs, and one other person who tried it was also able to reproduce. You have to execute this code in a debugger though, because otherwise you won't be able to distinguish a crash due to access violation from the execution finishing normally:
#include "dsound.h"
#include "assert.h"
//link against user32.lib, dsound.lib and dxguid.lib
LRESULT CALLBACK WindowProc(HWND handle, UINT message, WPARAM wParam, LPARAM lParam){
return DefWindowProcW(handle, message, wParam, lParam);
}
void main(){
VirtualAlloc(nullptr, 10llu * 1024 * 1024 * 1024 * 1024, MEM_RESERVE, PAGE_NOACCESS); //if you comment this out, it won't crash
auto application_instance = GetModuleHandle(NULL);
WNDCLASSEXW window_class;
ZeroMemory(&window_class, sizeof(window_class));
window_class.cbSize = sizeof(window_class);
window_class.style = CS_HREDRAW|CS_VREDRAW;
window_class.lpfnWndProc = WindowProc;
window_class.hInstance = application_instance;
window_class.lpszClassName = L"TEST_WINDOW_CLASS";
if(RegisterClassExW(&window_class) == 0)
assert(false);
auto window_handle = CreateWindowExW(0, window_class.lpszClassName, L"smashing", WS_OVERLAPPEDWINDOW|WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, 0, 0, application_instance, 0);
IDirectSound8* active_device = nullptr;
IDirectSoundBuffer8* active_buffer = nullptr;
if(DirectSoundCreate8(NULL, &active_device, NULL) != DS_OK)
assert(false);
if(active_device->SetCooperativeLevel(window_handle, DSSCL_PRIORITY) != DS_OK)
assert(false);
WAVEFORMATEX format_description;
format_description.wFormatTag = WAVE_FORMAT_PCM;
format_description.nChannels = 2;
format_description.nSamplesPerSec = 44100;
format_description.nAvgBytesPerSec = 44100 * 4;
format_description.nBlockAlign = 4;
format_description.wBitsPerSample = 16;
format_description.cbSize = 0;
DSBUFFERDESC buffer_description;
buffer_description.dwSize = sizeof(buffer_description);
buffer_description.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
buffer_description.dwBufferBytes = 44100 * 4;
buffer_description.dwReserved = 0;
buffer_description.lpwfxFormat = &format_description;
buffer_description.guid3DAlgorithm = DS3DALG_DEFAULT;
LPDIRECTSOUNDBUFFER buffer_before_cast = nullptr;
if(active_device->CreateSoundBuffer(&buffer_description, &buffer_before_cast, NULL) != DS_OK)
assert(false);
if(buffer_before_cast->QueryInterface(IID_IDirectSoundBuffer8, (void **)&active_buffer) != S_OK)
assert(false);
if(active_buffer->Play(0, 0, DSBPLAY_LOOPING) != DS_OK) //this is the place where it crashes more often than not
assert(false);
}
I have not found a solution to this issue, and since there is no real way to report such a bug to microsoft with any hopes of it actually getting fixed, I decided to put this on Stackoverflow so that other people hopefully don't waste as much time on it as I have. I will probably try using WASAPI instead next.

How can I show a window with the a name given as parameter in Windows in C++

I would like to make my software usable for Linux and Windows (Linux already works). Now I still need some functions so I can run the software on Windows, too.
I am currently trying to use the EnumWindows() function to get the window names and then show the window in the foreground (which matches the parameter).
static BOOL CALLBACK setWindowFocus(HWND hWnd, LPARAM lparam) {
int length = GetWindowTextLength(hWnd);
char* buffer = new char[length + 1];
GetWindowText(hWnd, buffer, length + 1);
std::string windowTitle(buffer);
// List visible windows with a non-empty title
if (IsWindowVisible(hWnd) && length != 0) {
// Check if it is the right Windowshandle
if ( windowTitle.compare(programname) == 0 ) <-- programname is a static variable
{
// Set application to the foreground
SetForegroundWindow(hWnd);
}
}
return TRUE;
}
Additionally, I used this to create the variable:
std::string programname;
And this to call it:
static void setWindowFocus(std::string programname)
{
std::cout << "Setting focus to window." << std::endl;
tempsavedProgramname=programname;
EnumWindows(setWindowFocus, NULL);
}
That is working, as long as it is in main(). But, I would like to have it in an extra class with some other functions (I would like to remove the static variable too, if possible).
Is there a way I can use the EnumWindows() function with an anonymous function, or something?
Can I use something like this to pass a string to the function:
EnumWindows(setWindowFocus, reinterpret_cast<LPARAM>(stringvariable));
Or, are there other ways which I can try to reach my goal?
Includes which I used for the code:
Windows.h
winuser.h
string
iostream
I hope that I did not forgot one.
Yes, you can use the LPARAM to pass a string variable into your callback, eg:
static BOOL CALLBACK setWindowFocus(HWND hWnd, LPARAM lparam) {
std::string &programname = *reinterpret_cast<std::string*>(lparam);
int length = GetWindowTextLength(hWnd);
char* buffer = new char[length + 1];
GetWindowText(hWnd, buffer, length + 1);
std::string windowTitle(buffer);
delete[] buffer; // <-- ADD THIS!
/* I would use this instead:
int length = GetWindowTextLength(hWnd);
std::string windowTitle(length+1, '\0');
windowTitle.resize(GetWindowText(hWnd, &windowTitle[0], length + 1));
*/
// List visible windows with a non-empty title
if (IsWindowVisible(hWnd) && (length != 0)) {
// Check if it is the right Windowshandle
if (windowTitle == programname)
{
// Set application to the foreground
SetForegroundWindow(hWnd);
return FALSE;
}
}
return TRUE;
}
static void setWindowFocus(std::string programname)
{
std::cout << "Setting focus to window." << std::endl;
EnumWindows(setWindowFocus, reinterpret_cast<LPARAM>(&programname));
}
And yes, you can use a C++11 lambda for the callback, rather than a static class method, but only if you use a non-capturing lambda, which is implicitly convertible to a function pointer (capturing lambdas are not). Fortunately, the LPARAM makes that a possibility, eg:
static void setWindowFocus(std::string programname)
{
std::cout << "Setting focus to window." << std::endl;
EnumWindows(
[](HWND hWnd, LPARAM lparam) -> BOOL {
std::string &programname = *reinterpret_cast<std::string*>(lparam);
// ...
},
reinterpret_cast<LPARAM>(&programname)
);
}
Now, that being said, there is a much simpler solution - since you already know the exact window text you are looking for, you can use FindWindow() instead of EnumWindows(), eg:
static void setWindowFocus(std::string programname)
{
std::cout << "Setting focus to window." << std::endl;
HWND hWnd = FindWindowA(NULL, programname.c_str());
if (hWnd != NULL) {
// Set application to the foreground
SetForegroundWindow(hWnd);
}
}
Here's the callback wrapped up in a class
class enum_windows {
protected:
virtual BOOL call_back(HWND hwnd) {
// Your code here
return TRUE;
}
public:
void start() {
EnumWindows([](HWND hwnd, LPARAM lParam) -> BOOL {
enum_windows * obj = reinterpret_cast<enum_windows *>(lParam);
return obj->call_back(hwnd);
}, reinterpret_cast<LPARAM>(this));
}
};
(You've already accepted an answer - I'm a slow typer 😄). I'll leave this here anyway.

follow official direct2d sample but got access violation error [duplicate]

This question already has answers here:
Direct2D : Unhandled Exception In WM_RESIZE switch case
(2 answers)
Closed 3 years ago.
Following the official tutorial of Direct2D (https://learn.microsoft.com/en-us/windows/win32/direct2d/direct2d-quickstart) to create a sample project with Visual Studio 2019. When running the code in x86, everything works fine while changing the platform to x64, I get an error that says: 'Exception thrown: read access violation.' in SampleD2D.cpp. (the line was commented in the code below)
the error is :
Exception thrown: read access violation.
this was 0xBB18F6E8.
LRESULT CALLBACK DemoApp::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT result = 0;
if (message == WM_CREATE)
{
LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
DemoApp* pDemoApp = (DemoApp*)pcs->lpCreateParams;
::SetWindowLongPtrW(
hwnd,
GWLP_USERDATA,
PtrToUlong(pDemoApp)
);
result = 1;
}
else
{
DemoApp* pDemoApp = reinterpret_cast<DemoApp*>(static_cast<LONG_PTR>(
::GetWindowLongPtrW(
hwnd,
GWLP_USERDATA
)));
bool wasHandled = false;
if (pDemoApp)
{
switch (message)
{
case WM_SIZE:
{
UINT width = LOWORD(lParam);
UINT height = HIWORD(lParam);
pDemoApp->OnResize(width, height); // throw the error!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
}
result = 0;
wasHandled = true;
break;
case WM_DISPLAYCHANGE:
{
InvalidateRect(hwnd, NULL, FALSE);
}
result = 0;
wasHandled = true;
break;
case WM_PAINT:
{
pDemoApp->OnRender();
ValidateRect(hwnd, NULL);
}
result = 0;
wasHandled = true;
break;
case WM_DESTROY:
{
PostQuitMessage(0);
}
result = 1;
wasHandled = true;
break;
}
}
if (!wasHandled)
{
result = DefWindowProc(hwnd, message, wParam, lParam);
}
}
return result;
}
Unfortunately, I'm no WinAPI expert but, out of curiosity, I googled a bit. Now, I'm quite sure about OPs problem:
::SetWindowLongPtrW(
hwnd,
GWLP_USERDATA,
PtrToUlong(pDemoApp)
);
specifically PtrToUlong(pDemoApp).
That might work for 32 bit applications but not for 64 bit.
long is in MS VC++ 32 bit – for x86 as well as x64 platform.
Hence, converting a pointer to long or unsigned long is good for making it wrong on x64 (as soon as the upper 32 bits are not 0 – which is probably hard to predict).
Googling into this direction I found e.g. PtrToUlong Q/A on gamedev.net with this (old) answer:
msdn, try to avoid using these because you are casting a pointer into an unsigned long. This may work correctly on 32-bit executables but if you compile in 64-bit you may have problems.
which supports my doubts.
According to MS doc. SetWindowLongPtrW function, the signature is:
LONG_PTR SetWindowLongPtrW(
HWND hWnd,
int nIndex,
LONG_PTR dwNewLong
);
So, this should fix it:
::SetWindowLongPtrW(
hwnd,
GWLP_USERDATA,
reinterpret_cast<LONG_PTR>(pDemoApp)
);
Please, note the MS doc. about LONG_PTR:
LONG_PTR
A signed long type for pointer precision. Use when casting a pointer to a long to perform pointer arithmetic.
This type is declared in BaseTsd.h as follows:
C++
#if defined(_WIN64)
typedef __int64 LONG_PTR;
#else
typedef long LONG_PTR;
#endif
Btw. I didn't understand as well
DemoApp* pDemoApp = reinterpret_cast<DemoApp*>(static_cast<LONG_PTR>(
::GetWindowLongPtrW(
hwnd,
GWLP_USERDATA
)));
According to doc. GetWindowLongPtrW function, the function returns LONG_PTR. So, why the static_cast<LONG_PTR>? A type cast should be always the last resort if absolutely necessary. (Although, I admit that WinAPI is probably unusable without.)

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;
}