|
Mike Landis wrote:
appreciate the fast reply, but I'm fairly certain the dialog's
ON_NOTIFY( NM_CUSTOMDRAW, IDC_PosList, OnCustDrwPosLst )
effectively filters out messages meant for controls other than PosList
Yes, I realized this right after posting the reply. Just to be 102% sure, check if you don't have duplicate control IDs in your dialog. This would screw notification routing.
At this point, I'd resort to basic debugging tricks. What are the contents of pCustomDraw structure - are members looking 'normally' or rather it's random data?
Also, according to comments in the code your program crashes when you're accessing the 0th element of the string. Maybe GetItemText returns empty one?
Tomasz Sowinski -- http://www.shooltz.com
Alika masiaka!
|
|
|
|
|
I don't think eVC 3.0 will load the resource file if you have conflicting IDs in the same dialog (I've had to fix this after hand editing the resource files before). I have hundreds of calls where I cast from CWnd* to a *Ctrl of some sort - the eVC3 documentation for CWnd::GetDlgItem says:
This method retrieves a pointer to the specified control or child window in a dialog box or other window. The pointer returned is usually cast to the type of control identified by nID.
The struct pointed to by pCustomDraw looks normal as does the nmcd struct.
You're absolutely right that GetItemTxt() could be returning an empty string. Its returning an empty string for every subitem in the list control. Why would that happen? The following:
if ( cst.GetLength() > 0 )
{ bool red = ( cst[0] == '-' );
CDC* dc = CDC::FromHandle( nmcd.hdc );
dc->SetTextColor( red ? RGB(255,0,0) : RGB(0,0,0) );
}
prevents access violations, but doesn't explain why cst comes back "" for every subitem.
In watching the code that responds to the LVN_GETDISPINFO messages to the PosListCtrl just before the CustomDraw messages come in, I can see normal looking CString values coming out of the LVN_GETDISPINFO handler:
void CSPosDialog::OnGetDispInfoPosList( NMHDR* pNMHDR, LRESULT* pResult )
{ LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
if ( pDispInfo->item.mask & LVIF_TEXT )
{ SPosListItemInfo* pItem =
(SPosListItemInfo*) pDispInfo->item.lParam;
CString cst = this->GetPosItemText( pDispInfo->item.iItem, pDispInfo->item.iSubItem );
LPTSTR pBuf = this->AddPool( &cst );
pDispInfo->item.pszText = pBuf;
}
*pResult = 0;
}
CString CSPosDialog::GetPosItemText( int rr, int si )
{ // get the sortCol for this subitem
CBOSListCtrl* pLC = (CBOSListCtrl*)this->GetDlgItem( IDC_PosList );
short msi = pLC->MapSubitem( si ); // column reordering
CHeaderCtrl* pHdr = pLC->GetHeaderCtrl();
short nItems = pHdr->GetItemCount();
if ( msi < 0 || msi >= nItems-1 ) return _T("");
SPosListItemInfo* pItem = (SPosListItemInfo*)pLC->GetItemData( rr );
if ( !pItem ) return _T(""); // impossible
CPos* pos = pItem->thePos;
bool itsTheTotalRow = ( pos == 0 );
double res;
if ( msi == 8 )
return itsTheTotalRow ? _T("") : pos->note;
unsigned short buf[20];
switch ( msi )
{ case 0:
swprintf( buf, "first col ..." );
// ...
case 7:
swprintf( buf, "other ..." );
}
CString cst( buf );
return cst;
}
CStrings coming out of OnGetDispInfoPosList(), feed AddPool(), and both look normal. Just after, in GetItemText(), all I get is "". That's the mystery.
Note, if I take all the conditions out of setting the text color in OnCustomDraw(), so it should paint subitem text in red no matter what, I still get black. That's the other mystery.
-Mike
|
|
|
|
|
Mike Landis wrote:
I have hundreds of calls where I cast from CWnd* to a *Ctrl of some sort - the eVC3 documentation for CWnd::GetDlgItem says:
This method retrieves a pointer to the specified control or child window in a dialog box or other window. The pointer returned is usually cast to the type of control identified by nID.
Well, this allows you to call wrapper methods which basically use SendMessage to expose Win32 control functionality. I'm assuming there's no associated MFC object and GetDlgItem returns temporary CWnd *. In such case you can't also use message reflection - this could contribute to your problems with NM_CUSTOMDRAW not passing through.
Anyway, the problem obviously lies in AddPool and/or related functions. I can't really comment on this, because parts of the code implementing pool are missing. I guess you should put the breakpoint in OnGetDispInfoList, in the line where pszText is actually set. You may also use TRACE to check if LVN_GETDISPINFO is handled correctly.
Wrt to changed text color - you should change the clrText member instead of using SetTextColor.
Tomasz Sowinski -- http://www.shooltz.com
Alika masiaka!
|
|
|
|
|
There are real MFC objects behind the GetDlgItem call, so I think the CWnd*s are real. I use the (cast)ptrs to call CCtrlList, CEdit, etc. functions. I'm not wrapping anything, just subclassing, so I hope I haven't killed NM_CUSTOMDRAW passthrough. The reason I don't suspect OnGetDispInfoList() is because the control behaves quite rationally in all other cases. I can scroll the view generating update events and it handily fetches the right stuff from OnGetDispInfoList() and displays it in the control.
The only other code I know is:
const unsigned short StringPoolSize = 3;
unsigned short nextFreeSlot;
CString cstPool[StringPoolSize ];
LPTSTR pBufPool[StringPoolSize ];
from the PosDialog's .h file and GetItemText in the ListCtrl itself, excerpted here:
CString CListCtrl::GetItemText(int nItem, int nSubItem) const
{
ASSERT(::IsWindow(m_hWnd));
LVITEM lvi;
memset(&lvi, 0, sizeof(LVITEM));
lvi.iSubItem = nSubItem;
CString str;
int nLen = 128;
int nRes;
do
{
nLen *= 2;
lvi.cchTextMax = nLen;
lvi.pszText = str.GetBufferSetLength(nLen);
nRes = (int)::SendMessage(m_hWnd, LVM_GETITEMTEXT, (WPARAM)nItem,
(LPARAM)&lvi);
} while (nRes == nLen-1);
str.ReleaseBuffer();
return str;
}
The chain of events is: the CustomDraw handler calls GetItemText which sends a LVM_GETITEMTEXT message, received by GetDispInfoPosList which puts the CString in the pool (calls AddPool). AddPool plays with the reference count so the CString can't be released and sends back its pool copy. The LPTSTR retVal also looks good every time and its still okay when pDispInfo->item.pszText is assigned in OnGetDispInfoPosList(). Then you're back in _AfxDispatchCmdMsg (which can hardly be screwed up). str still shows the correct value after ReleaseBuffer in GetItemText and is good when you are at the final brace. The next thing you know, you're in OnCustomDraw and the string is gone. Apparently ReleaseBuffer decrements the reference count to 0 and the string goes away when the stack unrolls.
Thinking that Blazczak's pooling didn't anticipate CustomDraw calling GetItemText(), ultimately leading to one ReleaseBuffer() call he hadn't anticipated, I tried setting:
const unsigned short StringPoolSize = 4;
in the PosDialog's .h file and modifying the circular indexing in AddPool to use StringPoolSize (instead of 3), so it now reads:
if ( ++nextFreeSlot > StringPoolSize-1 )
nextFreeSlot = 0;
No change was evident. As soon as you return from GetItemText(), where the reference count on the string was decremented by ReleaseBuffer, its gone.
There's no other code. The answer (I think) is getting the reference count to be > 1 when GetItemText releases the buffer, because str is still okay when GetItemText is about to return (still at the top of the stack).
On the color, the evc3 help doesn't show you the structure under the m_hAttribDC. In the debugger, I can see inside dc to the m_hAttribDC, but only see 'unused' within. Not sure what to do with that.
-Mike
|
|
|
|
|
Mike Landis wrote:
There are real MFC objects behind the GetDlgItem call, so I think the CWnd*s are real. I use the (cast)ptrs to call CCtrlList, CEdit, etc. functions. I'm not wrapping anything, just subclassing, so I hope I haven't killed NM_CUSTOMDRAW passthrough
If you have associated MFC objects, why do you call GetDlgItem? You should have some CListCtrl-derived objects as dialog members, and you should be able to access them easily. The fact you resorted to GetDlgItem suggests they are not there. This would explain missing NM_CUSTOMDRAWs.
On the color, the evc3 help doesn't show you the structure under the m_hAttribDC. In the debugger, I can see inside dc to the m_hAttribDC, but only see 'unused' within. Not sure what to do with that.
I'm not referring to CDC. To set the color of list item text, you don't call CDC::SetItemText. You just set the clrText member of NMLVCUSTOMDRAW to RGB you need.
Pool - is there real reason for pooling? Or you just have a feeling this would be good from perf viewpoint?
Tomasz Sowinski -- http://www.shooltz.com
*** Purgamentum init, exit purgamentum ***
|
|
|
|
|
pCustomDraw->clrText = RGB(255,0,0); works like a charm. Saw it in the structure and forgot about it until you reminded me.
I am not sure what you're referring to regarding the controls. I build up dialogs by adding controls in the resource editor. I've been finding them by calling GetDlgItem(). It's been working for responding to other messages. I didn't think NM_CUSTOMDRAW worked differently.
On Pooling - all I know is that there is a data longevity requirement which Blazczak's AddPool solves. If you don't do it absolutely nothing displays in the list control. This is behaving exactly the same way that it did before I put the pooling in. Blazczak says that you have to cache strings through two LBN_GETDISPINFO notifications after the one where you set the value.
- Mike Landis
|
|
|
|
|
Mike Landis wrote:
I am not sure what you're referring to regarding the controls. I build up dialogs by adding controls in the resource editor. I've been finding them by calling GetDlgItem(). It's been working for responding to other messages. I didn't think NM_CUSTOMDRAW worked differently.
Well, when your dialog is created, the controls are Win32 controls. More specifically, list control can be accessed as CListCtrl, but it's not CYourListCtrl unless you subclass it. This is usually by adding data member in ClassWizard (of course you can manually add CYourListCtrl as data member and insert DDX_Control call in DoDataExchange -- or use SubclassDlgItem in OnInitDialog).
Mike Landis wrote:
On Pooling - all I know is that there is a data longevity requirement which Blazczak's AddPool solves
Ok, I see what you mean. This is indeed fragile approach which can fail when you call GetItemText in custom draw handler.
I vaguely remember copying text (using strncpy) straight into item.pszText in some list control. But this was on Win32, not CE. You may try that approach - pszText may point to internal buffer when you're receiving LVN_GETDISPINFO.
Tomasz Sowinski -- http://www.shooltz.com
*** Purgamentum init, exit purgamentum ***
|
|
|
|
|
On subclassing, I've been using the Wizard to define classes. Finish the dialog in the resource, Ctrl-W, New class, etc. I think it's sewn together right. If you bring up the Wizard over any of my dialogs, you immediately see the subclass, messages, member functions...
Can you post example code or suggest a URL where strncpy is used to solve the longevity problem? I tried boosting the pool size to 12, just to see if it made any difference. It didn't. I am fairly convinced that defeating buffer release will solve this. The application is stable elsewhere.
If you find something that gets me valid CString's from GetItemText in the CustomDraw routine, I owe you $100.
- Mike Landis
|
|
|
|
|
Mike Landis wrote:
Can you post example code or suggest a URL where strncpy is used to solve the longevity problem? I tried boosting the pool size to 12, just to see if it made any difference. It didn't. I am fairly convinced that defeating buffer release will solve this. The application is stable elsewhere.
It's quite late in my timezone, so I'll do that in circa 10 hours. I'm still not sure if this will work, but I'll give it a try.
If you find something that gets me valid CString's from GetItemText in the CustomDraw routine, I owe you $100.
Can't accept that - help is 100% free at CodeProject
Tomasz Sowinski -- http://www.shooltz.com
Alika masiaka!
|
|
|
|
|
Mike Landis wrote:
On subclassing, I've been using the Wizard to define classes. Finish the dialog in the resource, Ctrl-W, New class, etc. I think it's sewn together right. If you bring up the Wizard over any of my dialogs, you immediately see the subclass, messages, member functions...
Yes, but this only takes care of subclassing the *dialog*. If you want to handle reflected notifications in list control, you'll also have to subclass it. Otherewise, nobody will scan its message map - it'll be plain Win32 control with no MFC window procedure behind. I guess haven't used ClassWizard's 'Member Vars' tab to associate CYourListCtrl with any control ID. How does DoDataExchange looks like in your dialog? It should have something like DDX_Control(pDX, IDC_LIST1, m_lst1);
Can you post example code or suggest a URL where strncpy is used to solve the longevity problem?
strncpy, or rather wcsncpy - because WinCE is Unicode only - skips over longevity. In your approach, you're trying to keep string data for some time, and you're just setting item.pszText to point inside your pool. But when your LVN_GETDISPINFO handler is called, list control itself has initialized pszText. It points to its internal buffer, managed by Windows. You can create the string you need on the fly, and instead of stuffing it into pool copy it into this buffer using wcsncpy. Here how it looks in my test app running just fine on hp1910:
void CTestListCtrl::OnGetdispinfo(NMHDR* pNMHDR, LRESULT* pResult) <br />
{<br />
LV_DISPINFO* pdi = (LV_DISPINFO*)pNMHDR;<br />
if (LVIF_TEXT & pdi->item.mask)<br />
{<br />
CString strItem;<br />
strItem.Format(_T("Item %d - %d"), pdi->item.iItem, pdi->item.iSubItem);<br />
<br />
wcsncpy(pdi->item.pszText, strItem, pdi->item.cchTextMax);<br />
}<br />
*pResult = 0;<br />
}
You don't care about the lifetime of strItem, because it is copied before leaving OnGetdispinfo.
I'm sending the source of my test app to your email account. It's 12 kb zip file; solves all problems you've reported (handles NM_CUSTOMDRAW/LVN_GETDISPINFO in list control class and changes colors of list items).
Tomasz Sowinski -- http://www.shooltz.com
Alika masiaka!
|
|
|
|
|
BTW, I have just noticed that you're casting CWnd* returned from GetDlgItem to CListCtrl-derived class. This may also contribute to your problem. Usually, one would have a dialog member represeting list control, connected to actual HWND with SubclassDlgItem or DDX_Control.
Tomasz Sowinski -- http://www.shooltz.com
Alika masiaka!
|
|
|
|
|
We have a multithreaded application, in which multiple threads call a function which has an win32 api CreateDirectory( ).
We observe a stack overflow at a location in ntdll.dll which raises from createdirectory( ) api further calling many other functions in Kernel32.dll and ntdll.dll...
When I attach the process to debugger(windbg ) and put a breakpoint at CreateDirectory( ) ,the control of the execution comes there and when proceeded, stack overflow is not observed..
without a breakpoint, if we try to proceed after attaching to the process, we get a stack overflow from this api at the internal function in ntdll.dll..
we tried out two options
1) By increasing this thread stack size from default 1MB to 10MB(as we saw, one system needs more than 3MB which was sufficient in many system). This increases the stack size of the thread and the Stack overflow is overcome..
Here the question is How a thread of a particular stack size undergoes a stack overflow in one h/w configuration and doesn't stack overflow in other hardware configurations...OS in all the h/w configuration is Win2K_English..
same case with winXP OS too..
2) By putting a sleep(1) ,delay of 1ms before the CreateDirectory( ) api on assumption of a timing issue..
These two options seems to work, but we are not sure on how it circumvents the stack overflow problem..
Any lights on this issue is highly appreciated.
Regards,
Shiva P
|
|
|
|
|
Is there some reason you don't synchronize access to the CreateDirectory() call?
"No matter where you go, there your are." - Buckaroo Banzai
-pete
|
|
|
|
|
Thanks for your reply..
Sure..I do use a critical section locking mechanism..
Lock();
CreateDirectory(..,..);
Unlock();
|
|
|
|
|
Dear Shiva,
I too experianced the stack correption problem in one of my projects. The reason was, if you had classes of big size, dont create then on stack, but create them on heap.
Another possible reason may be with exception handling. In our project we are throwing an exception object which is very big in size. So when the system enters into a funciton, it calulate the maximum stack that is needed. So, in exception handling mechanism, we throwed the same object many number of times in the same function, when some error cases come. In our sense as only one throw can work at a time, the system will calculate the stack size with that single exception object. But C++ calculates the stack size as ( total number of throw objects * size of single object ). thats the reason.
Hope this can help you.
Regards,
Jijo.
________________________________
Yesterday is history,
Tomorrow is a mystery,
But today is a present.
|
|
|
|
|
Do anyone how to make a simple application to link a computer to a mobile phone using visual c++. If anyone has an idea or knows the source code for it can u please help me out.
Thanks!!
|
|
|
|
|
What mobile phone model are you talking about ?
Nokia releases and upkeeps the Nokia PC Connectivity SDK, which allows you to programmatically control a phone connected to your computer via Nokia serial cable, USB cable, Bluetooth or IrDA.
I believe Ericsson and other manufacturers have similar SDKs. They all come with a proper documentation and lots of examples. Consult these for more help.
-Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
Hi
I am getting list of files in given directory using FindFirstFile() and FindNextFile() function. But it shows directory as well as files. How can I know that which one is file and which one is directory ?
Or
Is ther any specific function which gives only files or only directory ?
Plz Help me.
I am in Hurry...
Thanking you
Atmiya
|
|
|
|
|
If you read the documentation in MSDN for FindNextFile you will see that the second parameter is a pointer to a WIN32_FIND_DATA structure. That structure first member is dwFileAttributes . All you do is check if the FILE_ATTRIBUTE_DIRECTORY bit is set. If it is, you have a directory, else you have a file.
"You're obviously a superstar." - Christian Graus about me - 12 Feb '03
"Obviously ??? You're definitely a superstar!!!" mYkel - 21 Jun '04
Within you lies the power for good - Use it!
|
|
|
|
|
U can use..
if(GetFileAttributes(file_r_dir_name) == FILE_ATTRIBUTE_DIRECTORY)
{
//it's a directory
}
else
{
//it's a fil
}
|
|
|
|
|
Won't work as expected. You have to check the FILE_ATTRIBUTE_DIRECTORY bit only. Directories can be hidden, compressed, readonly etc.
if (GetFileAttributes(file_r_dir_name) & FILE_ATTRIBUTE_DIRECTORY)
"You're obviously a superstar." - Christian Graus about me - 12 Feb '03
"Obviously ??? You're definitely a superstar!!!" mYkel - 21 Jun '04
Within you lies the power for good - Use it!
|
|
|
|
|
Hi !
I create a UI Thread in my software and I am sure that it is created because I have a breakpoint in the InitInstance function which only Return TRUE; At this point, I know that the message pump of this thread is running. (Is it right ?)
I use PostThreadMessage() to send a user message to my thread. It seems that the message is never sent. I try to use SPY++ with this thread and I don't find them. I find the main thread of my software but not the UI Thread created by me (This is a derivative of CWinThread). I want to see all messages for this thread in SPY++. I use it for the first time and I understand how it work which other thread and process. It does'nt work for my thread.
Do you have any idea ?
|
|
|
|
|
Danny Gilbert wrote:
At this point, I know that the message pump of this thread is running. (Is it right ?)
No, the message loop does not begin until after InitInstance() returns. If it returns FALSE, the message loop is never entered.
Danny Gilbert wrote:
I use PostThreadMessage() to send a user message to my thread. It seems that the message is never sent.
What did PostThreadMessage() return? Show us the code you used to call PostThreadMessage() .
Ryan "Punctuality is only a virtue for those who aren't smart enough to think of good excuses for being late" John Nichol "Point Of Impact"
|
|
|
|
|
Thanks Ryan !
My InitInstance() function is the one given by Wizard. It returns TRUE and it works. (I saw it with debugger).
Here is a part of my code.
// Create Thread.
m_pUIThreadTestPlan = (ThreadTestPlan *) AfxBeginThread( RUNTIME_CLASS(ThreadTestPlan));
// Start the execution of all activities in the thread.
m_pUIThreadTestPlan->PostThreadMessage( WU_UITHREAD_TESTPLAN_START, 0, (LPARAM) thread_info);
thread_info is a structure with some information for the thread.
Here is the message map for the handler of my WU_UITHREAD_TESTPLAN_START message.
BEGIN_MESSAGE_MAP(ThreadTestPlan, CWinThread)
//{{AFX_MSG_MAP(ThreadTestPlan)
ON_THREAD_MESSAGE(WU_UITHREAD_TESTPLAN_START, OnStart)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
And for sure, I have a function named OnStart().
LRESULT ThreadTestPlan::OnStart(WPARAM, LPARAM lp)
{
// Something inside here.
With my debugger I never ENTER here. NOTHINGS HAPPEN.
}
The other point is I don't see The THREAD in SPY++.
|
|
|
|
|
Danny Gilbert wrote:
The other point is I don't see The THREAD in SPY++.
Hmmm, this seems to suggest that the thread doesn't exist. Spy++ should be able to see it if it's there... Are you sure the thread is being created correctly?
Ryan "Punctuality is only a virtue for those who aren't smart enough to think of good excuses for being late" John Nichol "Point Of Impact"
|
|
|
|
|