|
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.
|
|
|
|
|
does Win98 interpret a WM_KEYDOWN message differently than in WinNT ?
I have a method that extract a bunch of keyboard data whenever the WM_KEYDOWN is hit
It pulls off stuff like the virtual key code, the char representation, etc. On NT this works fine (and is my primary dev platform). But when I run it on 98 I get nothing! For example the VK codes that I get on NT turn to nothing on 98. Is there something special you have to do to properly handle this ?
|
|
|
|
|
From my experience this should be the same except some bizarre key combinations such as Shift + (keypad +,-).
|
|
|
|
|
I don't know if this is the appropriate forum to be asking this question, but i'll assume as VC++ programmers someone will know, because it's probably VC++ programmers who write the code for the JScript interpreter.
Do the following code optimizations apply to both compiled and interpreted code.
Common sub-expression elimination
Loop invariant hoisting
Dead store elimination which i'll assume is dropping unused functions...?
I gave this some thought and i figure if it works for compiled why shouldn't it work in scripts...? Do you think the JScript interpreter does this while reading the file into it's buffer...? dead store is obvious...less text, less size = quicker downloads. You get size opt, but wouldn't this make a difference with execution time as well...?
Merci buckets...
Tia
"An expert is someone who has made all the mistakes in thier field" - Niels Bohr
|
|
|
|
|
I don't know this for certain but I would be very surprised if any significant code optimization is done by the JS compiler. Speed of compilation is generally a higher priority than speed of execution.
|
|
|
|
|
Really...i would figure both would be about equal for scripting langs. Maybe even in favour for run time, seeing how people kinda expect to have a short delay in the download process.
I'm really curious if optimized code would work in a interpreted environment.
Take the following example:
for(i=0; i<10000; i++)
a[i] = b + c;
t = a + b;
for(i=0; i<10000; i++)
a[i] = t;
even in interpretation it one less operation to perform each iteration of the loop...?
I figure i'll try it out by executing similar loops and timing the diff. Only i don't know quite how to go about it. Would JScript allow me to clock it in the code itself or will i have to do it through the IWebBrowser2 or similar component
Minus 30 degrees C is so damn cold
"An expert is someone who has made all the mistakes in thier field" - Niels Bohr
|
|
|
|
|
If the "interpreter" is actually a JIT compiler, then it can do all those optimizations, but a true interpreter would be limited to statement-level common subexpression elimination.
|
|
|
|
|
I think I have a fairly broken class. I try to locate the Access Violation but I just can't seem to find it. I've tried examing the call stack but all i get is a bunch of kernel addresses. Can someone check it out and tell if there is anything wrong?
Here is the .h file
#ifndef _KTRANSCEIVER_H_
#define _KTRANSCEIVER_H_
#pragma warning(disable: 4786)
#include "bfThread.h"
#include "kStreamServer.h"
#include <vector>
#define EOK 0x0F1
#define EBADSOCK 0x0F2
using std::vector;
class bfSocket;
class kTransceiver:public bfThread
{
private:
struct client_t
{
bfSocket* pSock;
client_info *clinfo;
};
vector< bfSocket* > m_pClients;
bfSocket* m_pSource;
string m_streamName;
source_info *info;
//Removes a client from list of clients
int cleanClients();
int removeClient(std::vector<bfSocket*>::iterator sock_i);
int removeAll();
void End();
protected:
public:
//Constructor
kTransceiver(bfSocket* pSource, source_info *_info);
~kTransceiver();
//Add a client to list of clients
int addClient(bfSocket* pClient, client_info *clinfo);
DWORD ThreadProc();
};
#endif
Here is the .cpp file
#pragma warning(disable:4786)
#include <vector>
#include <string>
#include "../include/kTransceiver.h"
#include "../include/bfSocket.h"
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
kTransceiver::kTransceiver(bfSocket *pSource, source_info *_info)
{
if (pSource)
m_pSource = pSource;
else
m_pSource = NULL;
info = _info;
}
kTransceiver::~kTransceiver()
{
End();
}
int kTransceiver::addClient(bfSocket* pClient, client_info *clinfo)
{
string buffer;
string temp;
if (pClient && pClient->IsConnected())
{
//Client Greeting
if (clinfo->icy_metdata) //client uses icy
{
buffer = "ICY 200 OK\r\n";
buffer += "Icy-Name: ";
buffer += info->name;
buffer += "\r\n";
buffer += "Icy-Notice1:This must be a Winamp <www.winamp.com> compatible player.\r\n";
buffer += "Icy-Notice2:Katie Alpha 0.1\r\n\r\n";
}
else
{
//Send audiocast headers
buffer = "HTTP/1.0 200 OK\r\n";
buffer += "x-audiocast-name: ";
buffer += info->name;
buffer += "\r\n";
if (!info->description.empty())
{
buffer += "x-audiocast-description:";
buffer += info->description;
buffer += "\r\n";
}
if (!info->genre.empty())
{
buffer += "x-audiocast-genre: ";
buffer += info->genre;
buffer += "\r\n";
}
buffer +="\r\n\r\n";
}
pClient->Send(buffer, buffer.length());
//Add to list
BeginLock();
m_pClients.push_back(pClient);
EndLock();
}
else
{
if (pClient)
delete pClient;
return EBADSOCK;
}
return EOK;
}
int kTransceiver::removeClient(std::vector< bfSocket* >::iterator sock_i)
{
BeginLock();
delete *sock_i;
*sock_i = NULL;
m_pClients.erase(sock_i);
EndLock();
return EOK;
}
DWORD kTransceiver::ThreadProc()
{
string buffer;
std::vector<bfSocket*>::iterator i;
int read, sent, total, z;
BOOL tryagain = FALSE;
while(isRunning())
{
read = 0;
sent = 0;
//read from the source
read = m_pSource->Receive(buffer, 2046);
if (!m_pSource->IsConnected())
{
break;
}
//Send the data to the clients
BeginLock();
printf("Checking size: %d\n", m_pClients.size());
printf("Sending data...\n");
for (i = m_pClients.begin(); i != m_pClients.end(); i++)
{
if(m_pClients.size() > 0)//make sure there are clients to send the data to
{
total = 0;
tryagain = FALSE;
//try twice to write
for (z = 0; z < 2; z++)
{
while (total < read) //make sure that it all gets sent
{
sent = ((bfSocket*)*i)->Send(buffer, read);
if (sent <0)
{
printf("Unable to send data! Trying again...\n");
tryagain = TRUE;
break;
}
total += sent;
if (!((bfSocket*)*i)->IsConnected())
{
printf("Client %s disconnected.\n", ((bfSocket*)*i)->GetAddress());
tryagain=FALSE;
break;
}//if
}//while(sent < read)
if (tryagain)
{
Sleep(100);
}
else
break;
}//for
}
else
break;//if
}//for
cleanClients();
EndLock();
Sleep(100);
}//while(isRunning())
//destroy our source
delete m_pSource;
delete info;
removeAll();
return 0;
}
void kTransceiver::End()
{
bfThread::End();
}
int kTransceiver::removeAll()
{
std::vector<bfSocket*>::iterator i;
if (m_pClients.size() == 0)
return EOK;
for(i = m_pClients.begin(); i != m_pClients.end(); i++)
{
//disconnect the client
((bfSocket*)*i)->Disconnect();
//remove the socket
delete ((bfSocket*)*i);
}
return EOK;
}
int kTransceiver::cleanClients()
{
std::vector<bfSocket*>::iterator i;
BOOL bKeepChecking = FALSE;
printf("Cleaning Clients...\n");
if (m_pClients.size() == 0)
return EOK;
for (i = m_pClients.begin(); i != m_pClients.end(); i++)
{
//check if the client is disconnected
if (*i)
{
if (!((bfSocket*)*i)->IsConnected())
{
//client isn't connected so remove him
printf("Removing Client.\n");
removeClient(i);
bKeepChecking = TRUE;
break;
}
}
}
if (bKeepChecking)
cleanClients();
return EOK;
}
<b>S</b>tephen <b>C</b>aldwell
Blackfission, CEO
http://blackfission.myip.org:81
|
|
|
|
|
Hey Stephen,
It's hard to tell what's happening just by looking at your code. We don't know what any of the data member types are, and of course we can't compile it. Are you getting the crash in Debug mode? You should also try setting the Access Violation Exception to Stop Always, which should tell you exactly where the crash is happening (this can be done by running the app, then in VC going Debug | Exceptions | and then setting the Access Violation to Stop Always).
Hope this helps!
cheers,
swinefeaster
Check out Aephid Photokeeper, the powerful digital
photo album solution at www.aephid.com.
|
|
|
|
|
When I try to edit the HOSTS file to get a name on my server so my client apps can connect to the server app by typing xblade.focus.com instead of the damn IP number (xxx.xxx.xxx.xxx). But it seems to not work for me! :/
I've tried typing:
127.0.0.1 xblade.focus.com
and
#xxx.xxx.xxx.xxx is my IP to the computer (server, but a client in my LAN)
xxx.xxx.xxx.xxx xblade.focus.com
I've restarted the system after changing it, but nothing happens. My network can be unstable or not work correctly, so can that be the errror?
The error code is 10061 (No connection could be made because the target machine actively refused it. This usually results from trying to connect to a service that is inactive on the foreign host—that is, one with no server application running.)
HELP!!
------------------------------
©0d3 ©®4©k3® - That's me!
------------------------------
|
|
|
|
|
I have talked with a lot of programmers about this (including one professor) and all know it's possible, but no one knows exactly how I can do this. I hope you do.
ifstream MyFile(FileName);
while (!MyFile.eof()) {
MyFile >> MyString;
cout << MyString << endl; }
This works great, but one problem is that the default >> operator seperates these words at spaces so I get from "What!! is, this;thing man?" :
What!!
is,
this;thing
man?
(4 words)
I want to separate at all punct char's (\":;?!, etc) so I get:
What
is
this
thing
man
(5 words)
Does anyone have an idea -- a lot of people in my lab are interested. We think that we can overload the << operator to do this, but need some guidance.
Thanks,
Tim
(oh how easy this is to do in Perl . . . )
---------------------------------------
Tim Booher
|
|
|
|
|
Read in a line at a time (getline, I think) and then break up the string using strtok(). Keep a running count of how many tokens you get for each line. You can use multiple string delimiters with strtok(). Look it up in the MSDN documentation.
Jon Sagara
What about ?
|
|
|
|
|
jon,
thanks for the info . . . but that is what I am doing -- I have heard I can change the << operator to split on a user defined value -- not just whitespace. that would simplify my code by a great deal.
thanks for the help . . .
tim
---------------------------------------
Tim Booher
|
|
|
|
|
Actually you will have to overload the >> operator if you want to get token by token. Use “get” to read the next character from the input stream and return when you get a whitespace ( in your case “;” , “.” Or whatever … ). Something like this ( is just a pseudocode )
istream& operator>> ( istream& is, char* szToken )
{
do
{
char c;
is >> c;
if( is_separator(c))
break;
add_to( szToken, c);
}
while( true);
return is;
}
|
|
|
|
|
I know the following is not vc++ terms, but i am not sure what the equivalent.
How can i "pack" and "zap" a recordset?
I would like to do this on either the open or close of the recordset.
this is my current open statement
CRecordset::Open(nOpenType, lpszSql,CRecordset::FlushResultSet|CRecordset::skipDeletedRecords | CRecordset::useBookmarks);
i though the flushresultset() would do this form me.
thank you.
|
|
|
|
|
First off, I'm very new to IDL, so please be kind
I'm trying to create an interface in an idl file with the following methods:
[id(1)] HRESULT Add([in] BSTR bstrFraction1, [in] BSTR bstrFraction2, [out, retval] BSTR* pbstrSum);
[id(2)] HRESULT Add([in] BSTR bstrFraction, [in] double dReal, [out, retval] double* pdSum);
[id(3)] HRESULT Add([in] BSTR bstrFraction, [in] long lWholeNum, [out, retval] long* plSum);
I assume this would work since the functions all have different signatures, but the MIDL compiler complains that I'm redefining Add(...). So, does IDL not support method overloading?
|
|
|
|
|
I learnt VC++ using MFC approach. Now I can create application programs very quickly, but the problem is that I can't "experiment" with window. I mean that I can only use the window that is provided by MFC framework. I don't know how to subclass a window. For example the tabs of property sheet normally appears on the top. What i have to do if i want these tabs to appear at the bottom. And infact many questions like these always tickles in my mind. Please suggest me the correct way of learning VC++ so that I can create my own style window from the scratch rather than using framework provided window. I shall be grateful if you suggest me good books that suits my needs as i discussed above.
Saad
|
|
|
|
|
Check out the following
Subclass tutorial
A quick tutorial(Chris Maunder) on control subclassing...i think it uses a CButton as example
Have a day
"An expert is someone who has made all the mistakes in thier field" - Niels Bohr
|
|
|
|
|
Hi all !
i have a little problem with the function Format("..") in CString MFC class. When i compile in UNICODE and debug my application, this little code doesn't work :
DWORD dw = 0x123456;
CString str;
str.Format(_T("%x"), dw);
At this moment, the variable str contains the first character of dw. Here, str equals to "1".
Can anybody help me ?
Thanks in advance.
|
|
|
|