GetTextExtentPoint32(m_hAttribDC, lpszString, nCount, &size)) - mfc

My program is to display some points with their positions(x,y) on a graph. When I use mouse to drag any point, its position will automatically changed. Updated position is implemented following this code(using thread):
m_thread =AfxBeginThread((AFX_THREADPROC)MainThread,this)
UINT CAtwWnd::MainThread(LPVOID pParam)
{
CAtwWnd *pMainDlg = (CAtwWnd*)pParam;
static SChartXYPoint pPoint;
TCHAR strTemp[32]={0,};
while(1)
{
pMainDlg->m_chart.EnableRefresh(false);
pMainDlg->InitGraph1();
wsprintf(strTemp, _T("[%d](%d,%d)"), (int)index,(int)xPoint,(int) yPoint);
pBalloon[index]->SetLabelText(strTemp);
pBalloon[index] = pMainDlg->m_pPointSeries->CreateBalloonLabel(index, strTemp);
pBalloon[index]->SetVisisble(true);
pMainDlg->m_pPointSeries->SetVisible(true);
pMainDlg->m_chart.EnableRefresh(true);
pMainDlg->SetAtwGraphStep(1);
}
return 0;
}
Mean while:
void CChartLabel<PointType>::SetLabelText(const TChartString& strText)
{
m_strLabelText = strText;
m_pParentCtrl->RefreshCtrlAtw();
}
And:
void CChartCtrl::RefreshCtrlAtw()
{
// Window is not created yet, so skip the refresh.
if (!GetSafeHwnd())
return;
if (m_iEnableRefresh < 1)
{
m_bPendingRefresh = true;
return;
}
// Retrieve the client rect and initialize the
// plotting rect
CClientDC dc(this) ;
CRect ClientRect;
GetClientRect(&ClientRect);
m_PlottingRect = ClientRect;
// If the backgroundDC was not created yet, create it (it
// is used to avoid flickering).
if (!m_BackgroundDC.GetSafeHdc() )
{
CBitmap memBitmap;
m_BackgroundDC.CreateCompatibleDC(&dc) ;
memBitmap.CreateCompatibleBitmap(&dc, ClientRect.Width(),ClientRect.Height()) ;
m_BackgroundDC.SelectObject(&memBitmap) ;
}
// Draw the chart background, which is not part of
// the DrawChart function (to avoid a background when
// printing).
DrawBackground(&m_BackgroundDC, ClientRect);
ClientRect.DeflateRect(3,3);
DrawChart(&m_BackgroundDC,ClientRect);
for (int i=0; i<4 ;i++)
{
if (m_pAxes[i])
m_pAxes[i]->UpdateScrollBarPos();
}
Invalidate();
}
when dragging points on graph I gets these errors somtimes: Debug Assertion Failed ( afxwin1.inl, line 639, and 646)
_AFXWIN_INLINE CSize CDC::GetTextExtent(LPCTSTR lpszString, int nCount) const
{
ASSERT(m_hAttribDC != NULL);
SIZE size;
VERIFY(::GetTextExtentPoint32(m_hAttribDC, lpszString, nCount, &size));
return size;
}
_AFXWIN_INLINE CSize CDC::GetTextExtent(const CString& str) const
{
ASSERT(m_hAttribDC != NULL);
SIZE size;
VERIFY(::GetTextExtentPoint32(m_hAttribDC, str, (int)str.GetLength(), &size));
return size;
}
Could you help me to fix this problem? I tried to find some ways to fix but doesn't work. :(

My answer is just a guess, but the reason might be caused by using MFC objects from one thread (the creator) in a second thread. And it is a guess because you didn't told us what the ASSERT say and what VS version you are using.
The problem: When you create some objects in the MFC, the handle values are saved in a map that allows the MFC to find the object only with the handle value.
This handle maps are stored per thread.
Also if a window object stores other objects that are associated with those handle maps, the usage from another thread will fail.
So the answer can be found in the call stack. It tells you who uses such an object. And the object that causes the problem is simply identified by the ASSERT.

Related

CMemDC class issue

