|
Two questions: Where is the event.hEvent signaled? Are you waiting for the event to become signaled or waiting for it to time out?
If I understand your question you need to test for WAIT_TIMEOUT not WAIT_OBJECT_0
|
|
|
|
|
i'm using mfc, with cview as the base class. i can't find any books that shows how to add grid lines. i was wondering if you guys knew how?
|
|
|
|
|
I don't think there is a DrawGrid member function in the default CView class.
You'll have to write your own.
BOOL CTestView::DrawGrid(CDC* pDC, UINT nWidth, UINT nHeight, COLORREF clrGrid)
{
CRect rcArea;
GetClientRect(&rcArea);
HPEN hPen = CreatePen(PS_SOLID, 1, clrGrid);
SelectObject(pDC->m_hDC, hPen);
int x, y = 0;
for(y=0; y<=rcArea.bottom; y+=nHeight)
{
pDC->MoveTo(x, y);
pDC->LineTo(0, y);
for(x=0; x<=rcArea.right; x+=nWidth)
{
pDC->MoveTo(x, y);
pDC->LineTo(x, 0);
}
}
return TRUE;
}
Your gonna probably wanna tweak this. For example
becuz i don't use the CPen class(I dunno why, i just never do) I'm pretty sure your going to want to restore the original object in your selectObject, cuz it leaks and each time you call DrawGrid which is lots cuz it's called in OnDraw you'll leak and your GDI will go for sh*ts eventually.
Anyways hope this helps
Laterz
"An expert is someone who has made all the mistakes in thier field" - Niels Bohr
|
|
|
|
|
|
Hi guys,
I need some expert advice here, if anyone knows more about this stuff .
First, let's name two classes for clarity. cService and cUser.
The cService class uses a handle mechanism to give the cUser class a way to indicate which agreggate objects (within cService) are being referred to whenever it makes various function calls. That handle, as far as the cUser is concerned, is just a number which means nothing to the cUser. But internally to cService, this handle is really a pointer to a link element in a linked list.
The problem that arises is that sometimes the cUser may have an invalid handle because of multithreaded (de)synchronization, which it will pass to the cService. The cService class needs to check whether this handle is valid, so what I have devised is to cast the handle to some base class pointer, namely cDestructible*, and then try to do cast it to the templated link list element class pointer, say cListLink<cServiceAggregate>*.
This is done through a safe_dynamic_cast<>, which is basically a dynamic_cast<> wrapped in try catch handlers, as so:
<code>
// safe_dynamic_cast<> never throws an exception; it traps all exceptions, and
// returns a NULL pointer instead (and so the cast must be between two
// pointers).
template <class tDestType, class tSourceType>
tDestType
safe_dynamic_cast(tSourceType SourceObject)
{
tDestType Dest = NULL;
try
{
Dest = dynamic_cast<tDestType>(SourceObject);
}
catch(...)
{
// Failed; return NULL.
}
return Dest;
}
</code>
Now this mechanism seems to work fine. To further clarify (if anyone has been able to follow so far), we have cListLink, which is derived from cDestructible. cService has a list of cServiceAggregate objects which are referred to by the cUser via handles. When the cUser object calls a function of the cService class, the cService class validates the handle, trying to convert the handle to a pointer, as follows:
<code>
cListLink<cServiceAggregate>* Aggregate =
safe_dynamic_cast<cListLink<cServiceAggregate>*>
((cDestructible*)handle);
if(Aggregate)
{
// Do stuff with Aggregate here, as it is valid.
}
</code>
Now this system seems to work fine in debug mode, and has been working quite well for a while actually. But in release mode something falls apart. I get an access violation while in the dynamic_cast<> call, which is fine, but then my catch handler doesn't catch it---instead, everything just goes poop. The whole app crashes. Perhaps what I'm doing here is a no-no, but I don't know any other way I can do this.
C++ support RTTI, which I find is useless, because there is no way of determining if a given pointer is of a given type (only if it's MOST DERIVED type is that type). I can't just use a base class and a virtual function cause this doesn't help as we don't know if the handles are valid.
Anyone have any thoughts to this?
Cheers!
swinefeaster
Check out Aephid Photokeeper, the powerful digital
photo album solution at www.aephid.com.
|
|
|
|
|
First of all, dynamic cast does not throw an exception, it just returns NULL. As far as I can see, there is no point in the safe dynamic cast class above.
I'm lost as to the rest of this - a handle is just a pointer to an object ? The point of RTTI is to be able to have an objerct of a base class and know which derived type it is pointing to. I didn't know if there were multiple levels of derivation it would fail if, for example, I asked if a CCheckListBox pointer was a CListBox pointer. That sounds wrong to me, I'll have to write some code to check.
Christian
I have come to clean zee pooollll. - Michael Martin Dec 30, 2001
Picture the daffodil. And while you do that, I'll be over here going through your stuff.
Picture a world without war, without hate. And I can picture us attacking that world, because they would never expect it.
Sonork ID 100.10002:MeanManOzI live in Bob's HungOut now
|
|
|
|
|
I've done a lot of mucking around with this. Yes, the documentation SAYS that it should return NULL. However, dynamic_cast sometimes crashes when given an invalid pointer, and sometimes throws a bad_cast exception. Go figure!
And RTTI doesn't work with multiple levels of derivation. I've tried.
swinefeaster
Check out Aephid Photokeeper, the powerful digital
photo album solution at www.aephid.com.
|
|
|
|
|
swinefeaster wrote:
I've done a lot of mucking around with this. Yes, the documentation SAYS that it should return NULL. However, dynamic_cast sometimes crashes when given an invalid pointer, and sometimes throws a bad_cast exception. Go figure!
I'd love to see the code. I don't doubt you, but this has *never* happened to me and I use dynamic_cast constantly. MAybe we can find the reason you're getting such errors.
swinefeaster wrote:
And RTTI doesn't work with multiple levels of derivation. I've tried.
I haven't, but I'll have a play tonight ( not that I doubt you, I just like to prove stuff ). That is a little disappointing...
Christian
I have come to clean zee pooollll. - Michael Martin Dec 30, 2001
Picture the daffodil. And while you do that, I'll be over here going through your stuff.
Picture a world without war, without hate. And I can picture us attacking that world, because they would never expect it.
Sonork ID 100.10002:MeanManOzI live in Bob's HungOut now
|
|
|
|
|
Here's a sample project that I made in a couple of minutes to illustrate how dynamic_cast<> does NOT work as advertised. Pretty disappointing....
BadDynamicCast.zip
swinefeaster
Check out Aephid Photokeeper, the powerful digital
photo album solution at www.aephid.com.
|
|
|
|
|
It seems to me that you are accessing a pointer in an invalid range in the sample code that you submitted:
<br />
void CBadDynamicCastDlg::OnCrash() <br />
{<br />
CDialog* Crash = (CDialog*)2342;<br />
CAboutDlg* String = dynamic_cast< CAboutDlg* >(Crash);<br />
}<br />
Your pointer at 2342 or 0x926 is well below the 0x40000 range of protected memory. Try giving it a pointer that is above the 4 Meg boundary or NULL.
|
|
|
|
|
That's exactly the point! The documentation of dynamic_cast<> says at the bottom "The value of a failed cast to pointer type is the null pointer. A failed cast to reference type throws a bad_cast exception."
So, if the pointer is bad, it should ALWAYS return NULL. But no, we get a bad_cast exception sometimes, and even sometimes just making this call seems to screw up something pretty bad in the whole app and the whole thing crashes! Yikes.
swinefeaster
Check out Aephid Photokeeper, the powerful digital
photo album solution at www.aephid.com.
|
|
|
|
|
What is inside the angle brackets of dynamic_cast? The html post stripped out this part - to stop this happening, click the "Display this message as-is (no HTML)" checkbox.
e.g. dynamic_cast<...>(val);
--
Andrew.
|
|
|
|
|
Done .
But I've since fixed the bug...
Swine
Check out Aephid Photokeeper, the powerful digital
photo album solution at www.aephid.com.
|
|
|
|
|
Ok, I'm not sure you've sorted this out, but here's my 2 cents.
The dynamic_cast actually has to examine the data at the other end of the pointer you feed it. It needs to look for the vtables of the type to which you want to cast the pointer. I'm guessing that the code inserted for the dynamic_cast doesn't do the dereference intelligently. So if you feed it a pointer that would normally dump core when you dereference it, it's still gonna yak.
The documentation should probably mention this, although perhaps the authors just assumed you'd be feeding it actual object pointers.
J
|
|
|
|
|
Yes, I would expect it to 'yak', but in a way that the catch(...) handler would just be invoked with an exception and everything should continue as normal, no? But it seems that a bad dynamic_cast<> also modifies memory somewhere, and really messes things up.
swinefeaster
Check out Aephid Photokeeper, the powerful digital
photo album solution at www.aephid.com.
|
|
|
|
|
Another possible solution to your problem:
Use a map to track all valid handles in cService. When a handle is freed, remove the entry from the map. When a call is made which uses a handle, see if it exists in the map. If it does not, it is an invalid handle.
A numeric map should be pretty fast (just set the size of the hash table).
Just my 2 cents.
Matt Gullett
|
|
|
|
|
Actually that's exactly what I came up with after some more thought . But then I ran into a global / static object problem with this scheme. Check out my more Recent Post... I implemented the code as follows:
<br />
#pragma once<br />
<br />
#include "cMap.h"<br />
#include "cCriticalSection.h"<br />
<br />
<br />
class cParanoid : public cDestructible<br />
{<br />
public:<br />
cParanoid(void);<br />
virtual ~cParanoid(void);<br />
<br />
static cParanoid* GetParanoid(void* Pointer);<br />
<br />
private:<br />
static cMap<cParanoid*, cParanoid*, bool, bool> m_ParanoidMap;<br />
<br />
static cCriticalSection m_ParanoidSection;<br />
};<br />
<br />
cMap<cParanoid*, cParanoid*, bool, bool> cParanoid::m_ParanoidMap;<br />
<br />
cCriticalSection cParanoid::m_ParanoidSection;<br />
<br />
cParanoid::cParanoid(void)<br />
{<br />
m_ParanoidSection.Lock();<br />
{<br />
m_ParanoidMap[this] = true;<br />
}<br />
m_ParanoidSection.Unlock();<br />
}<br />
<br />
cParanoid::~cParanoid(void)<br />
{<br />
m_ParanoidSection.Lock();<br />
{<br />
if(!m_ParanoidMap.RemoveKey(this))<br />
{<br />
}<br />
}<br />
m_ParanoidSection.Unlock();<br />
}<br />
<br />
cParanoid* <br />
cParanoid::GetParanoid(void* Pointer)<br />
{<br />
cParanoid* Paranoid = NULL;<br />
<br />
m_ParanoidSection.Lock();<br />
{<br />
if(m_ParanoidMap.DoesKeyExist((cParanoid*)Pointer))<br />
{<br />
Pointer = (cParanoid*)Pointer;<br />
}<br />
}<br />
m_ParanoidSection.Unlock();<br />
<br />
return Paranoid;<br />
}<br />
The problem is that I get a pure virtual function called upon shutdown of the app. This is because CWinApp is a global, and the critical section and map of cParanoid get destoyed before CWinApp does, and there are some objects owned by CWinApp that are derived from cParanoid.
Any thoughts?
Thanks!
swinefeaster
Check out Aephid Photokeeper, the powerful digital
photo album solution at www.aephid.com.
|
|
|
|
|
First thought,
if the objects owned by CWinApp are allocated on the heap (ie. new), then I would add a method to my CWinApp derived class something like "NotifyObjDelete(cParanoid* pValue)". In my CWinApp class, I would see if I own that object and set it to NULL.
I would call the NotifyObjectDelete from my objects destructor.
This is not a pretty solution, but might work depending on where you are in your development process.
I'll keep thinking.
Matt Gullett
(Sorry for the Anonymous, I am not at my PC right now.)
|
|
|
|
|
Thanks for the input... but unfortunately this won't do.
First off, the objects can't know anything about the CWinApp object, as they can be destroyed via a thread other than the main gui thread (and you're not supposed to access CWnd objects from other threads, and I believe this goes for CWinApp objects as well).
Second, the real nuts of the problem is that by the time the CWinApp destructor is invoked, the cParanoid static members have already been destroyed. This includes the critical section and the map of valid cParanoid pointers.
There's gotta be a way to specify which global objects get deleted in which order. I just don't know it...
swinefeaster
Check out Aephid Photokeeper, the powerful digital
photo album solution at www.aephid.com.
|
|
|
|
|
Try adding code to your applications ExitInstance method to free the reference to these objects in your derived CWinApp object.
Tim Smith
Descartes Systems Sciences, Inc.
|
|
|
|
|
Now I wouldn't do this, but you might look into the #pragma init_seg pragma. This controls the order that objects are initialized. It would seem that it would also defined the order the are destroyed (reversed hopefully.)
Tim Smith
Descartes Systems Sciences, Inc.
|
|
|
|
|
This works great excluding one VERY minor point. There is a chance that a later created object could have the same address as one just freed. Thus a cUser object could be using an old pointer which just happens to match a new one. (I have no idea how rare this might be.)
We got around this problem by using an unique index system. Here is the basic layout.
1. Assume you have a table going from 1 to 4096 (4096 is just for example and the table size can grow if needed.) Each element of this table consists of the handle match value and a pointer to the real objects.
2. The handle is generated by taking the index in the table and oring it with a counter specific to that index. For example, let us say the handle was a DWORD. The low word is the index into the table. The high word is the unique counter for that index. Every time the index is allocated for an object, the unique counter is incremented. Thus, the first time index 20 is allocated, the handle would be 0x00010014. The next time it is allocated it would be 0x00020014. When a handle is allocated, the generated handle should be stored in the handle match value for that index.
3. When a handle is freed, it is placed at the end of a deleted list. Thus, all indexes are used prior to an index getting reused. This helps to make sure that a long period of time goes by before a handle is reused.
4. The table need not be a fixed size. If you start with 4096 entries and use all but 256 up, you can double the size of the table. There are two reasons to do this. First, you don't run out of indexes. Second, it helps to make sure handles don't get reused to quickly. If you had 4095 handles allocated and then allocated and freed the last one 65536 times quickly, it would reuse a handle quickly.
5. To look up an object from the handle. Take the handle and AND off the unquie counter. Locate the index in the object table. Compare the full handle against the handle match value for that index. If they do not match, then someone is using an old handle. If they do match, return the pointer.
6. This index system is actually faster than maps.
7. HOWEVER, 9 times out of 10 a map is a better solution because there is little worry about reusing the same object address as a handle.
(Hmm, maybe I should submit my handle to object class to CP.)
Tim Smith
Descartes Systems Sciences, Inc.
|
|
|
|
|
Very well thought out idea, Tim. Maybe you should indeed post the article. However, the handle reuse problem does not apply in my app, as I already thought of this before and avoided it in other ways... Hmmm, I'll look into that pragma you mentioned.
Cheers,
swinefeaster
Check out Aephid Photokeeper, the powerful digital
photo album solution at www.aephid.com.
|
|
|
|
|
Yeah, the #pragma init_seg(lib) directive works just great! I know it's a bit of a hack, but it'll do quite well for now. All those nasty crashes are gone! I can't believe that I was having so much trouble just because of a stupid dynamic_cast<>!
cheers,
swinefeaster
Check out Aephid Photokeeper, the powerful digital
photo album solution at www.aephid.com.
|
|
|
|
|
Hmmm looks like I am gonna have to implement this for one of my classes! I think I am having the handle reuse problem, though in a different module...
I will try to follow your suggestions, and see how it goes.
Thanks!
swine
[b]yte your digital photos with [ae]phid [p]hotokeeper - www.aephid.com.
|
|
|
|
|