I have a class, which I tried in another MFC project which compiled fine, but for some reason in this project it doesn't compile and complains about my wndproc function that is declared in a header file.
Below is the header file of the class I used in another MFC project. I had to comment out #include <windows.h> because it would say it can't be used in MFC, which wasn't the case in the other MFC project (what must be noted is that the other MFC project had precompiled headers).
skin.h
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// WINDOWS SKINNING TUTORIAL - by Vander Nunes - virtware.net
// This is the source-code that shows what is discussed in the tutorial.
// The code is simplified for the sake of clarity, but all the needed
// features for handling skinned windows is present. Please read
// the article for more information.
//
// skin.h : CSkin class declaration
// 28/02/2002 : initial release.
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#ifndef _SKIN_H_
#define _SKIN_H_
//#include <windows.h>
#include <afxwin.h>
// --------------------------------------------------------------------------
// The CSkin class will load the skin from a resource
// and subclass the associated window, so that the
// WM_PAINT message will be redirected to the provided
// window procedure. All the skin handling will be automatized.
// --------------------------------------------------------------------------
class CSkin
{
// --------------------------------------------------------------------------
// the skin window procedure, where the class
// will handle WM_PAINT and WM_LBUTTONDOWN automatically.
// --------------------------------------------------------------------------
friend LRESULT CALLBACK SkinWndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam);
private:
// the associated window handle
HWND m_hWnd;
// the associated CWnd window handle
CWnd * m_cwnd;
// the old window procedure
WNDPROC m_OldWndProc;
// skin region
HRGN m_rgnSkin;
// the internal skin device context handle
HDC m_dcSkin;
// bitmap and old bitmap from the device context
HBITMAP m_hBmp, m_hOldBmp;
// skin dimensions
int m_iWidth, m_iHeight;
// on|off toggle
bool m_bEnabled;
// tell the class if it has a window subclassed.
bool m_bHooked;
// skin retrieval helper
bool GetSkinData(int iSkinRegion, int iSkinBitmap);
public:
// ----------------------------------------------------------------------------
// constructor 1 - use it when you have not already created the app window.
// this one will not subclass automatically, you must call Hook() to subclass.
// will throw an exception if unable to initialize skin from resource.
// ----------------------------------------------------------------------------
CSkin(int iSkinRegion, int iSkinBitmap);
// ----------------------------------------------------------------------------
// constructor 2 - use it when you have already created the app window.
// this one will subclass the window automatically.
// will throw an exception if unable to initialize skin from resource.
// ----------------------------------------------------------------------------
CSkin(HWND hWnd, int iSkinRegion, int iSkinBitmap);
// ----------------------------------------------------------------------------
// destructor - just call the destroyer
// ----------------------------------------------------------------------------
virtual ~CSkin();
// ----------------------------------------------------------------------------
// destroy skin resources and free allocated resources
// ----------------------------------------------------------------------------
void Destroy();
// ----------------------------------------------------------------------------
// subclass a window.
// ----------------------------------------------------------------------------
bool Hook(HWND hWnd);
// ----------------------------------------------------------------------------
// subclass a window. The CWnd version
// ----------------------------------------------------------------------------
bool Hook(CWnd *cwnd);
// ----------------------------------------------------------------------------
// unsubclass the subclassed window.
// ----------------------------------------------------------------------------
bool UnHook();
// ----------------------------------------------------------------------------
// unsubclass the subclassed window. The CWnd version
// ----------------------------------------------------------------------------
bool UnHookCWnd();
// ----------------------------------------------------------------------------
// tell us if we have a window subclassed.
// ----------------------------------------------------------------------------
bool Hooked();
// ----------------------------------------------------------------------------
// toggle skin on/off.
// ----------------------------------------------------------------------------
bool Enable(bool bEnable);
// ----------------------------------------------------------------------------
// tell if the skinning is enabled
// ----------------------------------------------------------------------------
bool Enabled();
// ----------------------------------------------------------------------------
// return the skin bitmap width.
// ----------------------------------------------------------------------------
int Width();
// ----------------------------------------------------------------------------
// return the skin bitmap height.
// ----------------------------------------------------------------------------
int Height();
// ----------------------------------------------------------------------------
// return the skin device context.
// ----------------------------------------------------------------------------
HDC HDC();
// ----------------------------------------------------------------------------
// return the handle region.
// ----------------------------------------------------------------------------
HRGN HRGN();
// toggle skin on/off for Cwnd
bool EnableCWnd(bool bEnable);
};
#endif
This is the cpp file:
skin.cpp
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// WINDOWS SKINNING TUTORIAL - by Vander Nunes - virtware.net
// This is the source-code that shows what is discussed in the tutorial.
// The code is simplified for the sake of clarity, but all the needed
// features for handling skinned windows is present. Please read
// the article for more information.
//
// skin.cpp : CSkin class implementation
// 28/02/2002 : initial release.
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#include "skin.h"
// ----------------------------------------------------------------------------
// constructor 1 - use it when you have not already created the app window.
// this one will not subclass automatically, you must call Hook() and Enable()
// to subclass the app window and enable the skin respectively.
// will throw an exception if unable to initialize skin from resource.
// ----------------------------------------------------------------------------
CSkin::CSkin(int iSkinRegion, int iSkinBitmap)
{
// default starting values
m_bHooked = false;
m_OldWndProc = NULL;
// try to retrieve the skin data from resource.
if ( !GetSkinData(iSkinRegion, iSkinBitmap) )
throw ("Unable to retrieve the skin.");
}
// ----------------------------------------------------------------------------
// constructor 2 - use it when you have already created the app window.
// this one will subclass the window and enable the skin automatically.
// will throw an exception if unable to initialize skin from resource.
// ----------------------------------------------------------------------------
CSkin::CSkin(HWND hWnd, int iSkinRegion, int iSkinBitmap)
{
// default starting values
m_bHooked = false;
m_OldWndProc = NULL;
// initialize
CSkin(iSkinRegion, iSkinBitmap);
// subclass
Hook(hWnd);
// enable
Enable(true);
}
// ----------------------------------------------------------------------------
// destructor - just call the destroyer
// ----------------------------------------------------------------------------
CSkin::~CSkin()
{
Destroy();
}
// ----------------------------------------------------------------------------
// destroy skin resources and free allocated resources
// ----------------------------------------------------------------------------
void CSkin::Destroy()
{
// unhook the window
UnHook();
// free bitmaps and device context
if (m_dcSkin) { SelectObject(m_dcSkin, m_hOldBmp); DeleteDC(m_dcSkin); m_dcSkin = NULL; }
if (m_hBmp) { DeleteObject(m_hBmp); m_hBmp = NULL; }
// free skin region
if (m_rgnSkin) { DeleteObject(m_rgnSkin); m_rgnSkin = NULL; }
}
// ----------------------------------------------------------------------------
// toggle skin on/off - must be Hooked() before attempting to enable skin.
// ----------------------------------------------------------------------------
bool CSkin::Enable(bool bEnable)
{
// refuse to enable if there is no window subclassed yet.
if (!Hooked()) return false;
// toggle
m_bEnabled = bEnable;
// force window repainting
InvalidateRect(m_hWnd, NULL, TRUE);
return true;
}
// ----------------------------------------------------------------------------
// tell if the skinning is enabled
// ----------------------------------------------------------------------------
bool CSkin::Enabled()
{
return m_bEnabled;
}
// ----------------------------------------------------------------------------
// hook a window
// ----------------------------------------------------------------------------
bool CSkin::Hook(HWND hWnd)
{
// unsubclass any other window
if (Hooked()) UnHook();
// this will be our new subclassed window
m_hWnd = hWnd;
// set the skin region to the window
SetWindowRgn(m_hWnd, m_rgnSkin, true);
// subclass the window procedure
m_OldWndProc = (WNDPROC)SetWindowLong(m_hWnd, GWL_WNDPROC, (LONG)SkinWndProc);
// store a pointer to our class instance inside the window procedure.
if (!SetProp(m_hWnd, "skin", (void*)this))
{
// if we fail to do so, we just can't activate the skin.
UnHook();
return false;
}
// update flag
m_bHooked = ( m_OldWndProc ? true : false );
// force window repainting
InvalidateRect(m_hWnd, NULL, TRUE);
// successful return if we're hooked.
return m_bHooked;
}
bool CSkin::Hook(CWnd *cwnd)
{
if (Hooked() )UnHookCWnd();
m_cwnd = cwnd;
m_cwnd->SetWindowRgn(m_rgnSkin, TRUE);
m_bHooked = true;
m_cwnd->InvalidateRect(NULL, TRUE);
//m_cwnd->Invalidate(true);
//m_cwnd->UpdateWindow();
return m_bHooked;
}
// ----------------------------------------------------------------------------
// unhook the window
// ----------------------------------------------------------------------------
bool CSkin::UnHook()
{
// just to be safe we'll check this
WNDPROC OurWnd;
// cannot unsubclass if there is no window subclassed
// returns true anyways.
if (!Hooked()) return true;
// remove the skin region from the window
SetWindowRgn(m_hWnd, NULL, true);
// unsubclass the window procedure
OurWnd = (WNDPROC)SetWindowLong(m_hWnd, GWL_WNDPROC, (LONG)m_OldWndProc);
// remove the pointer to our class instance, but if we fail we don't care.
RemoveProp(m_hWnd, "skin");
// update flag - if we can't get our window procedure address again,
// we failed to unhook the window.
m_bHooked = ( OurWnd ? false : true );
// force window repainting
InvalidateRect(m_hWnd, NULL, TRUE);
// successful return if we're unhooked.
return !m_bHooked;
}
bool CSkin::UnHookCWnd()
{
if (!Hooked()) return true;
m_cwnd->SetWindowRgn(NULL, TRUE);
m_bHooked = false;
m_cwnd->InvalidateRect(NULL, TRUE);
return !m_bHooked;
}
// ----------------------------------------------------------------------------
// tell us if there is a window subclassed
// ----------------------------------------------------------------------------
bool CSkin::Hooked()
{
return m_bHooked;
}
// ----------------------------------------------------------------------------
// return the skin bitmap width
// ----------------------------------------------------------------------------
int CSkin::Width()
{
return m_iWidth;
}
// ----------------------------------------------------------------------------
// return the skin bitmap height
// ----------------------------------------------------------------------------
int CSkin::Height()
{
return m_iHeight;
}
// ----------------------------------------------------------------------------
// return the skin device context
// ----------------------------------------------------------------------------
HDC CSkin::HDC()
{
return m_dcSkin;
}
HRGN CSkin::HRGN()
{
return m_rgnSkin;
}
// ----------------------------------------------------------------------------
// skin retrieval helper
// ----------------------------------------------------------------------------
bool CSkin::GetSkinData(int iSkinRegion, int iSkinBitmap)
{
// get app instance handle
HINSTANCE hInstance = GetModuleHandle(NULL);
// -------------------------------------------------
// retrieve the skin bitmap from resource.
// -------------------------------------------------
m_hBmp = LoadBitmap(hInstance, MAKEINTRESOURCE(iSkinBitmap));
if (!m_hBmp) return false;
// get skin info
BITMAP bmp;
GetObject(m_hBmp, sizeof(bmp), &bmp);
// get skin dimensions
m_iWidth = bmp.bmWidth;
m_iHeight = bmp.bmHeight;
// -------------------------------------------------
// then, we retrieve the skin region from resource.
// -------------------------------------------------
// ask resource for our skin.
HRSRC hrSkin = FindResource(hInstance, MAKEINTRESOURCE(iSkinRegion),"BINARY");
if (!hrSkin) return false;
// this is standard "BINARY" retrieval.
LPRGNDATA pSkinData = (LPRGNDATA)LoadResource(hInstance, hrSkin);
if (!pSkinData) return false;
// create the region using the binary data.
m_rgnSkin = ExtCreateRegion(NULL, SizeofResource(NULL,hrSkin), pSkinData);
// free the allocated resource
FreeResource(pSkinData);
// check if we have the skin at hand.
if (!m_rgnSkin) return false;
// -------------------------------------------------
// well, things are looking good...
// as a quick providence, just create and keep
// a device context for our later blittings.
// -------------------------------------------------
// create a context compatible with the user desktop
m_dcSkin = CreateCompatibleDC(0);
if (!m_dcSkin) return false;
// select our bitmap
m_hOldBmp = (HBITMAP)SelectObject(m_dcSkin, m_hBmp);
// -------------------------------------------------
// done
// -------------------------------------------------
return true;
}
// ------------------------------------------------------------------------
// Default skin window procedure.
// Here the class will handle WM_PAINT and WM_LBUTTONDOWN, originally sent
// to the application window, but now subclassed. Any other messages will
// just pass through the procedure and reach the original app procedure.
// ------------------------------------------------------------------------
LRESULT CALLBACK SkinWndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
// we will need a pointer to the associated class instance
// (it was stored in the window before, remember?)
CSkin *pSkin = (CSkin*)GetProp(hWnd, "skin");
// to handle WM_PAINT
PAINTSTRUCT ps;
// if we fail to get our class instance, we can't handle anything.
if (!pSkin) return DefWindowProc(hWnd,uMessage,wParam,lParam);
switch(uMessage)
{
case WM_PAINT:
{
// ---------------------------------------------------------
// here we just need to blit our skin
// directly to the device context
// passed by the painting message.
// ---------------------------------------------------------
BeginPaint(hWnd,&ps);
// blit the skin
BitBlt(ps.hdc,0,0,pSkin->Width(),pSkin->Height(),pSkin->HDC(),0,0,SRCCOPY);
EndPaint(hWnd,&ps);
break;
}
case WM_LBUTTONDOWN:
{
// ---------------------------------------------------------
// this is a common trick for easy dragging of the window.
// this message fools windows telling that the user is
// actually dragging the application caption bar.
// ---------------------------------------------------------
SendMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION,NULL);
break;
}
}
// ---------------------------------------------------------
// call the default window procedure to keep things going.
// ---------------------------------------------------------
return CallWindowProc(pSkin->m_OldWndProc, hWnd, uMessage, wParam, lParam);
}
// toggle skin on/off for Cwnd
bool CSkin::EnableCWnd(bool bEnable)
{
// TODO: Add your implementation code here.
if (!Hooked()) return false;
// toggle
m_bEnabled = bEnable;
m_cwnd->InvalidateRect(NULL, TRUE);
//m_cwnd->Invalidate(TRUE);
//m_cwnd->UpdateWindow();
return true;
}
Here are my other files, if you think they will be relevant:
Hello.h
#pragma once
class CMyApp : public CWinApp
{
public:
virtual BOOL InitInstance();
};
class CMainWindow : public CFrameWnd
{
public:
CMainWindow();
protected:
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
// This is the height of the bitmap
int iHeight;
int iWidth;
int BitmapId;
// This sets the height variable of the bitmap
void SetHeight(int height);
// This sets the width variable of the bitmap
void SetWidth(int width);
// This is sets the bitmap id for the image
void SetBitmapId(int bitmapid);
};
Hello.cpp
#include <afxwin.h>
#include "Hello.h"
#include "SkinClass/skin.h"
#include "resource.h"
CMyApp myApp;
/////////////////////////////////////////////////////////////////////////
// CMyApp member functions
BOOL CMyApp::InitInstance()
{
m_pMainWnd = new CMainWindow;
CSkin ii(ID_bitmap, ID_REGION);
CMainWindow* cmw = dynamic_cast<CMainWindow*>(m_pMainWnd);
cmw->SetHeight(ii.Height());
cmw->SetWidth(ii.Width());
cmw->SetBitmapId(ID_bitmap);
ii.Hook(m_pMainWnd);
ii.Enable(true);
m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();
return TRUE;
}
/////////////////////////////////////////////////////////////////////////
// CMainWindow message map and member functions
BEGIN_MESSAGE_MAP(CMainWindow, CFrameWnd)
ON_WM_PAINT()
ON_WM_KEYDOWN()
END_MESSAGE_MAP()
CMainWindow::CMainWindow()
{
Create(NULL, _T("The Hello Application"));
}
void CMainWindow::OnPaint()
{
//CPaintDC dc(this);
//CRect rect;
//GetClientRect(&rect);
//dc.DrawText(_T("Hello, MFC"), -1, &rect,
// DT_SINGLELINE | DT_CENTER | DT_VCENTER);
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
// Do not call CFrameWnd::OnPaint() for painting messages
CDC memDC;
memDC.CreateCompatibleDC(&dc);
CBitmap bm;
bm.LoadBitmap(BitmapId);
memDC.SelectObject(bm);
dc.BitBlt(0, 0, iWidth, iHeight, &memDC, 0, 0, SRCCOPY);
}
void CMainWindow::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: Add your message handler code here and/or call default
// if (nChar == VK_ESCAPE) {
// MessageBox("we have entered here");
// //std::cout << "some stuff in here";
//}
if (nChar == VK_ESCAPE) {
PostQuitMessage(0);
}
CFrameWnd::OnKeyDown(nChar, nRepCnt, nFlags);
}
// This sets the height variable of the bitmap
void CMainWindow::SetHeight(int height)
{
// TODO: Add your implementation code here.
iHeight = height;
}
// This sets the width variable of the bitmap
void CMainWindow::SetWidth(int width)
{
// TODO: Add your implementation code here.
iWidth = width;
}
// This is sets the bitmap id for the image
void CMainWindow::SetBitmapId(int bitmapid)
{
// TODO: Add your implementation code here.
BitmapId = bitmapid;
}
The error message I am getting is:
Error C2065 'SkinWndProc': undeclared identifier mfcexample2 C:\Users\samsu_kag5dbu\source\repos\mfcexample2\mfcexample2\SkinClass\skin.cpp 134
Per https://en.cppreference.com/w/cpp/language/friend :
A name first declared in a friend declaration within a class or class template X becomes a member of the innermost enclosing namespace of X, but is not visible for lookup (except argument-dependent lookup that considers X) unless a matching declaration at namespace scope is provided - see namespaces for details.
You are declaring SkinWndProc() for the first time in skin.h as a friend of CSkin, and then both declaring and defining the actual SkinWndProc() function only in skin.cpp after the definition of CSkin::Hook() tries to use it. As such, SkinWndProc() has not actually been declared yet in the namespace that owns CSkin, so it is not visible to Hook(), which is why you are getting an "undeclared identifier" error.
To fix this, you can either:
in skin.cpp, add a forward declaration for SkinWndProc() above the definition of CSkin::Hook(), eg:
LRESULT CALLBACK SkinWndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam);
bool CSkin::Hook(HWND hWnd)
{
// can now use SkinWndProc as needed...
}
LRESULT CALLBACK SkinWndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
...
}
in skin.cpp, move the entire definition of SkinWndProc() above the definition of CSkin::Hook(), eg:
LRESULT CALLBACK SkinWndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
...
}
bool CSkin::Hook(HWND hWnd)
{
// can now use SkinWndProc as needed...
}
in skin.h and skin.cpp, change SkinWndProc() to be a static class method instead of a standalone friend function, eg:
class CSkin
{
static LRESULT CALLBACK SkinWndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam);
...
};
bool CSkin::Hook(HWND hWnd)
{
// can use CSkin::SkinWndProc as needed...
}
LRESULT CALLBACK CSkin::SkinWndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
...
}
Related
I'm new to C++ so I'm not exactly sure what to put into the title of this problem. Anyway, I created a class whose purpose is to create a Label then use it later to create another Label again and again.
CALLBACK MyClassName::WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) noexcept -> LRESULT {
....
switch (msg) {
....
case WM_CREATE:
{
ControlLabel controlLabel, anotherLabel; //declare two control label
controlLabel.Label(123, hwnd); //Set new id and window handle for label
controlLabel.SetXPosition(68); //Set x position
controlLabel.SetYPosition(110); //Set y position
controlLabel.SetText("This is Label"); //Set the text of Label
controlLabel.SetFontSize(14); //Set the font size of the text
anotherLabel.Label(456, hwnd); //Create and set new id and window handle for another label
anotherLabel.SetXPosition(68); //Set x position of another label
anotherLabel.SetYPosition(140); //Set y position of another label
anotherLabel.SetText("This is another Label"); //Set the text of another label
anotherLabel.SetFontSize(14); //Set the font size of another label
break;
}
....
return ::DefWindowProcW(hwnd, msg, wparam, lparam);
}
I'm expecting it to have an output of two different labels, e.g.
This is Label
This is another Label
Instead, I get two Labels with the same text.
This is another Label
This is another Label
Anyway, here's the full source of the class.
ControlLabel.H
#pragma once
#ifndef CONTROLLABEL_H
#define CONTROLLABEL_H
#include "Header.h"
class ControlLabel {
public:
ControlLabel();
HWND Label(int Label_ID, HWND WindowHandle);
void SetXPosition(int xPosition);
void SetYPosition(int yPosition);
void SetText(string Text);
void SetFontFamily(string FontFamily);
void SetFontSize(int FontSize);
void SetFontColor(int R, int G, int B);
void SetBackgroundColor(int Rr, int Gg, int Bb, bool SetBGColor);
private:
void UpdateLabel();
void SetWidthAndHeights();
static std::wstring StringConverter(const std::string& s);
static LRESULT CALLBACK LabelProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
static HWND LabelHandle;
static SolidBrush vFontColor;
static string text, vFontFamily;
static bool SetBGColor;
static int xPosition, yPosition, width, height, LABEL_ID, vFontSize, R, G, B, BckR, BckG, BckB;
};
#endif
ControlLabel.cpp
#include "ControlLabel.h"
HWND ControlLabel::LabelHandle = NULL;
int ControlLabel::xPosition = 0;
int ControlLabel::yPosition = 0;
int ControlLabel::width = 0;
int ControlLabel::height = 0;
int ControlLabel::LABEL_ID = 0;
int ControlLabel::vFontSize = 12;
int ControlLabel::R = 0;
int ControlLabel::G = 0;
int ControlLabel::B = 0;
int ControlLabel::BckR = 0;
int ControlLabel::BckG = 0;
int ControlLabel::BckB = 0;
bool ControlLabel::SetBGColor = FALSE;
string ControlLabel::text = "Label";
string ControlLabel::vFontFamily = "Segoe UI";
ControlLabel::ControlLabel() {}
/** This function is used to convert string into std::wstring. **/
std::wstring ControlLabel::StringConverter(const std::string& s) {
int len;
int slength = (int)s.length() + 1;
len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0);
wchar_t* buf = new wchar_t[len];
MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
std::wstring r(buf);
delete[] buf;
return r;
}
/** This function is used to automatically set the Width and Height of static control base on the length of the text. **/
void ControlLabel::SetWidthAndHeights() {
std::wstring fontFamilyTemp = StringConverter(vFontFamily);
std::wstring textTemp = StringConverter(text);
LPCWSTR textLabel = textTemp.c_str();
HDC hdc = GetDC(LabelHandle);//static control
HFONT hFont = CreateFont(
-MulDiv(vFontSize, GetDeviceCaps(hdc, LOGPIXELSX), 90), //calculate the actual cHeight.
0, 0, 0, // normal orientation
FW_NORMAL, // normal weight--e.g., bold would be FW_BOLD
false, false, false, // not italic, underlined or strike out
DEFAULT_CHARSET, OUT_OUTLINE_PRECIS, // select only outline (not bitmap) fonts
CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, VARIABLE_PITCH | FF_SWISS, fontFamilyTemp.c_str());
SIZE size;
HFONT oldfont = (HFONT)SelectObject(hdc, hFont);
GetTextExtentPoint32(hdc, textLabel, wcslen(textLabel), &size);
width = size.cx;
height = size.cy;
SelectObject(hdc, oldfont); //don't forget to select the old.
DeleteObject(hFont); //always delete the object after creating it.
ReleaseDC(LabelHandle, hdc); //alway reelase dc after using.
/*char buffer[100];
sprintf_s(buffer, "WIDTH: %d | HEIGHT: %d\n", width, height);
OutputDebugStringA(buffer);*/
}
/** This function will be called when new option is set. For example, fontSize is set. **/
void ControlLabel::UpdateLabel() {
if(LabelHandle != NULL) {
SetWidthAndHeights();
SetWindowPos(LabelHandle, nullptr, xPosition, yPosition, width, height, SWP_NOZORDER | SWP_NOOWNERZORDER);
InvalidateRect(LabelHandle, NULL, FALSE);
UpdateWindow(LabelHandle);
}
}
/** This is the callback function of static control. **/
LRESULT CALLBACK ControlLabel::LabelProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) {
switch(uMsg) {
case WM_ERASEBKGND: {
if(SetBGColor) { //We only want to do this if the SetColor is modified to true, meaning we want to set the color of background.
RECT rect;
GetClientRect(hwnd, &rect);
FillRect((HDC)wParam, &rect, CreateSolidBrush(RGB(BckR, BckG, BckB))); //set titlebar background color.
return 1; //return 1, meaning we take care of erasing the background.
}
return 0;
}case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
Graphics g(hdc);
std::wstring fontFamilyTemp = StringConverter(vFontFamily);
std::wstring textTemp = StringConverter(text);
FontFamily theFontFamily(fontFamilyTemp.c_str());
Font font(&theFontFamily, vFontSize, FontStyleRegular, UnitPixel);
SolidBrush brush(Color(255, R, G, B));
PointF pointF(0.0f, 0.0f);
TextRenderingHint hint = g.GetTextRenderingHint(); // Get the text rendering hint.
g.SetTextRenderingHint(TextRenderingHintAntiAlias); // Set the text rendering hint to TextRenderingHintAntiAlias.
g.DrawString(textTemp.c_str(), -1, &font, pointF, &brush);
EndPaint(hwnd, &ps);
return TRUE;
}case WM_NCDESTROY: {
RemoveWindowSubclass(hwnd, LabelProc, uIdSubclass);
return 0;
}
}
return DefSubclassProc(hwnd, uMsg, wParam, lParam);
}
/** Use this function to create a Label. Parent or WindowHandle must be specified, this is where the Label will be drawn. Unique Label ID must be specified. **/
HWND ControlLabel::Label(int Label_ID, HWND WindowHandle) {
LABEL_ID = Label_ID;
LabelHandle = CreateWindowEx(0, L"STATIC", NULL, WS_CHILD | WS_VISIBLE | SS_OWNERDRAW, xPosition, yPosition, width, height, WindowHandle, NULL, NULL, NULL); //create the static control.
SetWindowSubclass(LabelHandle, &LabelProc, LABEL_ID, 0);
return LabelHandle;
}
/** Use this function to set the X Position of the Label. **/
void ControlLabel::SetXPosition(int xxPosition) {
if(LabelHandle != NULL) {
xPosition = xxPosition; //set xposition
UpdateLabel();
}
}
/** Use this function to set the Y Position of the Label. **/
void ControlLabel::SetYPosition(int yyPosition) {
if(LabelHandle != NULL) {
yPosition = yyPosition; //set xposition
UpdateLabel();
}
}
/** Use this function to set the text of the Label. **/
void ControlLabel::SetText(string ttext) {
if(LabelHandle != NULL) {
text = ttext; //set text
UpdateLabel();
}
}
/** Use this function to set the font family of the Label. **/
void ControlLabel::SetFontFamily(string font_family) {
if(LabelHandle != NULL) {
vFontFamily = font_family; //set font family
UpdateLabel();
}
}
/** Use this function to set the font size of the Label. **/
void ControlLabel::SetFontSize(int size) {
if(LabelHandle != NULL) {
vFontSize = size; //set font size
UpdateLabel();
}
}
/** Use this Function to set the font color of the Label using RGB. **/
void ControlLabel::SetFontColor(int Rr, int Gg, int Bb) {
if(LabelHandle != NULL) {
R = Rr;
G = Gg;
B = Bb;
UpdateLabel();
}
}
/** Use this Function to set the background color of the Label using RGB. Last parameter must be TRUE if you want to set your own background color. **/
void ControlLabel::SetBackgroundColor(int Rr, int Gg, int Bb, bool setColor) {
if(LabelHandle != NULL) {
SetBGColor = setColor;
BckR = Rr;
BckG = Gg;
BckB = Bb;
UpdateLabel();
}
}
Static class members are shared between all instances of a class. There's a static string text in your class so it is to be expected that all instances share that. If you need to store per-instance data you need to use non-static class members.
Presumably, you've used static class members so that you can put your window procedure inside the class' implementation (which needs to be static). To have a static window procedure access per-instance data has been asked and answered before (like here, here, here, or here).
There's no such thing as "instance" when all your variables are declared static. static means the variable is shared among all instances of the class, making it essentially global. So, when you call:
controlLabel.SetText("This is Label");
You assign your text to the global text variable. Then, calling
anotherLabel.SetText("This is another Label");
Assigns the new string to that same global text variable. Your original string was forgotten at this point.
How can you solve this? I can think of multiple ways off the top of my head, maybe you can think of something better. The idea is to somehow bind the text (or the entire controlLabel instance) to a label.
Putting the label text directly into the window data (using WM_SETTEXT. Then you can pull it up in LabelProc and draw it, or just let the default STATIC window procedure handle it.
Making the labels a custom window class that has some extra space reserved for each window instance. Then use SetWindowLong to put a pointer to a whole controlLabel in there. Raw pointers are generally not a great thing in C++, but then again, Win32 API was made for C. Then pull the instance up when needed with GetWindowLong. Just remember to un-static the text member, so it doesn't get overwritten.
Use a global/static std::map<HWND, controlLabel> to associate each label with an instance of controlLabel. Again, if you do this, remember to un-static the text.
Oh, and when you called any controlLabel method that somehow uses the label handle, you just randomly happened to have the handle that you wanted in the LabelHandle variable, since it's also static.
That doesn't make any sense, you won't be able to have a different instance if all your members are static.
However, since the callback of window procedure needs to be static, then you won't be able to access those non-static members inside that function.
What you can do is use the dwRefData parameter of the subclass to pass the instance of your class into your callback function. You can then cast that parameter to access non-static members.
For example in your ::Label function;
SetWindowSubclass(LabelHandle, &LabelProc, LABEL_ID, <DWORD_PTR>(this)); //notice the last parameter, pass `this` instance so you can use `dwRefData`.
Then on your callback;
ControlLabel* controlLabel = reinterpret_cast<ControlLabel*>(dwRefData); //type cast the value of dwRefData.
controlLabel->text //you can now access your non-static variable text
controlLabel->vFontFamily //you can now access your non-static variable vFontFamily
Something like that.
Another problem is you shouldn't declare your callback as private, make it public instead. And do not declare your ControlLabel object inside the WM_CREATE, make it global instead.
ControlLabel controlLabel, anotherLabel; //declare two control label as Global.
CALLBACK MyClassName::WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) noexcept -> LRESULT {
....
switch (msg) {
....
case WM_CREATE:
{
controlLabel.Label(123, hwnd); //Set new id and window handle for label
...
anotherLabel.Label(456, hwnd); //Create and set new id and window handle for another label
...
break;
}
....
return ::DefWindowProcW(hwnd, msg, wparam, lparam);
}
Anyway, I noticed your class doesn't have destructor to destroy your LabelHandle. Make sure to do that.
ControlLabel.h //In your ControlLabel.h
~ControlLabel(); //should be in public
ControlLabel.cpp //In your ControlLabel.cpp
ControlLabel::~ControlLabel() {
if(LabelHandle) DestroyWindow(LabelHandle); //destroy when done.
}
I am using owner drawn dialog. I like to give the shadow for my sub-dialog. Is it possible?
Thank in advance.
Sure, it's possible. You could tweak your dialog background using OnEraseBkgnd().
As an example, I have put shadows on the OK and Cancel buttons of a dialog (CDialogControlShadowDlg) ...
First, some declarations in the header file of your dialog class:
// Implementation
protected:
HICON m_hIcon;
CRect ComputeDrawingRect(int control_id); // <-- !!!
void DrawShadow(CDC* pDC, CRect &r); // <-- !!!
// Generated message map functions
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg BOOL OnEraseBkgnd(CDC* pDC); // <-- !!!
DECLARE_MESSAGE_MAP()
};
Then add OnEraseBkgnd to your message map in the .cpp file:
BEGIN_MESSAGE_MAP(CDialogControlShadowDlg, CDialog)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_ERASEBKGND() // <-- !!!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
Last, but not least, the member function definitions:
// gets the actual drawing location of a control relative to the dialog frame
CRect CDialogControlShadowDlg::ComputeDrawingRect(int control_id)
{
CRect r;
GetDlgItem(control_id)->GetWindowRect(&r);
ScreenToClient(&r);
return r;
}
#define SHADOW_WIDTH 6
// draws the actual shadow
void CDialogControlShadowDlg::DrawShadow(CDC* pDC, CRect &r)
{
DWORD dwBackgroundColor = GetSysColor(COLOR_BTNFACE);
DWORD dwDarkestColor = RGB(GetRValue(dwBackgroundColor)/2,
GetGValue(dwBackgroundColor)/2,
GetBValue(dwBackgroundColor)/2); // dialog background halftone as base color for shadow
int nOffset;
for (nOffset = SHADOW_WIDTH; nOffset > 0; nOffset--)
{
DWORD dwCurrentColorR = (GetRValue(dwDarkestColor)*(SHADOW_WIDTH-nOffset)
+ GetRValue(dwBackgroundColor)*nOffset) / SHADOW_WIDTH;
DWORD dwCurrentColorG = (GetGValue(dwDarkestColor)*(SHADOW_WIDTH-nOffset)
+ GetGValue(dwBackgroundColor)*nOffset) / SHADOW_WIDTH;
DWORD dwCurrentColorB = (GetBValue(dwDarkestColor)*(SHADOW_WIDTH-nOffset)
+ GetBValue(dwBackgroundColor)*nOffset) / SHADOW_WIDTH;
pDC->FillSolidRect(r + CPoint(nOffset, nOffset), RGB(dwCurrentColorR, dwCurrentColorG, dwCurrentColorB));
}
}
BOOL CDialogControlShadowDlg::OnEraseBkgnd( CDC* pDC )
{
// draw dialog background
CRect rdlg;
GetClientRect(&rdlg);
DWORD dwBackgroundColor = GetSysColor(COLOR_BTNFACE);
pDC->FillSolidRect(rdlg, dwBackgroundColor);
// draw shadows
CRect r1, r2;
r1 = ComputeDrawingRect(IDOK);
r2 = ComputeDrawingRect(IDCANCEL);
DrawShadow(pDC, r1);
DrawShadow(pDC, r2);
return TRUE;
}
After applying these modifications, the dialog should look like this:
(source: easyct.de)
I get the below two linking errors when I try to compile in VS 2010. I have ensured that my include & library settings are correct in the project properties > VC ++ Directories & also checked to make sure that Project > Linker > Input has d3d9.lib & d3dx9.lib in it which it does.
I've also tried adding #pragma comment for the two above libraries in D3DGraphics.h but to no avail :(
The compile errors....
1>D3DGraphics.obj : error LNK2019: unresolved external symbol _Direct3DCreate9#4 referenced in function "public: long thiscall D3DGraphics::SetupD3D(struct HWND *)" (?SetupD3D#D3DGraphics##QAEJPAUHWND__###Z)
1>main.obj : error LNK2019: unresolved external symbol "public: __thiscall FIREWORKCLASS::FIREWORKCLASS(struct IDirect3DDevice9 *)" (??0FIREWORKCLASS##QAE#PAUIDirect3DDevice9###Z) referenced in function "void __cdecl SetupFirework1(void)" (?SetupFirework1##YAXXZ)
... : fatal error LNK1120: 2 unresolved externals
Full program structure below...
D3DGraphics.h
#include <d3d9.h> // necessary Direct3D libraries
// Global pointer to the Direct 3D device
extern IDirect3DDevice9* g_pd3dDevice;
// Used to create the Direct3D object
extern IDirect3D9* g_pD3D;
class D3DGraphics
{
public:
// Global pointer to the Direct3D object
IDirect3D9* g_pD3D;
// Global pointer to the Direct 3D device
IDirect3DDevice9* g_pd3dDevice;
//The class constructor - executes whenever an instance is created.
//D3DGraphics() { /* does nothing */ }
// Method to setup D3D parameters
HRESULT SetupD3D ( HWND hWnd );
// Destructor.
// A method that executes when an instance is destroyed.
~D3DGraphics();
void Render();
void Cleanup(); // close Direct3D and release resources
};
D3DGraphics.cpp
#include "D3DGraphics.h"
// Global pointer to the Direct 3D device
IDirect3DDevice9* g_pd3dDevice;
// Used to create the Direct3D object
IDirect3D9* g_pD3D;
//// Constructor code
//D3DGraphics :: D3DGraphics()
//{
//
//}
// TYPE Classname :: MethodName
HRESULT D3DGraphics :: SetupD3D ( HWND hWnd)
{
// Create a D3D object called g_pD3D, return a fail message if this can't be done.
if (NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION))) return E_FAIL;
/* *** Setup a data structure of paramteres to create the Direct3D device *** */
// data structure is called d3dpp
D3DPRESENT_PARAMETERS d3dpp;
// used to clear all data from the structure to ensure no spurious values will be used
ZeroMemory( &d3dpp,sizeof( d3dpp ) );
// application will be windowed
d3dpp.Windowed = TRUE;
// back to front buffer behavior - DISCARD = random data used for error checking
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
// back buffer format - UNKNOWN = use current display resolution to retain consistency
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
// D3D device to create and manage depth and stencil buffer automatically
d3dpp.EnableAutoDepthStencil = TRUE;
// format of the surfaces which hold the depth & stencil buffers - D16 = 16Bit colours
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
////////////* ***END data structure creation*** *////////////
/* *** Create the Direct3D Device using the defined parameters from the data strucutre d3dpp *** */
// Create the Direct3D Device and return a pointer to it, or return E_FAIL if it can't be created
if (FAILED(g_pD3D -> CreateDevice( D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp,
&g_pd3dDevice)))
{
return E_FAIL;
}
// Enable the Z buffer
g_pd3dDevice -> SetRenderState(D3DRS_ZENABLE, TRUE);
return S_OK;
}
// Destructor code
D3DGraphics :: ~D3DGraphics()
{
//???
}
void D3DGraphics :: Cleanup()
{
//release the D3DDevice creation resources
if (g_pD3D != NULL) g_pD3D -> Release();
//release the rendering device creation resources
if (g_pd3dDevice !=NULL) g_pd3dDevice -> Release();
// Render the frame to the back buffer.
}
/* *** The Render cycle for drawing graphics on the screen *** */
void D3DGraphics :: Render()
{
// black background colour
DWORD BackgroundColour = 0x0000000;
// Clear the contents of the backbuffer & Zbuffer and set its colour.
g_pd3dDevice -> Clear(0, // 0 rectangles to be cleared
NULL, // no array of rectangle coordinates
D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, // which buffers should be cleared
BackgroundColour, // the background colour to use, defined as black 0x0000000
1.0f, // Z buffer value
0); // stencil buffer value
// Begin rendering the scene.
if (SUCCEEDED(g_pd3dDevice -> BeginScene()))
{
/// ...GRAPHICS ARE DRAWN HERE...///
// end the rendering
g_pd3dDevice -> EndScene();
}
// Present the backbuffer to the display.
g_pd3dDevice -> Present(NULL, NULL, NULL, NULL);
}
////////////* *** END The Render cycle *** *////////////
Fireworks.h
#include "D3DGraphics.h"
#include <d3dx9math.h> // required in this file for D3DXVECTOR3
// class for a single firework spark
class SPARKCLASS
{
public:
SPARKCLASS();
D3DXVECTOR3 Position;
float XVelocity, YVelocity, ZVelocity;
float Time;
int LifeTime;
};
// max number of sparks that can exist in the system
const int MaxNumberOfSparks = 500;
// class for the firework particle system
class FIREWORKCLASS
{
public:
FIREWORKCLASS (LPDIRECT3DDEVICE9);
void Update();
void Render();
float LaunchAngle;
float LaunchVelocity;
float ParticleSize;
int Lifetime;
int StartInterval, StartCounter, NumberToStart;
float TimeIncrement;
D3DCOLOR SparkColour;
D3DXVECTOR3 Origin;
private:
//array of sparks
SPARKCLASS Sparks[MaxNumberOfSparks];
//starts a new particle
void StartParticle(int);
//counter for the number of sparks that are alive
int SparksAlive;
//vertex buffer for the points
LPDIRECT3DVERTEXBUFFER9 pPointBuffer;
//the Direct3D Deice onto which sparks will be rendered
LPDIRECT3DDEVICE9 pRenderTarget;
};
struct POINTVERTEX
{
D3DXVECTOR3 Position;
D3DCOLOR Colour;
};
// the structure of a vertex in our vertex buffer
#define D3DFVF_POINTVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE)
Fireworks.cpp
#include "Fireworks.h"
void FIREWORKCLASS :: StartParticle(int P)
{
// set this spark's lifetime to the maximum
Sparks[P].LifeTime = Lifetime;
Sparks[P].Time = 0.0f;
Sparks[P].Position.x = 0;
Sparks[P].Position.y = 0;
Sparks[P].Position.z = 0;
// select a random angle around a circle
float DirectionAngle = (float)rand()/(180/D3DX_PI);
//calculate the vertical component of velocity
Sparks[P].YVelocity = LaunchVelocity
* (float)sin(LaunchAngle);
//calculate the horizontal components of velocity - X & Z
Sparks[P].XVelocity = LaunchVelocity
* (float)sin(LaunchAngle)
* (float)cos(DirectionAngle);
Sparks[P].ZVelocity = LaunchVelocity
* (float)sin(LaunchAngle)
* (float)cos(DirectionAngle);
//since another spark now exists, increment the spark counter
SparksAlive++;
}
void FIREWORKCLASS :: Render()
{
//enable point sprites and set the size of the point
pRenderTarget -> SetRenderState(D3DRS_POINTSPRITEENABLE, true);
pRenderTarget -> SetRenderState(D3DRS_POINTSCALEENABLE, true);
pRenderTarget -> SetRenderTarget(D3DRS_LIGHTING, false);
//scale the points according to distance
pRenderTarget -> SetRenderState(D3DRS_POINTSIZE,
FtoDW(ParticleSize));
pRenderTarget -> SetRenderState(D3DRS_POINTSIZE_MIN, FtoDW(0.0f));
pRenderTarget -> SetRenderState(D3DRS_POINTSCALE_A, FtoDW(0.0f));
pRenderTarget -> SetRenderState(D3DRS_POINTSCALE_B, FtoDW(0.0f));
pRenderTarget -> SetRenderState(D3DRS_POINTSCALE_C, FtoDW(0.0f));
//render the contents of the vertex buffer
pRenderTarget -> SetStreamSource(0, pPointBuffer, 0,
sizeof(POINTVERTEX));
pRenderTarget -> SetFVF(D3DFVF_POINTVERTEX);
pRenderTarget -> DrawPrimitive(D3DPT_POINTLIST, 0, 0); // 0, ??
//reset the render states
pRenderTarget -> SetRenderState(D3DRS_POINTSPRITEENABLE, false);
pRenderTarget -> SetRenderState(D3DRS_POINTSCALEENABLE, false);
pRenderTarget -> SetRenderState(D3DRS_LIGHTING, true);
}
* Main.cpp *
#define D3D_DEBUG_INFO // Enable debugging information
#include "Windows.h"
#include "Fireworks.h"
//global pointer to Firework1 object
FIREWORKCLASS *g_Firework1 = NULL;
void SetupFirework1()
{
g_Firework1 = new FIREWORKCLASS(g_pd3dDevice);
g_Firework1 -> Origin.x = 0.0f;
g_Firework1 -> Origin.x = 0.0f;
g_Firework1 -> Origin.x = 0.0f;
g_Firework1 -> StartInterval = 10;
g_Firework1 -> StartCounter = 10;
g_Firework1 -> LaunchAngle = D3DXToRadian(80);
g_Firework1 -> LaunchVelocity = 40.0f;
g_Firework1 -> TimeIncrement = 0.04f;
g_Firework1 -> Lifetime = 200;
g_Firework1 -> NumberToStart = 8;
g_Firework1 -> ParticleSize = 2.0f;
g_Firework1 -> SparkColour = 0x00FFE000; // yellow
}
// The window's message handling function.
LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
{
// The user has clicked on the 'close' button on the window's title bar.
// Send a 'WM_QUIT' message to the application to close it down.
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
// WinMain() - The application's entry point.
// This sort of procedure is mostly standard, and could be used in most
// DirectX applications.
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int)
{
/* ***Create the application window*** */
// Register the window class
WNDCLASSEX wc = {sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
"Blank", NULL};
RegisterClassEx(&wc);
// Create the application's window
HWND hWnd = CreateWindow( "Blank", "---Fireworks---",
WS_OVERLAPPEDWINDOW, 100, 100, 800, 800, // ?, ?, size(x), size(y)
GetDesktopWindow(), NULL, wc.hInstance, NULL);
/* ***END application window creation*** */
// Create an instance of the D3DGraphics class called D3D
D3DGraphics D3D;
// Initialize Direct3D
if (SUCCEEDED(D3D.SetupD3D(hWnd)))
{
// Show the window
ShowWindow(hWnd, SW_SHOWDEFAULT);
UpdateWindow(hWnd);
// Enter the message loop
MSG msg;
ZeroMemory(&msg, sizeof(msg));
// Respond to messages until a 'WM_QUIT' message is received.
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
// g_Firework1 -> Update(); // update Firework1 particles
D3D.Render(); // render the scene
}
// Execute the class destructor to clear any resources that
// D3DGraphics class has created/used.
D3D.Cleanup();
}
UnregisterClass("Blank", wc.hInstance);
return 0;
}
This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 6 years ago.
Here's my (O.K. not my :)) code:
/*
* This Code Was Created By Jeff Molofee 2000
* A HUGE Thanks To Fredric Echols For Cleaning Up
* And Optimizing This Code, Making It More Flexible!
* If You've Found This Code Useful, Please Let Me Know.
* Visit My Site At nehe.gamedev.net
*/
#include <windows.h> // Header File For Windows
#include <gl\gl.h> // Header File For The OpenGL32 Library
#include <gl\glu.h> // Header File For The GLu32 Library
#include <gl\GLaux.h> // Header File For The Glaux Library
HDC hDC=NULL; // Private GDI Device Context
HGLRC hRC=NULL; // Permanent Rendering Context
HWND hWnd=NULL; // Holds Our Window Handle
HINSTANCE hInstance; // Holds The Instance Of The Application
bool keys[256]; // Array Used For The Keyboard Routine
bool active=TRUE; // Window Active Flag Set To TRUE By Default
bool fullscreen=TRUE; // Fullscreen Flag Set To Fullscreen Mode By Default
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc
GLvoid ReSizeGLScene(GLsizei width, GLsizei height) // Resize And Initialize The GL Window
{
if (height==0) // Prevent A Divide By Zero By
{
height=1; // Making Height Equal One
}
glViewport(0,0,width,height); // Reset The Current Viewport
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix
}
int InitGL(GLvoid) // All Setup For OpenGL Goes Here
{
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
return TRUE; // Initialization Went OK
}
int DrawGLScene(GLvoid) // Here's Where We Do All The Drawing
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
glLoadIdentity(); // Reset The Current Modelview Matrix
return TRUE; // Everything Went OK
}
GLvoid KillGLWindow(GLvoid) // Properly Kill The Window
{
if (fullscreen) // Are We In Fullscreen Mode?
{
ChangeDisplaySettings(NULL,0); // If So Switch Back To The Desktop
ShowCursor(TRUE); // Show Mouse Pointer
}
if (hRC) // Do We Have A Rendering Context?
{
if (!wglMakeCurrent(NULL,NULL)) // Are We Able To Release The DC And RC Contexts?
{
MessageBox(NULL,TEXT("Release Of DC And RC Failed."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
}
if (!wglDeleteContext(hRC)) // Are We Able To Delete The RC?
{
MessageBox(NULL,TEXT("Release Rendering Context Failed."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
}
hRC=NULL; // Set RC To NULL
}
if (hDC && !ReleaseDC(hWnd,hDC)) // Are We Able To Release The DC
{
MessageBox(NULL,TEXT("Release Device Context Failed."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
hDC=NULL; // Set DC To NULL
}
if (hWnd && !DestroyWindow(hWnd)) // Are We Able To Destroy The Window?
{
MessageBox(NULL,TEXT("Could Not Release hWnd."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
hWnd=NULL; // Set hWnd To NULL
}
if (!UnregisterClass(TEXT("OpenGL"),hInstance)) // Are We Able To Unregister Class
{
MessageBox(NULL,TEXT("Could Not Unregister Class."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
hInstance=NULL; // Set hInstance To NULL
}
}
/* This Code Creates Our OpenGL Window. Parameters Are: *
* title - Title To Appear At The Top Of The Window *
* width - Width Of The GL Window Or Fullscreen Mode *
* height - Height Of The GL Window Or Fullscreen Mode *
* bits - Number Of Bits To Use For Color (8/16/24/32) *
* fullscreenflag - Use Fullscreen Mode (TRUE) Or Windowed Mode (FALSE) */
BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)
{
GLuint PixelFormat; // Holds The Results After Searching For A Match
WNDCLASS wc; // Windows Class Structure
DWORD dwExStyle; // Window Extended Style
DWORD dwStyle; // Window Style
RECT WindowRect; // Grabs Rectangle Upper Left / Lower Right Values
WindowRect.left=(long)0; // Set Left Value To 0
WindowRect.right=(long)width; // Set Right Value To Requested Width
WindowRect.top=(long)0; // Set Top Value To 0
WindowRect.bottom=(long)height; // Set Bottom Value To Requested Height
fullscreen=fullscreenflag; // Set The Global Fullscreen Flag
hInstance = GetModuleHandle(NULL); // Grab An Instance For Our Window
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Redraw On Size, And Own DC For Window.
wc.lpfnWndProc = (WNDPROC) WndProc; // WndProc Handles Messages
wc.cbClsExtra = 0; // No Extra Window Data
wc.cbWndExtra = 0; // No Extra Window Data
wc.hInstance = hInstance; // Set The Instance
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // Load The Default Icon
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Load The Arrow Pointer
wc.hbrBackground = NULL; // No Background Required For GL
wc.lpszMenuName = NULL; // We Don't Want A Menu
wc.lpszClassName = TEXT("OpenGL"); // Set The Class Name
if (!RegisterClass(&wc)) // Attempt To Register The Window Class
{
MessageBox(NULL,TEXT("Failed To Register The Window Class."),TEXT("ERROR"),MB_OK|MB_ICONEXCLAMATION);
return FALSE; // Return FALSE
}
if (fullscreen) // Attempt Fullscreen Mode?
{
DEVMODE dmScreenSettings; // Device Mode
memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); // Makes Sure Memory's Cleared
dmScreenSettings.dmSize=sizeof(dmScreenSettings); // Size Of The Devmode Structure
dmScreenSettings.dmPelsWidth = width; // Selected Screen Width
dmScreenSettings.dmPelsHeight = height; // Selected Screen Height
dmScreenSettings.dmBitsPerPel = bits; // Selected Bits Per Pixel
dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
// Try To Set Selected Mode And Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
{
// If The Mode Fails, Offer Two Options. Quit Or Use Windowed Mode.
if (MessageBox(NULL,TEXT("The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?"),TEXT("NeHe GL"),MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
{
fullscreen=FALSE; // Windowed Mode Selected. Fullscreen = FALSE
}
else
{
// Pop Up A Message Box Letting User Know The Program Is Closing.
MessageBox(NULL,TEXT("Program Will Now Close."),TEXT("ERROR"),MB_OK|MB_ICONSTOP);
return FALSE; // Return FALSE
}
}
}
if (fullscreen) // Are We Still In Fullscreen Mode?
{
dwExStyle=WS_EX_APPWINDOW; // Window Extended Style
dwStyle=WS_POPUP; // Windows Style
ShowCursor(FALSE); // Hide Mouse Pointer
}
else
{
dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // Window Extended Style
dwStyle=WS_OVERLAPPEDWINDOW; // Windows Style
}
AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle); // Adjust Window To True Requested Size
// Create The Window
if (!(hWnd=CreateWindowEx( dwExStyle, // Extended Style For The Window
TEXT("OpenGL"), // Class Name
TEXT("title"), // Window Title
dwStyle | // Defined Window Style
WS_CLIPSIBLINGS | // Required Window Style
WS_CLIPCHILDREN, // Required Window Style
0, 0, // Window Position
WindowRect.right-WindowRect.left, // Calculate Window Width
WindowRect.bottom-WindowRect.top, // Calculate Window Height
NULL, // No Parent Window
NULL, // No Menu
hInstance, // Instance
NULL))) // Dont Pass Anything To WM_CREATE
{
KillGLWindow(); // Reset The Display
MessageBox(NULL,TEXT("Window Creation Error."),TEXT("ERROR"),MB_OK|MB_ICONEXCLAMATION);
return FALSE; // Return FALSE
}
static PIXELFORMATDESCRIPTOR pfd= // pfd Tells Windows How We Want Things To Be
{
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
1, // Version Number
PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
PFD_DOUBLEBUFFER, // Must Support Double Buffering
PFD_TYPE_RGBA, // Request An RGBA Format
bits, // Select Our Color Depth
0, 0, 0, 0, 0, 0, // Color Bits Ignored
0, // No Alpha Buffer
0, // Shift Bit Ignored
0, // No Accumulation Buffer
0, 0, 0, 0, // Accumulation Bits Ignored
16, // 16Bit Z-Buffer (Depth Buffer)
0, // No Stencil Buffer
0, // No Auxiliary Buffer
PFD_MAIN_PLANE, // Main Drawing Layer
0, // Reserved
0, 0, 0 // Layer Masks Ignored
};
if (!(hDC=GetDC(hWnd))) // Did We Get A Device Context?
{
KillGLWindow(); // Reset The Display
MessageBox(NULL,TEXT("Can't Create A GL Device Context."),TEXT("ERROR"),MB_OK|MB_ICONEXCLAMATION);
return FALSE; // Return FALSE
}
if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd))) // Did Windows Find A Matching Pixel Format?
{
KillGLWindow(); // Reset The Display
MessageBox(NULL,TEXT("Can't Find A Suitable PixelFormat."),TEXT("ERROR"),MB_OK|MB_ICONEXCLAMATION);
return FALSE; // Return FALSE
}
if(!SetPixelFormat(hDC,PixelFormat,&pfd)) // Are We Able To Set The Pixel Format?
{
KillGLWindow(); // Reset The Display
MessageBox(NULL,TEXT("Can't Set The PixelFormat."),TEXT("ERROR"),MB_OK|MB_ICONEXCLAMATION);
return FALSE; // Return FALSE
}
if (!(hRC=wglCreateContext(hDC))) // Are We Able To Get A Rendering Context?
{
KillGLWindow(); // Reset The Display
MessageBox(NULL,TEXT("Can't Create A GL Rendering Context."),TEXT("ERROR"),MB_OK|MB_ICONEXCLAMATION);
return FALSE; // Return FALSE
}
if(!wglMakeCurrent(hDC,hRC)) // Try To Activate The Rendering Context
{
KillGLWindow(); // Reset The Display
MessageBox(NULL,TEXT("Can't Activate The GL Rendering Context."),TEXT("ERROR"),MB_OK|MB_ICONEXCLAMATION);
return FALSE; // Return FALSE
}
ShowWindow(hWnd,SW_SHOW); // Show The Window
SetForegroundWindow(hWnd); // Slightly Higher Priority
SetFocus(hWnd); // Sets Keyboard Focus To The Window
ReSizeGLScene(width, height); // Set Up Our Perspective GL Screen
if (!InitGL()) // Initialize Our Newly Created GL Window
{
KillGLWindow(); // Reset The Display
MessageBox(NULL,TEXT("Initialization Failed."),TEXT("ERROR"),MB_OK|MB_ICONEXCLAMATION);
return FALSE; // Return FALSE
}
return TRUE; // Success
}
LRESULT CALLBACK WndProc( HWND hWnd, // Handle For This Window
UINT uMsg, // Message For This Window
WPARAM wParam, // Additional Message Information
LPARAM lParam) // Additional Message Information
{
switch (uMsg) // Check For Windows Messages
{
case WM_ACTIVATE: // Watch For Window Activate Message
{
if (!HIWORD(wParam)) // Check Minimization State
{
active=TRUE; // Program Is Active
}
else
{
active=FALSE; // Program Is No Longer Active
}
return 0; // Return To The Message Loop
}
case WM_SYSCOMMAND: // Intercept System Commands
{
switch (wParam) // Check System Calls
{
case SC_SCREENSAVE: // Screensaver Trying To Start?
case SC_MONITORPOWER: // Monitor Trying To Enter Powersave?
return 0; // Prevent From Happening
}
break; // Exit
}
case WM_CLOSE: // Did We Receive A Close Message?
{
PostQuitMessage(0); // Send A Quit Message
return 0; // Jump Back
}
case WM_KEYDOWN: // Is A Key Being Held Down?
{
keys[wParam] = TRUE; // If So, Mark It As TRUE
return 0; // Jump Back
}
case WM_KEYUP: // Has A Key Been Released?
{
keys[wParam] = FALSE; // If So, Mark It As FALSE
return 0; // Jump Back
}
case WM_SIZE: // Resize The OpenGL Window
{
ReSizeGLScene(LOWORD(lParam),HIWORD(lParam)); // LoWord=Width, HiWord=Height
return 0; // Jump Back
}
}
// Pass All Unhandled Messages To DefWindowProc
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
int WINAPI WinMain( HINSTANCE hInstance, // Instance
HINSTANCE hPrevInstance, // Previous Instance
LPSTR lpCmdLine, // Command Line Parameters
int nCmdShow) // Window Show State
{
MSG msg; // Windows Message Structure
BOOL done=FALSE; // Bool Variable To Exit Loop
// Ask The User Which Screen Mode They Prefer
if (MessageBox(NULL,TEXT("Would You Like To Run In Fullscreen Mode?"), TEXT("Start FullScreen?"),MB_YESNO|MB_ICONQUESTION)==IDNO)
{
fullscreen=FALSE; // Windowed Mode
}
// Create Our OpenGL Window
if (!CreateGLWindow("NeHe's OpenGL Framework",640,480,16,fullscreen))
{
return 0; // Quit If Window Was Not Created
}
while(!done) // Loop That Runs While done=FALSE
{
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) // Is There A Message Waiting?
{
if (msg.message==WM_QUIT) // Have We Received A Quit Message?
{
done=TRUE; // If So done=TRUE
}
else // If Not, Deal With Window Messages
{
TranslateMessage(&msg); // Translate The Message
DispatchMessage(&msg); // Dispatch The Message
}
}
else // If There Are No Messages
{
// Draw The Scene. Watch For ESC Key And Quit Messages From DrawGLScene()
if (active) // Program Active?
{
if (keys[VK_ESCAPE]) // Was ESC Pressed?
{
done=TRUE; // ESC Signalled A Quit
}
else // Not Time To Quit, Update Screen
{
DrawGLScene(); // Draw The Scene
SwapBuffers(hDC); // Swap Buffers (Double Buffering)
}
}
if (keys[VK_F1]) // Is F1 Being Pressed?
{
keys[VK_F1]=FALSE; // If So Make Key FALSE
KillGLWindow(); // Kill Our Current Window
fullscreen=!fullscreen; // Toggle Fullscreen / Windowed Mode
// Recreate Our OpenGL Window
if (!CreateGLWindow("NeHe's OpenGL Framework",640,480,16,fullscreen))
{
return 0; // Quit If Window Was Not Created
}
}
}
}
// Shutdown
KillGLWindow(); // Kill The Window
return (msg.wParam); // Exit The Program
}
How I can solve problem with unresolved externals?
I can't post image so here's link to image with some errors what my VC++ Express wrote: http://i.stack.imgur.com/2v2US.png
Unresolved externals usually means you did not input the correct libraries. In your project settings, what OpenGL libraries did you include? Standard is
opengl32.lib
glu32.lib
in your project linker settings.
I'm having a very frustrating issue setting up a DirectX 9 (irrelevant to the issue.. I think) framework in VS 2010. Here is my DirectX framework:
#ifndef _DX9_H_
#define _DX9_H_
// window includes
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
// required for ush typedef and window properties to setup backbuffer
#include "sys_params.h"
// directx9 includes
#define DIRECTINPUT_VERSION 0x0800
#include <d3dx9.h>
#include <dinput.h>
#include <DxErr.h>
#include <vector>
#include <iterator>
// directx9 libraries
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
#pragma comment(lib, "dinput8.lib")
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "dxerr.lib")
namespace nsdx9
{
using nssysprms::ush;
#define CheckHR(hr) CheckForDXError(__FILE__, __LINE__, hr)
class DX9
{
public:
DX9(HINSTANCE& inst, int cmdShow, const std::string& title, ush wndwidth, ush wndheight, short wndx, short wndy);
~DX9();
// windows message processor
UINT ProcessMessages();
// --- DIRECTX GAME FUNCTIONS --- //
// input functions
void InputUpdate();
BYTE KeyHeld(ush key);
bool KeyPressed(ush key);
// sprite functions
const LPD3DXSPRITE& GetSpriteInterface();
void SpriteBeginDraw(DWORD flags = D3DXSPRITE_ALPHABLEND);
void SpriteEndDraw();
// font functions
void MakeFont(int height, int width, UINT weight = FW_DONTCARE, LPCSTR face = "Calibri", bool italic = false);
const LPD3DXFONT& GetFontAtIndex(ush index);
const std::vector<LPD3DXFONT>& GetFontVector();
// --- END DIRECTX GAME FUNCTIONS --- //
private:
// --- WINDOW FUNCTIONS/VARIABLES --- //
WNDCLASSEX _wc;
HWND _hwnd;
MSG _msg;
HINSTANCE _inst;
std::string _title;
static LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wprm, LPARAM lprm);
// --- END WINDOW FUNCTIONS/VARIABLES --- //
// --- DIRECTX FUNCTIONS/VARIABLES --- //
// D3D interfaces
LPDIRECT3D9 _d3d;
LPDIRECT3DDEVICE9 _d3ddev;
D3DPRESENT_PARAMETERS _d3dpp;
// directinput interfaces
LPDIRECTINPUT8 _dInput;
LPDIRECTINPUTDEVICE8 _diMouse;
LPDIRECTINPUTDEVICE8 _diKeyboard;
DIMOUSESTATE _mouseState;
BYTE _keys[256];
bool _keyStates[256];
bool _keyboardStateChanged;
void AcquireInputDevice(const LPDIRECTINPUTDEVICE8& dev);
// sprite interfaces
LPD3DXSPRITE _spriteBatch;
// font vector
std::vector<LPD3DXFONT> _fonts;
// hresult checker, for debugging only
void CheckForDXError(const char *file, int line, HRESULT hr);
// --- END DIRECTX FUNCTIONS/VARIABLES --- //
};
/*=================================================*/
/*--------------DIRECTX CONSTRUCTOR----------------*/
/*=================================================*/
DX9::DX9(HINSTANCE& inst, int cmdShow, const std::string& title, ush wndwidth, ush wndheight, short wndx, short wndy)
{
/*=================================================*/
/*--------------WINDOW INITIALIZATION--------------*/
/*=================================================*/
_title = title;
_inst = inst;
// init window class struct
_wc.cbClsExtra = NULL;
_wc.cbSize = sizeof(WNDCLASSEX);
_wc.cbWndExtra = NULL;
_wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
_wc.hCursor = LoadCursor(NULL, IDC_ARROW);
_wc.hIcon = NULL;
_wc.hIconSm = NULL;
_wc.hInstance = inst;
_wc.lpfnWndProc = (WNDPROC)WinProc;
_wc.lpszClassName = title.c_str();
_wc.lpszMenuName = NULL;
_wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClassEx(&_wc);
// create handle to the window
_hwnd = CreateWindow(title.c_str(),
title.c_str(),
WS_OVERLAPPEDWINDOW,
wndx,
wndy,
wndwidth,
wndheight,
NULL,
NULL,
inst,
NULL);
// required to make the window show up
ShowWindow(_hwnd, cmdShow);
UpdateWindow(_hwnd);
/*=================================================*/
/*--------------END WINDOW INITIALIZATION----------*/
/*=================================================*/
/*=================================================*/
/*--------------DIRECTX INITIALIZATION-------------*/
/*=================================================*/
// --- INITIALIZE DIRECTX9 VARIABLES --- //
SecureZeroMemory(&_d3dpp, sizeof(_d3dpp));
SecureZeroMemory(&_mouseState, sizeof(_mouseState));
SecureZeroMemory(&_keys, sizeof(_keys));
for (int i = 0; i < 256; i++)
{
_keyStates[i] = true;
}
_d3d = NULL;
_d3ddev = NULL;
_dInput = NULL;
_diMouse = NULL;
_diKeyboard = NULL;
_keyboardStateChanged = false;
_spriteBatch = NULL;
// --- END INITIALIZE DIRECTX9 VARIABLES --- //
// --- DIRECTX9 INITIALIZATION --- //
_d3d = Direct3DCreate9(D3D_SDK_VERSION);
if (!_d3d)
{
OutputDebugString("Error: Failed to create Direct3D.\n");
}
// set d3d present parameters
_d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
_d3dpp.BackBufferCount = 1;
_d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
_d3dpp.BackBufferHeight = nssysprms::WND_HEIGHT;
_d3dpp.BackBufferWidth = nssysprms::WND_WIDTH;
_d3dpp.EnableAutoDepthStencil = 1;
_d3dpp.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
//_d3dpp.FullScreen_RefreshRateInHz
_d3dpp.hDeviceWindow = _hwnd;
//_d3dpp.MultiSampleQuality
//_d3dpp.MultiSampleType
_d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
_d3dpp.Windowed = nssysprms::isWindowed;
// create d3d device
CheckHR(_d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, _hwnd, D3DCREATE_MIXED_VERTEXPROCESSING, &_d3dpp, &_d3ddev));
// --- END DIRECTX9 INITIALIZATION --- //
// --- INITIALIZE DIRECTINPUT --- //
CheckHR(DirectInput8Create(inst, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&_dInput, NULL));
// create mouse and keyboard
CheckHR(_dInput->CreateDevice(GUID_SysKeyboard, &_diKeyboard, NULL));
CheckHR(_dInput->CreateDevice(GUID_SysMouse, &_diMouse, NULL));
// initialize keyboard
CheckHR(_diKeyboard->SetDataFormat(&c_dfDIKeyboard));
CheckHR(_diKeyboard->SetCooperativeLevel(_hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND));
AcquireInputDevice(_diKeyboard);
// initialize mouse
CheckHR(_diMouse->SetDataFormat(&c_dfDIMouse));
CheckHR(_diMouse->SetCooperativeLevel(_hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND));
AcquireInputDevice(_diMouse);
// create sprite object
CheckHR(D3DXCreateSprite(_d3ddev, &_spriteBatch));
// --- END INITIALIZE DIRECTINPUT --- //
/*=================================================*/
/*--------------END DIRECTX INITIALIZATION---------*/
/*=================================================*/
}
/*=================================================*/
/*--------------END DIRECTX CONSTRUCTOR------------*/
/*=================================================*/
/*=================================================*/
/*--------------DIRECTX DESTRUCTOR-----------------*/
/*=================================================*/
DX9::~DX9()
{
// set all stack variables to NULL
SecureZeroMemory(&_d3dpp, sizeof(_d3dpp));
SecureZeroMemory(&_mouseState, sizeof(_mouseState));
SecureZeroMemory(&_keys, sizeof(_keys));
SecureZeroMemory(&_keyStates, sizeof(_keyStates));
// free all the D3D interfaces from memory
if (!_fonts.empty())
{
for (std::vector<LPD3DXFONT>::iterator it = _fonts.begin(); it != _fonts.end(); it++)
{
// SOLVEPROBLEM figure out why this doesn't work
//*it->OnLostDevice();
}
_fonts.erase(_fonts.begin(), _fonts.end() - 1);
}
if (_spriteBatch != NULL)
{
_spriteBatch->Release();
_spriteBatch = NULL;
}
if (_diKeyboard != NULL)
{
_diKeyboard->Release();
_diKeyboard = NULL;
}
if (_diMouse != NULL)
{
_diMouse->Release();
_diMouse = NULL;
}
if (_d3ddev != NULL)
{
_d3ddev->Release();
_d3ddev = NULL;
}
if (_d3d != NULL)
{
_d3d->Release();
_d3d = NULL;
}
// free the window class from memory
UnregisterClass(_title.c_str(), _inst);
}
/*=================================================*/
/*--------------END DIRECTX DESTRUCTOR-------------*/
/*=================================================*/
/*=================================================*/
/*--------------HRESULT ERROR CHECK----------------*/
/*=================================================*/
void DX9::CheckForDXError(const char *file, int line, HRESULT hr)
{
if (SUCCEEDED(hr))
{
return;
}
// Get the direct X error and description
char desc[1024];
sprintf_s(desc,"(DX) %s - %s", DXGetErrorString(hr), DXGetErrorDescription(hr));
// Output the file and line number in the correct format + the above DX error
char buf[2048];
sprintf_s(buf,"%s(%d) : Error: %s\n", file, line, desc);
OutputDebugString(buf);
}
/*=================================================*/
/*--------------END HRESULT ERROR CHECK------------*/
/*=================================================*/
/*=================================================*/
/*--------------MESSAGE PROCESSOR------------------*/
/*=================================================*/
UINT DX9::ProcessMessages()
{
if (PeekMessage(&_msg, NULL, NULL, NULL, PM_REMOVE))
{
TranslateMessage(&_msg);
DispatchMessage(&_msg);
}
return _msg.message;
}
/*=================================================*/
/*--------------END MESSAGE PROCESSOR--------------*/
/*=================================================*/
/*=================================================*/
/*--------------MESSAGE HANDLER--------------------*/
/*=================================================*/
LRESULT CALLBACK DX9::WinProc(HWND hwnd, UINT msg, WPARAM wprm, LPARAM lprm)
{
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wprm, lprm);
}
/*=================================================*/
/*--------------END MESSAGE HANDLER----------------*/
/*=================================================*/
/*=================================================*/
/*--------------DIRECTINPUT FUNCTIONS--------------*/
/*=================================================*/
// for init only, helper function to initially acquire the
// mouse and keyboard
void DX9::AcquireInputDevice(const LPDIRECTINPUTDEVICE8& dev)
{
// loop and attempt to acquire the device until success
while (FAILED(dev->Acquire()))
{
dev->Acquire();
}
}
// update the state of the mouse and keyboard
void DX9::InputUpdate()
{
_diKeyboard->GetDeviceState(sizeof(_keys), (LPVOID)_keys);
_diMouse->GetDeviceState(sizeof(_mouseState), (LPVOID)&_mouseState);
// after directinput has been updated, check to see if any keys are no,
// longer pressed, and reset the keystate array at that key's index if,
// this is the case
// keystates true = key is available for key press
if (_keyboardStateChanged)
{
for (int i = 0; i < 256; i++)
{
if (!KeyHeld(i))
{
_keyStates[i] = true;
}
}
}
_keyboardStateChanged = false;
}
// captures a key being held down
BYTE DX9::KeyHeld(ush key)
{
return _keys[key] & 0x80;
}
// captures a single key press
bool DX9::KeyPressed(ush key)
{
if (KeyHeld(key) && _keyStates[key])
{
_keyStates[key] = false;
return true;
}
else
{
if (!KeyHeld(key) && !_keyStates[key])
{
_keyboardStateChanged = true;
}
return false;
}
}
/*=================================================*/
/*--------------END DIRECTINPUT FUNCTIONS----------*/
/*=================================================*/
/*=================================================*/
/*--------------SPRITE FUNCTIONS-------------------*/
/*=================================================*/
// returns the sprite interface
const LPD3DXSPRITE& DX9::GetSpriteInterface()
{
return _spriteBatch;
}
// begin drawing with the sprite batch
void DX9::SpriteBeginDraw(DWORD flags)
{
_spriteBatch->Begin(flags);
}
// end sprite batch drawing
void DX9::SpriteEndDraw()
{
_spriteBatch->End();
}
/*=================================================*/
/*--------------END SPRITE FUNCTIONS---------------*/
/*=================================================*/
/*=================================================*/
/*--------------FONT FUNCTIONS---------------------*/
/*=================================================*/
// create a font
void DX9::MakeFont(int height, int width, UINT weight, LPCSTR face, bool italic)
{
LPD3DXFONT newfont;
CheckHR(D3DXCreateFont(_d3ddev,
height,
width,
weight,
0,
italic,
DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS,
CLEARTYPE_QUALITY,
DEFAULT_PITCH | FF_DONTCARE,
face,
&newfont));
_fonts.push_back(newfont);
}
// gets a font at the specified index
const LPD3DXFONT& DX9::GetFontAtIndex(ush index)
{
return _fonts[index];
}
const std::vector<LPD3DXFONT>& DX9::GetFontVector()
{
return _fonts;
}
/*=================================================*/
/*--------------END FONT FUNCTIONS-----------------*/
/*=================================================*/
}
#endif
This really doesn't do anything but create and initialize a window, DirectX and some basic DirectX functions.
The actual error is this:
Error 1 error LNK2005: "public: __thiscall nsdx9::DX9::DX9(struct HINSTANCE__ * &,int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,unsigned short,unsigned short,short,short)" (??0DX9#nsdx9##QAE#AAPAUHINSTANCE__##HABV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##GGFF#Z) already defined in game_manager.obj C:\Users\JAREK\documents\visual studio 2010\Projects\example\example\main.obj
This error is repeated for every single function in dx9.h. If I ONLY include dx9.h in main.cpp, I do not get this error. It is only if I include dx9.h in any other cpp file, or use any of the parameters in dx9.h in cpp files that have access to dx9.h by being included after dx9.h in main.cpp that I get this error. This sounds confusing, so here are some samples from other parts of the program:
main.cpp:
#include "sys_params.h"
#include "dx9.h"
#include "game_manager.h"
int WINAPI WinMain (HINSTANCE inst, HINSTANCE pinst, LPSTR cmdLine, int cmdShow)
{
// state of the program
bool appEnd = false;
// create and initialize the window and directx9
nsdx9::DX9* _dx9 = new nsdx9::DX9(inst, cmdShow, nssysprms::GAME_TITLE,
nssysprms::WND_WIDTH, nssysprms::WND_HEIGHT,
nssysprms::WND_POS_X, nssysprms::WND_POS_Y);
// create and initialize the game manager
Game_Manager* _mngr = new Game_Manager(_dx9);
// Windows message handler
// also the entry point for the main game loop
while (_dx9->ProcessMessages() != WM_QUIT && !appEnd)
{
if (!_mngr->Game_Run())
{
appEnd = true;
}
}
// clean up everything
delete _mngr;
delete _dx9;
return 0;
}
game_manager.h:
#ifndef _GAME_MANAGER_H_
#define _GAME_MANAGER_H_
#include <stack>
#include <vector>
#include "dx9.h"
#include "screen.h"
#include "message_handler.h"
class Game_Manager
{
public:
Game_Manager(nsdx9::DX9* dx9);
~Game_Manager();
bool Game_Run();
private:
nsdx9::DX9* _dx9;
std::stack<Screen*> _screens;
Message_Handler* _msg_hnd;
// *** DECLARE SCREENS HERE *** //
void InitFonts();
void InitScreens();
};
#endif
This should be what is actually causing the issue. The issue is originating from main.cpp through game_manager.h. Nothing I've tried has solved the problem for me. I've included header guards in dx9.h, so I have no idea what could be causing this. if you guys need more information, please let me know. Thanks!
Your definitions of the DX9 methods (as opposed to just the class definition) seem to be in the dx9.h header file - so you violate C++'s one-definition rule when you include dx9.h in multiple .cpp files. To solve this, move the method implementations into a .cpp file (e.g. dx9.cpp).
Don't include the implementation in the header file. This causes the implementation to be compiled again everywhere it is included.
for example:
/*=================================================*/
/*--------------DIRECTX CONSTRUCTOR----------------*/
/*=================================================*/
DX9::DX9(HINSTANCE& inst, int cmdShow, const std::string& title, ush wndwidth, ush wndheight, short wndx, short wndy)
{
.... et al
put that in it's own cpp