Here is the following CMemDC class I am using from code projects that supposedly fixes the flickering:
#ifndef _MEMDC_H_
#define _MEMDC_H_
#include "stdafx.h"
namespace MemoryDC
{
class CMemDC : public CDC {
private:
CBitmap m_bitmap; // Offscreen bitmap
CBitmap* m_oldBitmap; // bitmap originally found in CMemDC
CDC* m_pDC; // Saves CDC passed in constructor
CRect m_rect; // Rectangle of drawing area.
BOOL m_bMemDC; // TRUE if CDC really is a Memory DC.
public:
CMemDC(CDC* pDC, const CRect* pRect = NULL) : CDC()
{
ASSERT(pDC != NULL);
// Some initialization
m_pDC = pDC;
m_oldBitmap = NULL;
m_bMemDC = !pDC->IsPrinting();
// Get the rectangle to draw
if (pRect == NULL) {
pDC->GetClipBox(&m_rect);
}
else {
m_rect = *pRect;
}
if (m_bMemDC) {
// Create a Memory DC
CreateCompatibleDC(pDC);
pDC->LPtoDP(&m_rect);
m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(), m_rect.Height());
m_oldBitmap = SelectObject(&m_bitmap);
SetMapMode(pDC->GetMapMode());
SetWindowExt(pDC->GetWindowExt());
SetViewportExt(pDC->GetViewportExt());
pDC->DPtoLP(&m_rect);
SetWindowOrg(m_rect.left, m_rect.top);
}
else {
// Make a copy of the relevent parts of the current DC for printing
m_bPrinting = pDC->m_bPrinting;
m_hDC = pDC->m_hDC;
m_hAttribDC = pDC->m_hAttribDC;
}
// Fill background
FillSolidRect(m_rect, pDC->GetBkColor());
}
~CMemDC()
{
if (m_bMemDC) {
// Copy the offscreen bitmap onto the screen.
m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),
this, m_rect.left, m_rect.top, SRCCOPY);
//Swap back the original bitmap.
SelectObject(m_oldBitmap);
}
else {
// All we need to do is replace the DC with an illegal value,
// this keeps us from accidently deleting the handles associated with
// the CDC that was passed to the constructor.
m_hDC = m_hAttribDC = NULL;
}
}
// Allow usage as a pointer
CMemDC* operator->()
{
return this;
}
// Allow usage as a pointer
operator CMemDC*()
{
return this;
}
};
}
#endif
Here is my OnDraw function using above class:
void ViewerView::OnDraw(CDC* pDC)
{
MemoryDC::CMemDC dc(pDC);
ViewerDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
else
RenderPage(dc, 0);
}
And here is the OnEraseBkgnd function:
BOOL ViewerView::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
}
Here is the following video which best describes what is happening to my scrolling since a video is worth a thousand words
I tried double buffering and what not to fix this issue, but I am not having a good time.
If anyone has any suggestions or help much is appreciated.
Salute.
Do not reinvent the wheel.
MFC already has a memory DC class, you can easily use it like this:
void ViewerView::OnDraw(CDC* pDC)
{
CRect rc;
GetClientRect(&rc);
CMemDC memDC(*pDC, rc);
auto& rDC = memDC.GetDC();
RenderPage(&rDC, 0);
}
As a sidenote:
If you don't want the system to erase the background for you every time, you should return TRUE from the OnEraseBkgnd function.

Winapi c++ trying to get primary monitor's brightness

I tried to get the brightness of the primary monitor using the following code:
POINT monitorPoint = { 0, 0 };
HANDLE monitor = MonitorFromPoint(monitorPoint, MONITOR_DEFAULTTOPRIMARY);
DWORD minb, maxb, currb;
if (GetMonitorBrightness(monitor, &minb, &currb, &maxb) == FALSE) {
std::cout << GetLastError() << std::endl;
}
But it fails and GetLastError() returns 87 which means Invalid Parameter.
EDIT: I managed to solve this using EnumDisplayMonitors() and GetPhysicalMonitorsFromHMONITOR() like this:
std::vector<HANDLE> pMonitors;
BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
DWORD npm;
GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor, &npm);
PHYSICAL_MONITOR *pPhysicalMonitorArray = new PHYSICAL_MONITOR[npm];
GetPhysicalMonitorsFromHMONITOR(hMonitor, npm, pPhysicalMonitorArray);
for (unsigned int j = 0; j < npm; ++j) {
pMonitors.push_back(pPhysicalMonitorArray[j].hPhysicalMonitor);
}
delete pPhysicalMonitorArray;
return TRUE;
}
// and later inside main simply:
EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, NULL);
// and when I need to change the brightness:
for (unsigned int i = 0; i < pMonitors.size(); ++i) {
SetMonitorBrightness(pMonitors.at(i), newValue);
}
Now I encounter 2 new problems:
1) From EnumDisplayMonitors() I get 2 monitor handles since I have 2 monitors. The problem is that only my primary works. Whenever I try to so something with the secondary monitor I get this error:
0xC0262582: ERROR_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA
2) After using SetMonitorBrightness() for some time it stops working even for the primary monitor and I get the following error:
0xC026258D
You are passing an HMONITOR to the function. However, its documentation states that a handle to a physical monitor is required instead, and suggests that you call GetPhysicalMonitorsFromHMONITOR() to obtain it. Indeed, since MonitorFromPoint() returns an HMONITOR your code would have failed to compile with STRICT enabled, a practise that helps root out such mistakes.
You should include error checking for the call to MonitorFromPoint(). And the documentation also suggests that you should call GetMonitorCapabilities() passing MC_CAPS_BRIGHTNESS to make sure the monitor supports brightness requests.
Please refer to the documentation of GetMonitorBrightness() for more detail:

