I want to load an animated cursor stored in .ani format, which is described to be a RIFF archive/container, from memory without writing the memory to a temporary file. Thus far I am able to parse the .ani file structure and load the individual frames as a normal icon with the aid of CreateIconFromResourceEx LookupIconIdFromDirectoryEx
One of the problems that proofs difficult is the actual composition of these frames and the animation data (jiffy-rate etc) as there appears to be no entries in the Windows API to do so. Documentation or written knowledge over the subject seems to be limited to loading non-animated icons/cursors from memory.
Similar questions such as 'Load an embedded animated Cursor from the Resource' express the desire to load an animated cursor from an embeddable resource. However i am not able to reproduce a workable solution from that either. Partly because the resource compiler in visual studio 2008 & 2010 doesn't support .ani (only ico and cur) files and therefor embedding it simply results in a 1:1 copy of the bytes as they were in the original file as opposed to .cur and .ico files which get decomposed into multiple resources. The subsequent call to CreateIconFromResource as shown in both answers does not work because the data it expects is the icon/cursor data of a single directive in a icon archive and not a RIFF-based file structure.
To summarize I'm interested in any information regarding the structures of animated cursors (in memory) or otherwise relevant pointers that could assist me in pursuing my goal.
After re-evaluating loading an animated cursor from an embeddable resource as pointed out by mfc I have found a solution that allows me to load the cursors from an arbitrary memory address.
Data from an embeddable resource and data read from a file into memory are exactly identical. Therefor it suggests that CreateIconFromResource should work on normal regular memory as well. However there is one fundamental difference. Memory of the embeddable resources reside in special sections in the executable which are often padded to the nearest 4096-byte boundary. Memory allocated at runtime contains garbage values.
Now the solution that I found working exploits this by simply allocating a guard-band of zero-filled bytes. In my own test cases I have found that 8 is the minimum which also happens to be the size of a chunk in the riff container. Coincidence? What i suspect is that this is a bug and the algorithm happens to work for embeddable resources due to it's alignment restrictions within the dll/executable.
const int guardbandSize = 8;
FILE* fs = fopen("action.ani", "rb");
fseek(fs, 0,SEEK_END); int dwSize = ftell(fs); fseek(fs, 0,SEEK_SET);
char* memory = new char[dwSize + guardbandSize];
fread(memory, 1, dwSize, fs); memset(memory + dwSize, 0, guardbandSize);
fclose(fs);
cursor = (HCURSOR)CreateIconFromResource((PBYTE)memory,dwSize,FALSE,0x00030000);
delete memory;
Here is an overview of various ways to load an animated cursors.
#include <Windows.h>
#include <stdio.h>
#include "resource2.h"
void* hWnd;
bool visible = true;
bool running = true;
LRESULT CALLBACK WndProcInternal( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) ;
HCURSOR cursor = 0;
void main()
{
//Setup configuration
const int Width = 640, Height = 480;
const int Method = 4;
//Setup window class
WNDCLASS wcd;
wcd.style = CS_PARENTDC | CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wcd.lpfnWndProc = (WNDPROC)WndProcInternal;
wcd.cbClsExtra = 0;
wcd.cbWndExtra = 0;
wcd.hInstance = GetModuleHandle(NULL);
wcd.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wcd.hCursor = LoadCursor(NULL, IDC_ARROW);
wcd.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
wcd.lpszMenuName = NULL;
wcd.lpszClassName = TEXT("AnimatedIcon");
//Register the window class
if(!RegisterClass(&wcd))
{
MessageBox(NULL, TEXT("Window Registration Failed!"), TEXT("Error!"),MB_ICONEXCLAMATION | MB_OK);
FatalExit(-1);
}
//Create a window
if (!(hWnd=CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("AnimatedIcon"), TEXT("AnimatedIcon"),
WS_VISIBLE | WS_CAPTION | WS_MINIMIZEBOX | WS_THICKFRAME | WS_MAXIMIZEBOX | WS_SYSMENU,
0, 0, Width, Height, NULL, NULL, NULL, NULL)))
{
MessageBoxA(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION);
FatalExit(-1);
}
if( Method == 1 )
{
//Method 1: Load cursor directly from a file
cursor = LoadCursorFromFileA("action.ani");
}
if( Method == 2 )
{
//Method 2: Load cursor from an resource section in the executable.
cursor = LoadCursor(0, MAKEINTRESOURCE(IDR_ANICURSORS1));
}
if( Method == 3 )
{
//Method 3: Manually locate the resource section in the executable & create the cursor from the memory.
HINSTANCE hInst=GetModuleHandle(0);
HRSRC hRes=FindResourceA(hInst,MAKEINTRESOURCEA(IDR_ANICURSORS1),"ANICURSORS");
DWORD dwSize=SizeofResource(hInst,hRes);
HGLOBAL hGlob=LoadResource(hInst,hRes);
LPBYTE pBytes=(LPBYTE)LockResource(hGlob);
cursor = (HCURSOR)CreateIconFromResource(pBytes,dwSize,FALSE,0x00030000);
}
if( Method == 4 )
{
//Method 4: Load the cursor from a file into memory & create the cursor from the memory.
const int guardbandSize = 8;
FILE* fs = fopen("action.ani", "rb");
fseek(fs, 0,SEEK_END); int dwSize = ftell(fs); fseek(fs, 0,SEEK_SET);
char* memory = new char[dwSize + guardbandSize];
fread(memory, 1, dwSize, fs); memset(memory + dwSize, 0, guardbandSize);
fclose(fs);
cursor = (HCURSOR)CreateIconFromResource((PBYTE)memory,dwSize,FALSE,0x00030000);
delete memory;
}
//Set the cursor for the window and display it.
SetClassLong((HWND)hWnd, GCL_HCURSOR, (LONG)cursor);
while (running)
{
MSG wmsg;
if (PeekMessage(&wmsg, (HWND)hWnd, 0, 0, PM_REMOVE))
{
TranslateMessage(&wmsg);
DispatchMessage(&wmsg);
}
}
}
LRESULT CALLBACK WndProcInternal( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if( uMsg == WM_DESTROY )
{
PostQuitMessage(1);
running = false;
}
return (long)DefWindowProc((HWND)hWnd,uMsg,(WPARAM)wParam,(LPARAM)lParam);
}
Import your animated cursor as a custom resource.
Give it a text name, eg "MyType".
Then load the cursor with:
HCURSOR hCursor = LoadAnimatedCursor(IDR_MYTYPE1, _T("MyType"));
/* ======================================================== */
HCURSOR LoadAnimatedCursor(UINT nID, LPCTSTR pszResouceType)
{
HCURSOR hCursor = NULL;
HINSTANCE hInstance = AfxGetInstanceHandle();
if (hInstance)
{ HRSRC hResource = FindResource(hInstance, MAKEINTRESOURCE(nID), pszResouceType);
DWORD dwResourceSize = SizeofResource(hInstance, hResource);
if (dwResourceSize>0)
{ HGLOBAL hRsrcGlobal = LoadResource(hInstance, hResource);
if (hRsrcGlobal)
{ LPBYTE pResource = (LPBYTE)LockResource(hRsrcGlobal);
if (pResource)
{ hCursor = (HCURSOR)CreateIconFromResource(pResource, dwResourceSize, FALSE, 0x00030000);
UnlockResource(pResource);
}
FreeResource(hRsrcGlobal);
}
}
}
return hCursor;
}
Related
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) ...
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;
}
I'm trying to teach myself the win32 API by making a window and attaching an OpenGL context to it. In order to fetch the appropriate pixel format a call to ChoosePixelFormat must be made which should return a pixel format that the system supports and best meets my needs. When I check for errors everything goes smoothly until this function is called which stops execution and logs error 1150-ERR_OLD_WIN_VERSION which is supposed to mean that my version of windows does not support this function. This is obviously not the case and msdn confirms that this function runs on all versions of windows since windows 2000. Right now I'm running windows 7 x64 on my desktop and I made sure my video driver and os were fully updated. Lots of people seem to have had trouble with the pixel format functions but I have not found any with my problem so I decided to post here for help. Here is my full code; I have not tested it on any machines other than my own.
WinMain.cpp (the only non-default msvc lib this is linked with is opengl32.lib)
#include"Display.h"
#include<iostream>
#include<fstream>
MSG message;
DWORD error;
int status;
LRESULT CALLBACK WndProc(HWND hWindow, UINT message, WPARAM wParam, LPARAM lParam)
{ switch(message)
{case WM_CREATE:
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_KEYDOWN:
switch(wParam)
{case VK_ESCAPE:
PostQuitMessage(0);
return 0;}}
return DefWindowProc(hWindow, message, wParam, lParam);}
int MainLoop(Display d)
{
while((status = PeekMessage(&message, d.hWindow, 0, 0, PM_REMOVE)) != 0)
{
if (status == -1)
{
return -1;
}
DispatchMessage(&message);
}
return 0;
}
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
std::ofstream file("log.txt", std::ios::trunc);
Display window("TEST", hInstance, WndProc, 50, 50, 50, 50, NULL, NULL);
if(window.status == -1)
{ error = GetLastError();
file << error;
return 1;}
ShowWindow(window.hWindow, SW_SHOWNORMAL);
EnableWindow(window.hWindow, true);
MainLoop(window);
return 0;
}
Display.h (problem occurs in the class constructor)
#include <Windows.h>
class Display
{public:
Display(const char*, HINSTANCE, WNDPROC, int, int, int, int, DWORD, DWORD);
~Display();
HWND hWindow;
int status;
private:
WNDCLASSEX data;
HDC hDeviceContext;
HGLRC hGLContext;
PIXELFORMATDESCRIPTOR PFD;
int x, y, width, height;};
Display::Display(const char* title, HINSTANCE InstanceHandle, WNDPROC WindowProcedure, int ScreenPositionX, int ScreenPositionY, int WindowWidth, int WindowHeight, DWORD StyleFlags, DWORD ExtendedStyleFlags)
{ data.cbSize = sizeof(WNDCLASSEX);
data.style = CS_OWNDC;
data.lpfnWndProc = WindowProcedure;
data.cbClsExtra = 0;
data.cbWndExtra = 0;
data.hInstance = InstanceHandle;
data.hIcon = NULL;
data.hCursor = NULL;
data.hbrBackground = NULL;
data.lpszMenuName = NULL;
data.lpszClassName = "WIN1";
data.hIconSm = NULL;
RegisterClassEx(&data);
hWindow = CreateWindowEx(ExtendedStyleFlags, data.lpszClassName, title, StyleFlags | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, x = ScreenPositionX, y = ScreenPositionY, width = WindowWidth, height = WindowHeight, NULL, NULL, InstanceHandle, NULL);
PFD.nSize = sizeof(PIXELFORMATDESCRIPTOR);
PFD.nVersion = 1;
PFD.iPixelType = PFD_TYPE_RGBA;
PFD.iLayerType = PFD_MAIN_PLANE;
PFD.dwVisibleMask = 0;
PFD.dwLayerMask = 0;
PFD.dwDamageMask = 0;
PFD.dwFlags = PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL;
PFD.cAuxBuffers = 0;
PFD.bReserved = 0;
PFD.cColorBits = 24;
PFD.cAccumBits = 0;
PFD.cDepthBits = 32;
PFD.cStencilBits = 0;
PFD.cAlphaBits = 0;
PFD.cAccumAlphaBits = 0;
PFD.cAlphaShift = 0;
PFD.cBlueBits = 0;
PFD.cAccumBlueBits = 0;
PFD.cBlueShift = 0;
PFD.cGreenBits = 0;
PFD.cAccumGreenBits = 0;
PFD.cGreenShift = 0;
PFD.cRedBits = 0;
PFD.cAccumRedBits = 0;
PFD.cRedShift = 0;
hDeviceContext = GetDC(hWindow);
int pf = ChoosePixelFormat(hDeviceContext, &PFD); //throws error 1150, next three throw error 2000 because of this failing
SetPixelFormat(hDeviceContext, pf, &PFD);
hGLContext = wglCreateContext(hDeviceContext);
wglMakeCurrent(hDeviceContext, hGLContext);
if(GetLastError() != ERROR_SUCCESS)
{status = -1;}
else
{status = 0;}
return;}
Display::~Display()
{ wglMakeCurrent(NULL, NULL);
wglDeleteContext(hGLContext);
DestroyWindow(hWindow);
UnregisterClass(data.lpszClassName, data.hInstance);}
After I have tried all mentioned solutions I still had the same problem with ERR_OLD_WIN_VERSION after ChoosePixelFormat. In my case the problem was about the graphics card driver:
The system I'm working on uses an EVGA card with a GTX 770 GPU and yesterday I installed driver version 331.65. After that I got the same problems as the questioner. Installing the current Version 337.88 fixed the issue in my case. However ERR_OLD_WIN_VERSION seams to lead us in the wrong direction.
In your Display constructor, it looks like you don't initialize the hWindow member before you use it. That would be the value returned by CreateWindowEx.
Instead of testing the address of the GetLastError function, you should be calling it and testing its return value against ERROR_SUCCESS. I think this may be an oversight when you pasted the code, as you seem to be getting meaningful results from GetLastError (...).
UPDATE:
You might want to try something like:
#ifndef WINVER
# define WINVER 0x0500
#endif
Before #include <Windows.h>
That tells it to include all of the fields in the data structures that are new in Windows NT 5.0 (Windows 2000). Many of these structures determine the version of Windows they are targeting by the sizeof your structure, which will vary depending on how you have WINVER defined.
I was not able to boot up my older machine, but I did discover something when looking through the source code of SDL. It seems that they defined their own version of ChoosePixelFormat that loops through all available pixel formats using DescribePixelFormat and then compares them to the desired pixel format before choosing the best one. Since this is the exact same definition of windows's ChoosePixelFormat I suspect they had a good reason to make their own. Perhaps they knew it gave trouble in certain situations. Unfortunately since Microsoft Developer support is a myth, and barely anyone seems to care, this is as good an answer as I'll get for now. And since I've stopped caring too, this is probably the closest this question will ever get to an answer. Thnaks to those of you who tried to help.
I am creating a modeless property sheet using the following settings:
PROPSHEETHEADER pshdr = { 0 };
pshdr.dwSize = sizeof(PROPSHEETHEADER);
pshdr.dwFlags = PSH_NOAPPLYNOW | PSH_PROPSHEETPAGE |
PSH_MODELESS | PSH_USECALLBACK;
pshdr.pfnCallback = PropSheetProc;
pshdr.hwndParent = mGlobalState->trayWin;
pshdr.pszCaption = L"My Settings";
pshdr.nPages = mPages.size();
pshdr.ppsp = mWinPages;
In PropSheetProc, I catch the PSCB_PRECREATE message and modify the dialog template so that it gets the DS_CENTER style:
static int CALLBACK
PropSheetProc(HWND hwndDlg, // IN
UINT uMsg, // IN
LPARAM lParam) // IN
{
// Before the dialog is created, bless it with the DS_CENTER style.
if (uMsg == PSCB_PRECREATE) {
DLGTEMPLATE *dlgTemplate = (DLGTEMPLATE *)lParam;
_ASSERT(dlgTemplate);
dlgTemplate->style |= DS_CENTER;
}
return 0;
}
However this doesn't succeed in centering the dialog. I tried to catch PSCB_INITIALIZED instead and call a CenterWindow method on the hwnd passed to the PropSheetProc:
void
CenterWindow(HWND hwndWindow) // IN
{
int nX, nY, nScreenWidth, nScreenHeight;
RECT rectWindow;
nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
nScreenHeight = GetSystemMetrics(SM_CYSCREEN);
GetWindowRect(hwndWindow, &rectWindow);
nX = (nScreenWidth - (rectWindow.right - rectWindow.left)) / 2;
nY = (nScreenHeight - (rectWindow.bottom - rectWindow.top)) / 2;
SetWindowPos(hwndWindow, 0, nX, nY, 0, 0,
SWP_NOZORDER | SWP_NOSIZE);
}
But that doesn't work either!
Finally, I moved the CenterWindow call to directly after the PropSheet call:
mHwnd = (HWND)PropertySheet(&pshdr);
CenterWindow(mHwnd);
return mHwnd != NULL;
And this DOES work, though on a heavily loaded system, the dialog flashes from its initial position over to its final position, which is suboptimal.
Using the PropSheetProc to modify the DLGTEMPLATE structure seems intuitive. Actually, I can apply other window styles. But DS_CENTER seems to have no effect. So what am I doing wrong? There's many ways I can work around this brokennness but why is it broken in the first place?
Overload the InitialUpdate() of the CPropertySheet, and place the CenterWindow() call there. This happens before the window is drawn on the screen, but after it is created, so it's hwnd will be valid. There is nothing broken. The dialog has to be Created to have a valid HWND. Alternatively, if your working with the resource editor you can set it's property to centered, and it will achieve the same result. Why are you overloading the WinProc for the propertysheet? The whole reason MFC uses message maps was to eliminate the need to even touch WinProc's.
If your using raw win api in a SDK style application ::
Handle WM_CREATE in the WinProc of the property sheet. The LPCREATE struct in the LPARAM will contain a valid HWND from the create call. Just make sure you pass the proper parameters back to WndProcDefault() otherwise window creation will fail.
In MFC, is there an Open Folder Dialog? That is, rather than choosing a filename, it chooses a folder name? Ideally, I'd like it to be the way Visual Studio does it when navigating for a "Project Location" (when creating a new project), which looks very much like a normal file dialog. But I could make do with one of the vertical tree sort of interfaces if the former doesn't exist.
This code will get you a open folder dialog (this was taken from somewhere on the web but I don't really know where).
CString szSelectedFolder = _T("");
// This is the recommended way to select a directory
// in Win95 and NT4.
BROWSEINFO bi;
memset((LPVOID)&bi, 0, sizeof(bi));
TCHAR szDisplayName[_MAX_PATH];
szDisplayName[0] = '\0';
bi.hwndOwner = GetSafeHwnd();
bi.pidlRoot = NULL;
bi.pszDisplayName = szDisplayName;
bi.lpszTitle = _T("Select a folder");
bi.ulFlags = BIF_RETURNONLYFSDIRS;
// Set the callback function
bi.lpfn = BrowseCallbackProc;
LPITEMIDLIST pIIL = ::SHBrowseForFolder(&bi);
TCHAR szReturnedDir[_MAX_PATH];
BOOL bRet = ::SHGetPathFromIDList(pIIL, (TCHAR*)&szReturnedDir);
if (bRet)
{
if (szReturnedDir != _T(""))
{
szSelectedFolder = szReturnedDir;
}
LPMALLOC pMalloc;
HRESULT HR = SHGetMalloc(&pMalloc);
pMalloc->Free(pIIL);
pMalloc->Release();
}
you'll also have to implement this callback function:
TCHAR szInitialDir[_MAX_PATH];
// Set the initial path of the folder browser
int CALLBACK BrowseCallbackProc(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
// Look for BFFM_INITIALIZED
if (uMsg == BFFM_INITIALIZED)
{
SendMessage(hWnd, BFFM_SETSELECTION, TRUE, (LPARAM)szInitialDir);
}
return 0;
}