I am having issues with my code. I am making a class to wrap around some WinAPI to create GUIs, however I am having issues when attempting to register the class.
My code:
inline Window::Window(const TCHAR *windowName, const int x, const int y, const int width, const int height, const TCHAR *className) : abstractWindow() {
Window(0, className, windowName, WS_OVERLAPPEDWINDOW, x, y, width, height, NULL, NULL, NULL, NULL);
}
Window::Window(const DWORD dwExStyle, const TCHAR *lpClassName, const TCHAR *lpWindowName, const DWORD dwStyle, const int x, const int y, const int nWidth, const int nHeight, const HWND hWndParent, const HMENU hMenu, const HINSTANCE hInstance, const LPVOID lpParam) : abstractWindow() {
_proc = (WNDPROC*) &abstractWindow::msgRouter;
_styleEx = dwExStyle;
_className = (!lpClassName) ? TEXT("MyGuiClass") : lpClassName;
_windowName = lpWindowName;
_style = dwStyle;
_x = x;
_y = y;
_width = nWidth;
_height = nHeight;
_hwndParent = hWndParent;
_hInstance = (!hInstance) ? ::GetModuleHandle(NULL) : hInstance;
_hMenu = hMenu;
_lpParam = lpParam;
_wndClassEx.cbSize = sizeof(_wndClassEx);
_wndClassEx.style = CS_HREDRAW | CS_VREDRAW;
_wndClassEx.lpfnWndProc = abstractWindow::msgRouter;
_wndClassEx.cbClsExtra = 0;
_wndClassEx.cbWndExtra = 0;
_wndClassEx.hInstance = _hInstance;
_wndClassEx.hIcon = ::LoadIcon(NULL, IDI_APPLICATION);
_wndClassEx.hCursor = ::LoadCursor(NULL, IDC_ARROW);
_wndClassEx.hbrBackground = (HBRUSH) COLOR_WINDOW;
_wndClassEx.lpszMenuName = NULL;
_wndClassEx.lpszClassName = _className;
_wndClassEx.hIconSm = ::LoadIcon(NULL, IDI_APPLICATION);
}
_wndClassEx is already defined in the class header as of WNDCLASSEX and the register function simply runs RegisterClassEx(&_wndClassEx).
The following are how I call these classes: (However only one is called at a time)
Window gui (TEXT("Title"), 10, 10, 500, 250);
Window gui (0, NULL, TEXT("Title"), WS_OVERLAPPEDWINDOW, 10, 10, 500, 200, NULL, NULL, hInstance, NULL);
The second one works perfectly fine, however when I call the first (shorter parameters, which puts it through to the second) class registration fails. I have completely written the _wndClassEx as well as gone through every single one and modified it to no success. I have gone through with a debugger and everything seems fine. So I have absolutely no idea what to do.
By the way, abstractWindow::msgRouter is static.
Thanks.
The problem is with this constructor:
inline Window::Window(const TCHAR *windowName, const int x, const int y, const int width, const int height, const TCHAR *className) : abstractWindow() {
Window(0, className, windowName, WS_OVERLAPPEDWINDOW, x, y, width, height, NULL, NULL, NULL, NULL);
}
You can't call a constructor from another constructor like that. What ends up happening is that a temporary object is created and then immediatly discarded. The way to achieve that (this only works if you have a compiler which implements this feature from the new C++11 Standard) is if you say
inline Window::Window(const TCHAR *windowName, const int x, const int y, const int width, const int height, const TCHAR *className) : Window(0, className, windowName, WS_OVERLAPPEDWINDOW, x, y, width, height, NULL, NULL, NULL, NULL) {};
Another way would be to do what #aztaroth said: create a separate method and call it from both constructors (that works even with an older compiler).
Write a method that initializes the window (basically cut and paste the second constructor), then call it with proper values from both constructors.
Related
Currently I wrote some code that loads original image with WIC, stores it in variable as ID2D1Bitmap* and then creates another resized one, via compatible render target and scale effect (I can provide example, if needed), so, for every basic image I have two bitmaps.
However, bitmaps use a lot of ram — loading just 10 2mb images costs more than 100mb of ram. I don’t understand why it uses ram at all, if it should be in GPU memory, as I understand.
So, I asking here the solution to reduce that ram usage.
I read about atlas method, but it seems to be hard to develop. Maybe there are another tricks?
Example of code
#include <Windows.h>
HDC hdcDevice = GetDC(NULL);
int xw = GetDeviceCaps(hdcDevice, HORZRES);
int yw = GetDeviceCaps(hdcDevice, VERTRES);
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp);
#include <d2d1_1.h>
#include <dwrite.h>
#include <wincodec.h>
#pragma comment(lib, "d2d1")
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "dwrite.lib")
using namespace std;
template<class Interface>
inline void SafeRelease(
Interface** ppInterfaceToRelease)
{
if (*ppInterfaceToRelease != NULL)
{
(*ppInterfaceToRelease)->Release();
(*ppInterfaceToRelease) = NULL;
}
}
ID2D1Bitmap* bitmap;
ID2D1Factory* factory;
IWICImagingFactory* d2dWICFactory;
IWICFormatConverter* d2dConverter;
IDWriteFactory* writeFactory;
IWICFormatConverter* d2dConverter2 = nullptr;
ID2D1BitmapRenderTarget* back = nullptr;
ID2D1DeviceContext* tar = nullptr;
ID2D1DeviceContext* target = nullptr;
ID2D1Effect* scale = nullptr;
class UIElement
{
public:
ID2D1Bitmap* imgOrig;
ID2D1Bitmap* img;
D2D1_SIZE_F si;
ID2D1DeviceContext* tar;
float x;
float y;
float width;
float height;
UIElement(ID2D1DeviceContext *tar, float x, float y, float width, float height)
{
this->tar = tar;
this->x = x; this->y = y; this->width = width; this->height = height;
this->img = nullptr;
scale->SetValue(D2D1_SCALE_PROP_INTERPOLATION_MODE, D2D1_INTERPOLATION_MODE::D2D1_INTERPOLATION_MODE_HIGH_QUALITY_CUBIC);
}
void setBackgroundImage(const wchar_t* path)
{
IWICBitmapDecoder* d2dDecoder;
IWICBitmapFrameDecode* d2dBmpSrc;
IWICFormatConverter* d2dConverter2 = nullptr;
d2dWICFactory->CreateFormatConverter(&d2dConverter2);
d2dWICFactory->CreateDecoderFromFilename(path, NULL, GENERIC_READ,
WICDecodeMetadataCacheOnLoad, &d2dDecoder);
if (d2dDecoder)
{
d2dDecoder->GetFrame(0, &d2dBmpSrc);
if (d2dBmpSrc && d2dConverter2)
{
d2dConverter2->Initialize(d2dBmpSrc, GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone, NULL, 0.f, WICBitmapPaletteTypeMedianCut);
tar->CreateBitmapFromWicBitmap(d2dConverter2, NULL, &imgOrig);
if (imgOrig)
{
si = imgOrig->GetSize();
RescaleImage();
}
}
}
SafeRelease(&d2dConverter2);
SafeRelease(&d2dDecoder);
SafeRelease(&d2dBmpSrc);
}
inline void RescaleImage(ID2D1Bitmap* cache = nullptr)
{
SafeRelease(&img);
tar->CreateBitmap(D2D1::SizeU(width, height), 0, 0, D2D1::BitmapProperties(
D2D1::PixelFormat(DXGI_FORMAT::DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE::D2D1_ALPHA_MODE_PREMULTIPLIED)
), &img);
if (cache != nullptr)
scale->SetInput(0, cache);
else if (this->imgOrig)
scale->SetInput(0, this->imgOrig);
scale->SetValue(D2D1_SCALE_PROP_SCALE, D2D1::Vector2F(this->width / si.width, this->height / si.height));
ID2D1BitmapRenderTarget* rnd = nullptr;
tar->CreateCompatibleRenderTarget(D2D1::SizeF(width, height), &rnd);
ID2D1DeviceContext* rndc = nullptr;
rnd->QueryInterface(&rndc);
rndc->BeginDraw();
rndc->DrawImage(scale);
rndc->EndDraw();
img->CopyFromRenderTarget(0, rndc, 0);
SafeRelease(&rndc);
SafeRelease(&rnd);
}
inline void Render()
{
D2D1_RECT_F rect = D2D1::RectF(this->x, this->y, this->x + this->width, this->y + this->height);
if(img)
this->tar->DrawBitmap(img, rect);
}
}*elements[100] = { NULL };
inline void Render()
{
tar->BeginDraw();
tar->Clear(D2D1::ColorF(1,1,1,1));
target->BeginDraw();
target->Clear(D2D1::ColorF(1,0,1,1));
for (int i = 0; i < 100 && elements[i]; i++)
elements[i]->Render();
auto hr = target->EndDraw();
tar->DrawImage(bitmap);
hr = tar->EndDraw();
}
int WINAPI WinMain(HINSTANCE hin, HINSTANCE, LPSTR, int)
{
ReleaseDC(NULL, hdcDevice);
WNDCLASS c = { NULL };
c.lpszClassName = L"asd";
c.lpfnWndProc = WndProc;
c.hInstance = hin;
c.style = CS_VREDRAW | CS_HREDRAW;
c.hCursor = LoadCursor(NULL, IDC_ARROW);
c.hbrBackground = CreateSolidBrush(RGB(255, 255, 255));
RegisterClass(&c);
int cx = 500, cy = 500;
int x = xw / 2 - cx / 2, y = yw / 2 - cy / 2;
HWND hwnd = CreateWindowEx(NULL, L"asd", L"asd", WS_POPUP | WS_VISIBLE, x, y, cx, cy, NULL, NULL, hin, 0);
HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
CoInitialize(NULL);
D2D1CreateFactory(D2D1_FACTORY_TYPE::D2D1_FACTORY_TYPE_MULTI_THREADED, &factory);
CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
__uuidof(IWICImagingFactory), (void**)(&d2dWICFactory));
d2dWICFactory->CreateFormatConverter(&d2dConverter);
DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(writeFactory),
reinterpret_cast<IUnknown**>(&writeFactory)
);
d2dWICFactory->CreateFormatConverter(&d2dConverter2);
D2D1_SIZE_U size = D2D1::SizeU(cx, cy);
ID2D1HwndRenderTarget* a = nullptr;
factory->CreateHwndRenderTarget(D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED)), D2D1::HwndRenderTargetProperties(hwnd, size), &a);//);
a->QueryInterface(&tar);
tar->CreateCompatibleRenderTarget(&back);
back->QueryInterface(&target);
back->GetBitmap(&bitmap);
target->CreateEffect(CLSID_D2D1Scale, &scale);
scale->SetValue(D2D1_SCALE_PROP_INTERPOLATION_MODE, D2D1_INTERPOLATION_MODE::D2D1_INTERPOLATION_MODE_HIGH_QUALITY_CUBIC);
MSG msg;
for (int i = 0; i < 10; i++)
{
elements[i] = new UIElement(target, 50*i, 10, 50, 50);
elements[i]->setBackgroundImage(L"bitmap.bmp");
}
while (GetMessage(&msg, NULL, 0, 0))
{
Render();
TranslateMessage(&msg);
DispatchMessage(&msg);
}
CoUninitialize();
return 0;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
{
switch (message)
{
case WM_LBUTTONDOWN:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wp, lp);
}
return NULL;
}
*I want Windows 7 support.
As Simon Mourier pointed in comments, it seems that in my code WIC bitmap's memory, allocated at RAM is not being free, even despite on realizing all wic's com objects.
So, I tried to get bitmap from wic not to final direct2d bitmap I need but for temporary direct2d bitmap, then create empty final direct2d bitmap, copy there temp bitmap and release temp bitmap.
This worked, now with 10 2mb png images (with their resized duplicates) my program uses few megabytes of RAM, and earlier about 120mb.
// WIC loading stuff
ID2D1Bitmap *temp = nullptr;
ID2D1Bitmap *imgOrig = nullptr;
target->CreateBitmapFromWicBitmap(d2dConverter, NULL, &temp);
if (temp)
{
D2D1_SIZE_F size = temp->GetSize();
target->CreateBitmap(D2D1::SizeU(size.width, size.height), 0, 0, D2D1::BitmapProperties(
D2D1::PixelFormat(DXGI_FORMAT::DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE::D2D1_ALPHA_MODE_PREMULTIPLIED)
), &imgOrig);
imgOrig->CopyFromBitmap(0, temp, 0);
SafeRelease(&temp);
}
// Release WIC
I have create a custom scroll bar with transparency option. The way this transparency works is very simple, I invalidate the required region and let the parent to erase and paint itself, after that I repaint the scroll bar itself. Here's some piece of code:
void Refresh(bool bForceOwnerRedraw)
{
if (Gui.OwnerRedraw || bForceOwnerRedraw)
InvalidateBackgroundRegion(State.CurrentState);
RedrawWindow(Gui.OwnerWindow, &Gui.DrawingRectangle, NULL, RDW_INVALIDATE | RDW_NOERASE | RDW_INTERNALPAINT);
}
void InvalidateBackgroundRegion(DWORD State)
{
HWND hWndParent = GetParent(Gui.OwnerWindow);
POINT p = {0};
MapWindowPoints(Gui.OwnerWindow, hWndParent, &p, 1);
HRGN BackGroundRegion = CreateRectRgn(Gui.DrawingRectangle.left + p.x, Gui.DrawingRectangle.top + p.y, Gui.DrawingRectangle.right + p.x, Gui.DrawingRectangle.bottom + p.y);
HRGN MainRegion = NULL;
if (State & SELECTED || State & SELECTED_HOVER)
{
int Width = Gui.DrawingRectangle.left + Position.SelectedState.MainDrawing.right + p.x + 1,
Height = Gui.DrawingRectangle.top + Position.SelectedState.MainDrawing.bottom + p.y + 1;
MainRegion = CreateRoundRectRgn(Position.SelectedState.MainDrawing.left + Gui.DrawingRectangle.left + p.x, Position.SelectedState.MainDrawing.top + Gui.DrawingRectangle.top + p.y, Width, Height, Gui.uiCornerRoundness, Gui.uiCornerRoundness);
}
else if (State & UNSELECTED || State & UNSELECTED_HOVER)
{
int Width = Gui.DrawingRectangle.left + Position.UnselectedState.MainDrawing.right + p.x + 1,
Height = Gui.DrawingRectangle.top + Position.UnselectedState.MainDrawing.bottom + p.y + 1;
MainRegion = CreateRoundRectRgn(Position.UnselectedState.MainDrawing.left+Gui.DrawingRectangle.left+p.x, Position.UnselectedState.MainDrawing.top+Gui.DrawingRectangle.top+p.y, Width, Height, Gui.uiCornerRoundness, Gui.uiCornerRoundness);
}
else if (State & INTERMEDIATE || State & INTERMEDIATE_HOVER)
{
int Width = Gui.DrawingRectangle.left + Position.IntermediateState.MainDrawing.right + p.x + 1,
Height = Gui.DrawingRectangle.top + Position.IntermediateState.MainDrawing.bottom + p.y + 1;
MainRegion = CreateRoundRectRgn(Position.IntermediateState.MainDrawing.left + Gui.DrawingRectangle.left + p.x, Position.IntermediateState.MainDrawing.top + Gui.DrawingRectangle.top + p.y, Width, Height, Gui.uiCornerRoundness, Gui.uiCornerRoundness);
}
CombineRgn(BackGroundRegion, BackGroundRegion, MainRegion, RGN_DIFF);
RedrawWindow(hWndParent, NULL, BackGroundRegion, RDW_INVALIDATE | RDW_ERASE | RDW_INTERNALPAINT);
DeleteObject(MainRegion);
DeleteObject(BackGroundRegion);
}
The problem occurs when I resize the main window, everything flickers. However I can prevent that by using WS_CLIPCHILDREN flag on main window, but then my scroll bar looses it's transparency, because I no longer can't invalidate parts, that are owned by child windows.
What I have tried so far:
Before invalidating parent, I removed WS_CLIPCHILDREN flag, repainted, and then set WS_CLIPCHILDREN flag back. [Result: It worked, however my CPU usage went over 30%, so it's a no no.]
Tried validating child windows (without WS_CLIPCHILDREN), before erasing and repainting.
[Result: didn't work, don't know why... maybe I... nope no idea.]
Completely disabled all repainting in my scroll bar (without WS_CLIPCHILDREN) [Result: didn't work, still flickers.]
What I would like to achieve here is to find a way to to bypass WS_CLIPCHILDREN by invalidating window manually (maybe somehow invalidating using SendMessage() to bypass it). Any other suggestion are also welcome. Thanks
EDIT:
Some more information about how I create my scroll bar. In the code below you can see that my scroll bar is just an empty child window with WS_VISIBLE and WS_CHILD flags, all of the painting is done using good old gdi.
void RegisterScrollbarClass()
{
if (RegisteredClasses.bCustomScrollBar)
return;
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = BaseWindow::stWinMsgHandler;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = NULL;
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = TEXT("CUSTOM_SCROLLBAR");
wc.hIconSm = NULL;
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, TEXT("Button Class Registration Failed!"), TEXT("ERROR!"), MB_ICONERROR);
exit(EXIT_FAILURE);
}
RegisteredClasses.bCustomScrollBar = true;
}
HWND CreateScrollbar(DWORD dwExStyle, LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam)
{
DWORD ScrollbarStyle = NULL, Child = NULL;
if ((dwStyle & SB_VERT) == SB_VERT)
ScrollbarStyle = SB_VERT;
else if ((dwStyle & SB_HORZ) == SB_HORZ)
ScrollbarStyle = SB_HORZ;
else
return NULL;
if ((dwStyle & WS_CHILD) == WS_CHILD)
Child = WS_CHILD;
if ((dwStyle & WS_VISIBLE) == WS_VISIBLE)
Child |= WS_VISIBLE;
RegisterScrollbarClass();
Scrollbar.push_back(CustomScrollbar(ScrollbarStyle, x, y, nWidth, nHeight, (int)hMenu));
for(unsigned int i = 0; i < Scrollbar.size(); i++)
Scrollbar.at(i).Create();
if (Scrollbar.at(Scrollbar.size()-1).Create(dwExStyle, lpClassName, NULL, Child, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam) != NULL)
{
if (Scrollbar.size() == 2)
Scrollbar.at(Scrollbar.size() - 1).EnableTransparent(true);
return Scrollbar.at(Scrollbar.size()-1).WindowHandle();
}
else
{
Scrollbar.pop_back();
return NULL;
}
}
Here you can download sample program: http://www.putlocker.com/file/B8704C613BC7EC96
SOLVED:
Thanks to Raymond Chen, I have removed CS_HREDRAW | CS_VREDRAW from my Scroll bar class and I works like a charm without WS_CLIPCHILDREN.
EDIT : Now this is strange, if I move the call to jItems::populate ( std::string myList ) to the constructor of jDropDown::jDropDown from else where in the jDropDown::jDropDown, the child windows get created.
Originally its been called when the dropdown(jDropDown) window is made visible(shown), and the flow of the program doesn't allow a call to jItems::populate ( std::string myList ) be moved to constructor of jDropDown::jDropDown.
What I an trying to do is create a custom Dropdown box from scratch, the problem I am facing is the final Items(jItem) windows are not created, its an oop design and
every Items(jItem) is derived from jPanel, the other parts of the dropdown box are also drived from jPanel so creating each and every window follows the same process yet the final
Items(jItem) windows are not created, they are not visible and I can't find them with visual studio Spy++
I have checked for instance handle and window handle, and both the checks returns true, yet the jItem windows are not visible and can't find them in spy++ (I can see all the other windows in spy++)
Any help is appreciated.
Here is a reference image and some relevant code.
bool jPanel::registered = false;
jPanel::jPanel( std::string txt, int x, int y, int width, int height, HWND parent, HINSTANCE hInstance, WORD bitmap, DWORD style )
: jControl( parent, hInstance, bitmap )
{
if ( ! registered )
{
WNDCLASSEX wincl;
wincl.hInstance = hInstance;
wincl.lpszClassName = "jPanel";
wincl.lpfnWndProc = WndProc;
wincl.style = CS_BYTEALIGNWINDOW;
wincl.cbSize = sizeof ( WNDCLASSEX );
wincl.hIcon = 0;
wincl.hIconSm = 0;
wincl.hCursor = ::LoadCursor ( NULL, IDC_ARROW );
wincl.lpszMenuName = NULL;
wincl.cbClsExtra = 0;
wincl.cbWndExtra = 4;
wincl.hbrBackground = ::CreateSolidBrush ( backgroundColor );
::RegisterClassEx ( &wincl );
jPanel::registered = true;
}
DWORD flag = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CHILD;
if ( style ) flag = flag | style;
hwnd = ::CreateWindowEx ( 0, "jPanel", txt.c_str ( ), flag, x, y, width, height, parent, 0, hInstance, ( LPVOID ) this ) ;
};
jDropDown::jDropDown ( std::string txt, int x, int y, int width, int height, HWND parent, HINSTANCE hInstance, WORD bitmap )
: jPanel ( txt, x, y, width, height, parent, hInstance, bitmap ), capture ( false ), populated ( false )
{
RECT rect;
::GetWindowRect ( hwnd, &rect );
::MapWindowPoints ( HWND_DESKTOP, ::GetParent ( parent ), ( LPPOINT ) &rect, 2 );
items = new jItems ( "My Items List", rect.left, rect.top + height, width, 300, ::GetParent( parent ), hInstance, 0 );
items->setBackgroundColor ( RGB ( 100, 100, 100 ) );
};
jItems::jItems ( std::string txt, int x, int y, int width, int height, HWND parent, HINSTANCE hInstance, WORD bitmap )
: jPanel ( txt, x, y, width, height, parent, hInstance, bitmap ), wWidth ( width ), wHeight ( 30 )
{
::SetWindowPos ( this->hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
};
bool jItems::populate ( std::string myList )
{
int y = 0;
Hinstance hInstance = ::GetModuleHandle ( NULL );
std::vector < std::string > list = model::Service::explode ( "^", myList );
for ( std::vector < std::string >::const_iterator it = list.begin ( ); it != list.end ( ); ++it )
{
std::string s = *it;
jItem *i = new jItem ( "Your Item", 0, y, wWidth, wHeight, this->hwnd, hInstance, 0 );
}
::SetWindowPos ( this->hwnd, HWND_TOP, 0, 0, wWidth, list.size ( ) * wHeight, SWP_NOMOVE | SWP_NOZORDER );
return true;
};
jItem::jItem ( std::string txt, int x, int y, int width, int height, HWND parent, HINSTANCE hInstance, WORD bitmap )
: jPanel ( txt, x, y, width, height, parent, hInstance, bitmap ), empty ( false )
{
this->setBackgroundColor ( RGB ( 65, 65, 65 ) );
};
I get
Debug assertion failed.
p!=0
and it points to:
_NoAddRefReleaseOnCComPtr<T>* operator->() const throw()
{
ATLASSERT(p!=NULL);
return (_NoAddRefReleaseOnCComPtr<T>*)p;
}
in 'atlcomcli.h'
From what I understand it means I have forgot to initialize a pointer somewhere, but all of them seem to be initialized.
When I use normal pointers instead of 'CComPtr', it throws 'Access Violation Reading Location' at 'font->DrawTextA' in 'D3DFont::Draw' in D3DFont.cpp
//D3DFont.h:
#include <D3DX10.h>
#include <atlbase.h>
#include <string>
class D3DFont
{
public:
D3DFont(void);
~D3DFont(void);
bool Create(ID3D10Device *device, std::string name, int width,
int height, int weight, int mipLevels, bool italic, BYTE charset,
BYTE quality, BYTE pitchAndFamily);
void Draw(LPD3DX10SPRITE sprite, std::string text, int charCount,
LPRECT rect, UINT format, D3DXCOLOR color);
private:
CComPtr<ID3DX10Font> font;
};
//D3DFont.cpp:
#include "D3DFont.h"
D3DFont::D3DFont(void){}
D3DFont::~D3DFont(void){}
bool D3DFont::Create( ID3D10Device *device, std::string name,
int width, int height, int weight, int mipLevels, bool italic,
BYTE charset, BYTE quality, BYTE pitchAndFamily )
{
D3DX10_FONT_DESC fd;
ZeroMemory(&fd, sizeof(D3DX10_FONT_DESC));
fd.Height = height;
fd.Width = width;
fd.Weight = weight;
fd.MipLevels = mipLevels;
fd.Italic = italic;
fd.CharSet = charset;
fd.Quality = quality;
fd.PitchAndFamily = pitchAndFamily;
strcpy_s(fd.FaceName, name.c_str());
// INITIALIZING FONT HERE
D3DX10CreateFontIndirect(device, &fd, &font);
return true;
}
void D3DFont::Draw( LPD3DX10SPRITE sprite, std::string text,
int charCount, LPRECT rect, UINT format, D3DXCOLOR color )
{
// ERROR HERE
font->DrawTextA(sprite, text.c_str(), charCount, rect, format, color);
}
And my use of above functions:
if( !font.Create(d3d.GetDevice(), "Impact", 0, 175, 0, 1, false,
OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE) )
{
MessageBox(0, "Could not create font.", "Error!", MB_OK | MB_ICONERROR);
}
// later on...
RECT r = {35, 50, 0, 0};
font.Draw(0, "Test", -1, &r, DT_NOCLIP, d3d.GetColorObj(1.0f, 1.0f, 0.0f, 1.0f));
What could I miss?
'D3DX10CreateFontIndirect' throws 0x8876086C
Can't find what does it mean, but some google threads are related to d3dDevice, so I guess it must be related to it. Will update when I will have more info.
Calling the D3DX10CreateFontIndirect doesn't actually guarantee that your pointer will be initialized.
Rule of thumb : ALWAYS check HRESULTs when using DirectX functions that initialize a pointer:
HRESULT hr = D3DX10CreateFontIndirect(device, &fd, &font);
if(FAILED(hr)){
//Get the last error, display a message, etc.
//Eventually propagate the error if the code can't continue
//with the font pointer uninitialized.
}
When your function returns E_FAIL, do not try to use the pointer afterward. There are great chances that the values of the parameters are simply incorrect (here, your device pointer might be null or your font description might be incorrect).
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
Why does this happen?
1>------ Build started: Project: Client, Configuration: Debug Win32 ------
1> WindowManager.cpp
1> Generating Code...
1> Compiling...
1> Main.cpp
1> Generating Code...
1>WindowManager.obj : error LNK2001: unresolved external symbol
"private: static int WindowManager::win_stat" (?win_stat#WindowManager##0HA)
1>C:\Users\user\documents\visual studio
2012\Projects\TalkToMe\Debug\Client.exe : fatal error LNK1120: 1 unresolved externals
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
WindowManager.cpp
#include "WindowManager.h"
void WindowManager::PekMessage()
{
if(PeekMessage(&msg, window, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
bool WindowManager::isWindowOpen()
{
return win_stat != -1;
}
HWND WindowManager::textbox(int width, int height, int xPos, int yPos, LPCSTR content, bool edit_able)
{
int type = (edit_able) ? (WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL) : (WS_CHILD|WS_VISIBLE|WS_HSCROLL|ES_AUTOHSCROLL);
return CreateWindowEx(
WS_EX_CLIENTEDGE,
"EDIT",
content,
type,
xPos,
yPos,
width,
height,
window,
(HMENU)50,
GetModuleHandle(NULL),
NULL
);
}
HWND WindowManager::textbox(Vector size, Vector position, LPCSTR content, bool edit_able)
{
return textbox(size.getX(), size.getY(), position.getX(), position.getY(), content, edit_able);
}
LRESULT CALLBACK WindowManager::WindowProcedure(HWND winhan,UINT uint_Message,WPARAM parameter1,LPARAM parameter2)
{
switch(uint_Message)
{
case 16: // exit button
win_stat = -1;
break;
}
return DefWindowProc(winhan,uint_Message,parameter1,parameter2);
}
WindowManager::WindowManager(LPCTSTR title,int x, int y, int width, int height)
{
WNDCLASSEX wnd;
wnd.cbSize = sizeof(wnd);
wnd.style = CS_HREDRAW | CS_VREDRAW;
wnd.lpfnWndProc = WindowProcedure;
wnd.cbClsExtra = 0;
wnd.cbWndExtra = 0;
wnd.hInstance = GetModuleHandle(NULL);
wnd.hIcon = NULL;
wnd.hCursor = LoadCursor(NULL,IDC_ARROW);
wnd.hbrBackground = GetSysColorBrush(NULL);
wnd.lpszClassName = "TalkToMe";
wnd.lpszMenuName = NULL;
wnd.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&wnd);
window = CreateWindowEx(WS_EX_CONTROLPARENT, wnd.lpszClassName, title,
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE, x, y, width, height,NULL, NULL,
GetModuleHandle(NULL), NULL);
}
WindowManager::~WindowManager()
{
DestroyWindow(window);
}
WindowManager.h
#pragma once
#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#include <Windows.h>
#include "Vector.h"
class WindowManager
{
private:
MSG msg;
HWND window;
static int win_stat;
public:
WindowManager(LPCTSTR title,int x, int y, int width, int height);
~WindowManager();
static LRESULT CALLBACK WindowProcedure(HWND winhan,UINT uint_Message,WPARAM parameter1,LPARAM parameter2);
HWND textbox(int width, int height, int xPos, int yPos, LPCSTR content, bool edit_able=true);
HWND textbox(Vector size, Vector position, LPCSTR content, bool edit_able=true);
bool isWindowOpen();
void PekMessage();
};
The part in the header
static int win_stat;
is only a declaration. You also have to add
int WindowManager::win_stat;
to the .cpp file, just like you define the member functions there.