CImage destructor issue?

I am using the function below to process an image in real time. The function is called every 10 seconds using a timer.
The problem is that I get an assertion failure , and can't figure out the exact problem. I tried CImage::ReleaseDC() and DeleteDC() for the ImageDC but no luck.
Any ideas ?
LRESULT CAutodetectDialog::AutoscanPatterns(WPARAM, LPARAM)
{
HWND hwnd = ::FindWindow(NULL, windowTitle);
if (hwnd != NULL)
for (int i=0; i<N_NUMBERS; i++)
{
CImage image;
image.Create(dbParams.width, dbParams.height, 24);
CImageDC imageDC(image);
::SetWindowOrgEx(imageDC, db.topLeft.x, dbParams.topLeft.y + i * dbParams.height, NULL);
::PrintWindow(hwnd, imageDC, PW_CLIENTONLY);
// Process the image - processing takes < 1 sec
// and the image parameter is not being changed
SaveImagePatterns(&image);
} // <------------- This line fails , must be the destructor
// of CImage : atlimage.h Line 884, m_hDC == 0
// m_hDC is not NULL in the code
return 0;
}
// Process the image - processing takes < 1 sec
// and the image parameter is not changed
void CAutodetectDialog::SaveImagePatterns(const CImage* image)
{
.........
}
This is the code that fails in atlimage.h :
inline HBITMAP CImage::Detach() throw()
{
HBITMAP hBitmap;
ATLASSUME( m_hBitmap != NULL );
ATLASSUME( m_hDC == NULL ); // <------ This guy
hBitmap = m_hBitmap;
...
...
return( hBitmap );
}
UPDATE : After commenting out the call to function SaveImagePatterns() , the assertion failure did not happen. So the problem must be in that function, despite the CImage param passed as const.
This looks suspicious:
SaveImagePatterns(&image);
Since image is a local variable, depending on what SaveImagePatterns does with it, this can cause an issue since the image object is destroyed as soon as that block is exited.
Did you call any image->GetDC() by yourself in SaveImagePatterns?
Mind that image->GetDC() need to be paired with image->ReleaseDC().
So that m_hDC will be NULL.

Worker threads and MFC controls

I'm aware of the fact that MFC GUI controls are not accessible directly from a worker thread, but for example, they getting by passing to this thread a pointer to the object instance that owns the controls. My problem is, that I'm really sure about how it goes when I'm calling functions within the scope of the worker thread, which needs to access MFC controls. Please consider the following code:
//header:
class CMyDlg : public CDialog
{
...
...
...
afx_msg void OnButtonControl();
static UNIT ControlThread(LPVOID pParam);
bool ValidateEditControl();
}
//cpp
void CMyDlg::OnButtonControl()
{
CString Text = "Hello";
GetDlgItem(IDC_EDIT_HELLO)->SetWindowText(Text);
m_hControlThread = AxtBeginThread(ControlThread, this);
}
UINT CMyDlg::ControlThread(LPVOID pParam)
{
CMyDlg *dlg = (CMyDlg*) pParam;
CString Text = "Hello";
while(SomethingIsTrue) {
bool Ret = dlg->ValidateEditControl();
if (!Ret) //Someone changed ControlEntry -> change it back
dlg->GetDlgItem(IDC_EDIT_HELLO)->SetWindowText(Text);
}
AfxEndThread(0);
}
bool CMyDlg::ValidateEditControl()
{
CString Text;
this->GetDlgItem(IDC_EDIT_HELLO)->GetWindowText(Text); // do I need the "this" pointer here, or for general how do I access my MFC control at this point?
if (Text == "Hello")
return true;
else
return false;
}
What is the best way to this?
Thank you in advance
best Greg
Without going into too much details, here is how you should do it. I have't build, judged or modified your basic code, I have just addressed your threading part of question. You should be able to take it from here.
UINT CMyDlg::ControlThread(LPVOID pParam)
{
HWND hWnd = (HWND) pParam;
CString Text = "Hello";
while(SomethingIsTrue) {
bool Ret = SendMessage(HwND, VALIDATE_CONTROL,0,0 );
if (!Ret) //Someone changed ControlEntry -> change it back
SendMessage(CHANGE_EDIT_HELLO, &Text, 0);
}
AfxEndThread(0);
}

