|
Just not possible in this case. There's no way to 'manage' this as it is used by thousands of function calls in a very large legacy application (over a million lines of code).
|
|
|
|
|
Hi,
Look at your concepts again. You're trying to do something that is 'Funamentally Disallowed'. My advise is: re-appraise the basic concept of your program. You probably need to stick your current global data in a small database.
Bram van Kampen
|
|
|
|
|
Sorry that's just not really helpful. I'm already aware that the design is not ideal, unfortunately I'm dealing with a very large legacy application in which if the variable in question were dynamic (a handle to an ISAM db) I would have to pass the handle to thousands of function calls. It's just not feasible and that's why I'm looking for another solution.
|
|
|
|
|
How is it the problem arises now?
How could the legacy system run fine for that long a time?
What has changed?
|
|
|
|
|
The problem has never arisen before because before now every loaded instance of the application has only ever had to log in once to a single database.
Now we need to be able to log in and have open multiple handles to a database.
|
|
|
|
|
sludgenz wrote: Sorry that's just not really helpful.
Nevertheless true.
Steve
|
|
|
|
|
The first solution to your problem is obvious although I can understand perhaps not very palatable: update the DLL so it doesn’t use globals. The second solution which springs to mind is to get a different process to host the DLL for you and your main EXE would communicate to different instances of the DLLs via the host processes.
Steve
|
|
|
|
|
Yep, I had considered that solution and it is probably the way I am going to go (although separate AppDomains within the same process is looking like a promising line of inquiry too).
Updating the DLL so that it doesn't use the global handle to a dataset is completely impractical, it's over a million lines of code, with 10s of thousands of function calls which would have to pass in the handle to a dataset, unless I wrap the entire application in a separate object somehow which also seems very impractical. I completely understand that loading the DLL into multiples instances in memory is an undesirable solution but it is the most desirable among the solutions that appear to be available (I'm talking with confidence here as an experienced programmer whose had other experienced programmers review the problem to make sure I'm not missing something)
The original design was a poor choice, agreed, but that was over 15 years ago and I certainly didn't make it.
Thanks for the help, based on the feedback I'm now pretty sure it's not possible.
|
|
|
|
|
sludgenz wrote: although separate AppDomains within the same process is looking like a promising line of inquiry too
Native code has no concept of AppDomains.
sludgenz wrote: I completely understand that loading the DLL into multiples instances in memory is an undesirable solution but it is the most desirable among the solutions that appear to be available
While technically it may be possible, it would be a daunting task to load multiple versions of a same DLL into different locations in the same process. Doing so would require re-implementing your own PE loader.
If I was going to use the “host the DLLs in a separate process” approach I’d use COM. When your local server calls CoRegisterClassObject[^] it would use the REGCLS_SINGLEUSE value of the REGCLS[^] enum to ensure each instance is in a separate process. Obviously you'd have to wrap the features you use from the DLL in COM interfaces.
Steve
|
|
|
|
|
Stephen Hewitt wrote: Native code has no concept of AppDomains.
Yes I know, but the process that actually loads the native .DLL is actually a .NET Windows Service (using interop to calll out to the native code).
Stephen Hewitt wrote: If I was going to use the “host the DLLs in a separate process” approach I’d use COM. When your local server calls CoRegisterClassObject[^] it would use the REGCLS_SINGLEUSE value of the REGCLS[^] enum to ensure each instance is in a separate process. Obviously you'd have to wrap the features you use from the DLL in COM interfaces.
I hadn't thought about using COM, thanks.
|
|
|
|
|
sludgenz wrote: Yes I know, but the process that actually loads the native .DLL is actually a .NET Windows Service (using interop to calll out to the native code).
The barriers between AppDomains are enforced when the MSIL is JITed and require the code to be verifiable. It will not help that the client is managed.
Steve
|
|
|
|
|
You can't without renaming the DLL. This is by design.
However, you could copy the DLL to new file with a different name and load that.
Anyone who thinks he has a better idea of what's good for people than people do is a swine.
- P.J. O'Rourke
|
|
|
|
|
Nasty, but little doubt the easiest way. Let's keep our eyes on the "Coding Horror" message board...
Steve
|
|
|
|
|
Yeah, it makes me want to throw up. But, he asked...
Anyone who thinks he has a better idea of what's good for people than people do is a swine.
- P.J. O'Rourke
|
|
|
|
|
i use a *.mkv file to learn matroska file format(anyone can get the information at www.matroska.org). but i encounter a question i don't know how to understand it. it's about block(Cluster->BlockGroup->Block):EBML Lacing. there is a block header provided:
A1 E5 82 00 00 06 07 9A AE BF BF BF BF BF DE04.....
according to the document, 0xA1 tells that the following data is a block,0xE5 tells the total length of this block is 0x65(=101d), 0x82 tells that the track entry is a audio track, following 0x0000 is its timecode, 0x06 indicates the block use EBML Lacing, 0x07 tells us there are 8 laces chunk following. So,the following 7 bytes should store the first 7 laces' sizes, right? if so, size[0]=0x1A, size[1]=0x1A+?, and how to calculate the others' size?
Maybe i loss some key information about it because of my bad english, so i hope someone would like to help me to have a look. Thanks.
|
|
|
|
|
i hope someone can explain that,because i encounter the same question about lacing construction,thanks very much!
|
|
|
|
|
I am glad to meet a friend with the same question. But, tell the truth, i have got the solution.
In my example:A1 E5 82 00 00 06 07 9A AE BF BF BF BF BF...
0xA1:header tag
0xE5: tell the total length of the block is 0x65=101
0x82: tell the block is a slice of track 2(known as trackentry in the document)
0x0000: timecode, two byte
0x06: tell the lacing type of the block used is EBML Lacing
0x07: the lacing slice in the block is 0x08=8, so the there will be 7 lacing-sizes given
0x9A: says the first size is stored in only one byte, size[0]=ebml_unsigned(0x9A)=0x1A=26
0xAE: the delta of the second size according to the first one, tells the first delta(size[1]-size[0] is stored in only one byte. delta=0xAE-0x80-3F=-0x11=-17, so, size[1]=size[0]+delta=26+(-17)=9
0xBF: delta=0xBF-0x80-0x3F=0, so size[2]=size[1]+delta=9+0=9 ==>size[2]=9
....so, we can calculate the rest: size[3]=9,size[4]=9,size[5]=9,size[6]=9
and size[7]=101(total size)-12(before the real data witch began after the last BF)-[26+9*6]=9
and in my example, the block precisely end with my calculated ends!
Note: Why we should minus 0x80 and 0x3F: you know, in ebml integer, the first '1'bit indicates how many bytes of the data used, so its no contribution to the final value.so if the integer is 1 byte, we minus 0x80, if 2 bytes, we minux 0x4000,...; after the first '1' bit is the sign bit, if the real value is negative, we should add the max value to code it. For 1 byte integer,its 1*xxxxxxb,*is the sign bit, so the max 1 byte integer is 2^6-1=0x3F(according to block_structure,so for a 2 bytes integer value val: real_val = val-0x4000-0x1FFF.
For more details, you can go www.matroska.org to looking for.
good luck
|
|
|
|
|
thanks for your patiently answers,I will carefully to see,looks like you have been very familiar with MKV,but,i still was a novice,so,if you don't mind,could i keep contact with you?MSN or QQ?Sorry to occupy your time.
best wishes
|
|
|
|
|
Take care, I am a newbie too. if you like, we can exchange more details via msn, my account is kcynice@hotmail.com
see you.
|
|
|
|
|
My progress dialog creates a worker thread using AfxBeginThread.
When the user clicks cancel, I don't want the window to close if the thread is still running. I want to have the thread safely finish first.
There is a BOOL variable that the worker thread checks on occasion while running. If this is true, it begins to cancel. The worker thread only reads this variable, the Progress Dialog writes to it if needed. Should the worker thread be suspended before this variable is written? Or will it be OK since they will never Write at the same time.
Secondly, and most importantly, I currently have the Worker Thread Post a WM_USER message, with certain WPARAM and LPARAM for the reason, when it has ended. Is there any other way to check if the thread is running or not, and what the controlling function's return value was?
Thanks
|
|
|
|
|
There are two methods. I've included code with both. I used a bool to signal the other thread, but vastly prefer using events since threads often have waits within them. Also note that I can't remember the last time I checked a thread exit code, but you may have a reason. Finally, if you don't call MFC within the thread (with a few exceptions), you could just use _beginthreadex(). I just did this last week.
1) Call AfxBeingThread() with the CREATE_SUSPENDED flag.
2) set CWinThread::m_bAutoDelete to false
3) Call CWinThread::Resume()
4) At exit, after setting the bool (or setting an event, which is my preferred method), call WaitOnSingleObject() with CWinThread::m_hThread
5) Call GetThreadExitCode() to get exit code
6) Delete the CWinThread object
I've run into problems with MFC complaining about item 6.
CWinThread* StartAfxThread(AFX_THREADPROC pThreadProc, LPVOID pParam = NULL, int priority = THREAD_PRIORITY_NORMAL)
{
CWinThread* pThread = ::AfxBeginThread(pThreadProc, pParam, priority, 0, CREATE_SUSPENDED);
pThread->m_bAutoDelete = false;
pThread->ResumeThread();
return pThread;
}
CWinThread* pThread = StartAfxThread(TheThread);
isRunning = false;
if (::WaitForSingleObject(pThread->m_hThread, 1000) == WAIT_TIMEOUT)
{
::TerminateThread(pThread->m_hThread, (DWORD) -1);
Sleep(10);
}
DWORD exitCode = 0;
::GetExitCodeThread(pThread->m_hThread, &exitCode);
_tprintf(_T("Exit code: %u"), exitCode);
delete pThread;
1) Call AfxBeingThread() with the CREATE_SUSPENDED flag.
2) Duplicate CWindThread::m_hThread
3) Call CWinThread::Resume()
4) At exit, after setting the bool, call WaitOnSingleObject() with the duplicate handle.
5) Call GetThreadExitCode() to get exit code
6) Close the duplicate handle
HANDLE StartAfxThread(AFX_THREADPROC pThreadProc, LPVOID pParam = NULL, int priority = THREAD_PRIORITY_NORMAL)
{
CWinThread* pThread = ::AfxBeginThread(pThreadProc, pParam, priority, 0, CREATE_SUSPENDED);
HANDLE hProcess = GetCurrentProcess();
HANDLE hDup;
if (!::DuplicateHandle(hProcess, pThread->m_hThread, hProcess, &hDup, 0, FALSE, DUPLICATE_SAME_ACCESS))
hDup = NULL;
pThread->ResumeThread();
return hDup;
}
HANDLE hThread = StartAfxThread(TheThread);
isRunning = false;
if (::WaitForSingleObject(hThread, 1000) == WAIT_TIMEOUT)
{
::TerminateThread(hThread, (DWORD) -1);
Sleep(10);
}
DWORD exitCode = 0;
::GetExitCodeThread(hThread, &exitCode);
_tprintf(_T("Exit code: %u"), exitCode);
CloseHandle(hThread);
Anyone who thinks he has a better idea of what's good for people than people do is a swine.
- P.J. O'Rourke
|
|
|
|
|
When the user clicks cancel, I don't want the window to close if the thread is still running. I want to have the thread safely finish first.
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
DWORD exitcode;
GetExitCodeThread(hTread->m_hThread, &exitcode);
if (exitcode != STILL_ACTIVE )
OnCancel();
-@SuDhIrKuMaR@-
|
|
|
|
|
By default a CWinThread object with auto delete itself upon thread exit. Not only will the thread handle within be invalid, the pointer itself will be invalid.
Anyone who thinks he has a better idea of what's good for people than people do is a swine.
- P.J. O'Rourke
|
|
|
|
|
hi all,
anyone have a idea the meaning of the bold lines.
using child pointer to a the parent class.
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
//virtual int area (void) =0;
virtual int area (void)
{return 0;}
void printarea (void)
{ cout << this->area() << endl; }
};
class CTriangle: public CPolygon {
public:
int area (void)
{ return (width * height / 2); }
int test;
};
int main () {
CRectangle rect;
CTriangle trgl;
CPolygon * ppoly1 = ▭
CPolygon * ppoly2 = &trgl;
CTriangle * ptrgl = (CTriangle *) ▭
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
ptrgl->set_values (4,5);
ppoly1->printarea();
ppoly2->printarea();
ptrgl->printarea();
ptrgl->test = 1;
cout << ppoly1->area() << endl;
cout << ppoly2->area() << endl;
cout << ptrgl->area() << endl;
system("PAUSE");
return EXIT_SUCCESS;
}
|
|
|
|
|
The definition of CRectangle isn't present so I can't tell if the cast makes sense. I have to say it look like nonsense to me however. Also, as a general rule avoid C-style casts.
Steve
|
|
|
|
|