MessageBox does not work in a catch of an exception

Well I have 2 issues but my main concern right now is my catch exception. Here is the code...
int GXRenderManager::Ignite(HINSTANCE * hinst, int * nCmd, GXDEVICE DeviceType, int width, int height)
{
try
{
GXRenderManager::hinstance = hinst;
GXRenderManager::nCmdShow = nCmd;
GXRenderManager::height = height;
GXRenderManager::width = width;
InitWindows();
switch(DeviceType)
{
case DIRECTX:
GXRenderManager::renderDevice = new GXDX;
break;
case OPENGL:
GXRenderManager::renderDevice = new GXGL;
break;
default:
throw GXException(L"Error Finding Video Device");
}
Device()->StartUp(GXRenderManager::mainWindow ,width, height); //Error happens here
}
catch(GXVideoException &e)
{
MessageBox(0,e.pReason,L"GXVideoException",1);//Catch happens but no message box
return 0;
}
catch(GXWindowsException &e)
{
MessageBox(0,e.pReason,L"Windows Error",1);
return 0;
}
catch(GXException &e)
{
MessageBox(0,e.pReason,L"Error",1);
return 0;
}
return 1;
}
Here is where the error happens
void GXDX::StartUp(HWND* mainWindow,int w, int h)
{
width = w;
height = h;
this->mainWindow = mainWindow;
ID3D10Texture2D *backBufferSurface;
DXGI_SWAP_CHAIN_DESC swapChainDesc;
swapChainDesc.BufferCount = 2;
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
swapChainDesc.BufferDesc.Width = width;
swapChainDesc.BufferDesc.Height = height;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.OutputWindow = *mainWindow;
swapChainDesc.Windowed = TRUE;
D3D10_DRIVER_TYPE driverType = D3D10_DRIVER_TYPE_HARDWARE;
HRESULT hr = D3D10CreateDeviceAndSwapChain(NULL,driverType,NULL,0,
D3D10_SDK_VERSION, &swapChainDesc,&swapChain,&dxDevice);
if(FAILED(hr))
throw GXVideoException(L"Problems retrieving directX device");
}
When I do a walk through. the D3D10CreateDeviceAndSwapChain returns a failure, therefore triggering the GXVideoException error.
It then catches and returns back to GXRenderManager class as shown below.
catch(GXVideoException &e)
{
MessageBox(0,e.pReason,L"GXVideoException",1);
return 0;
}
At this point in time, If I put my cursor over the &e, I clearly see my message "Problems retrieving directX device". But the message box does not show
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
if(GXRenderManager::Ignite(&hInstance, &nCmdShow,DIRECTX) != 1)
return 0;
//NEVER REACHES THE RUN METHOD BELOW YET THE MAIN WINDOW REMAINS OPEN
GXRenderManager::Run();
return 0;
}
Another thing I find strange is that my created window remains showing but never reaches the main loop. It is like the application is idle due to the message box, but the message box is not showing...
I also would like to add that the static member renderDevice is a interface datatype. GXDX is of course a implemented class of the interface.
GXDX class includes the GXException Header so it is able to throw those exceptions so the main GXRenderManager can catch them.
[EDIT]
Another thing I would like to add is if I remove the Show window method
ShowWindow(*GXRenderManager::mainWindow, *GXRenderManager::nCmdShow);
It works. So as long as my main application window is not open. My message box appears like its suppose to.
[EDIT]
Prior to dauphic response which fixed part of the problem, I went on and edited my code. My catch now looks like this
catch(GXVideoException &e)
{
MessageBox(*GXRenderManager::mainWindow,e.pReason,L"GXVideoException",1);
return 0;
}
But now my application opens and then immediately closes without displaying the box. mainWindow is a pointer to my base window. So I had to dereference the pointer.
[EDIT]
The windows pointer is bad
If a dialog is present, MessageBox should always be passed a handle to it, rather than 0. Only pass MessageBox 0 if no dialog is available.
Side note, I don't understand the exact reason for this, so it would be great if someone else could give insight.
It's also possible that your message box is being attached to your dialog, and because your dialog isn't active, the message box isn't showing. Pressing alt when it hangs may cause it to show.