|
> Is there a way to register a thread "cleanup" function
> that gets called each time a thread exits?
Hm..the first solution that comes to my mind: Call GetExitCodeThread periodically.
DWORD dwExitCode;
GetExitCodeThread( hThread, &dwExitCode);
if( dwExitCode == STILL_ACTIVE )
else
Anyway, why don't you simply call the cleanup routine at the end of ThreadFunc (just before calling return )?
DWORD WINAPI ThreadFunc( LPVOID lpParameter )
{
MyCleanUpRoutine();
return 0;
} Regards,
RK
|
|
|
|
|
Robert,
I guess I'm not a big fan of polling. As for your second suggestion: I'm trying to write a library that other developers will use. My library won't be spawning threads -- the application written by someone else will. So to pursue your suggestion, I'd have to include in my library notes, "oh, and be sure to call MyCleanUpRoutine() before your thread exits. Don't really care for that either. I guess I'm going to have to figure out how to get a DLL to work for me instead.
Actually, I think a DLL will work for me, but my initial attempts to create a DLL have not gone so well -- having problems getting global data from the DLL to link.
Thanks much for your response.
Matt Busche
|
|
|
|
|
A *.dll would perfectly suit your needs. What you have to do is:
1.Create a *.dll and export all the functions you want your users to call
2.Make sure that the global data (if any) that simultanious threads can access (i.e. if two or more users at a time call the same function) is protected with syncronization objects like Critical sections
3.If your user calls LoadLibrary, your DllMain gets called with DLL_PROCESS_ATTACH, do some initialization, maybe keep reference count of attached clients, when your user calls FreeLibrary your DllMain gets called with reason DLL_PROCESS_DETACH. This is the place to call your CleanUpFunction()
Summary: your user has only to call LoadLibrary on your *.dll, GetProcAddress on the function, and FreeLibrary to get detached from your lib.
Peter Molnar
|
|
|
|
|
Peter,
Thanks for your reply. I actually started to do this and only just now discovered that this only works for RUN-TIME dynamic-linking of a DLL. (I.e., where you use the LoadLibrary call just like you said.) I saw some sample code on how to use LoadLibrary and GetProcAddress to call a single simple function from a DLL, but I'm not exporting a single simple function, I'm exporting a handfull of C++ concrete and abstract classes (along with all their numerous member methods and overloaded operators). It is not clear to me how you'd use run-time linking for such a library. Supppose Peter, you inherited from one of my abstract base-classes, then when you wrote your constructor, how would you call my base class constructor that is exported from my DLL?
And even if it's possible, my whole objective is to make my software as easy as possible to use. I certainly wouldn't want my users to have to jump through any flaming hoops to call a base class constructor or call the "=" operator for a class.
Here's a thought. What if I had two libraries? Library ALPHA has all my user visible software and could be built arbitrarily for either dynamic or static linkage. If built as a DLL it would be expected to be used with load-time dynamic-linkage. DLL BETA has nothing in it but a DllMain. Now, here's the trick: suppose DLL ALPHA secretly does a LoadLibrary call on BETA via some singleton constructor found in ALPHA. This singleton is instantiated the first time a user of ALHPA references resources that require thread initialization and cleanup activities. Then, I would presume that every subsequent thread spawn and delete would cause this DllMain in BETA to be invoked, would it not? I presume also that DllMain in BETA could invoke methods defined in ALPHA (to effect thread initialization and cleanup.)
I'm going to investigate this idea further and maybe try it out.
Let me know if I misunderstood the implications of your email. I've been battling this silly problem for a week now. If I don't come up with a better solution soon, I'll have to simply publish a threadCleanup method that must be called by users of my library on thread exit, but I really don't want to have to do this.
Once again, thanks sincerely for your help.
Matt
|
|
|
|
|
Peter,
OK, forget what I just wrote. If just found some words in the MSDN that would seem to imply that DllMain is used even if you use load time dynamic linking of the library. (Which I guess means that LoadLibrary must be invoked for you if you use load-time dynamic linking?)
Let me know if I'm lost. Let me know if I'm not lost. I'm forging ahead.
Matt
|
|
|
|
|
Hi
I have an application running with 2 forms.
however when i run it i get the following error:
c:\.......\stdafx.obj': <unknown>
Possible cause
If the message says "bad file number", the file may have been closing in the foreground while compiling in the background.
it seams there is a problem with #include "StdAfx.h"
at the begining of my plc.cpp class file. I have plc.h, and plc.cpp !!!
can someone please help me?
|
|
|
|
|
Is this a compile error or run error? Where are you getting the error message from?
John
|
|
|
|
|
it is a faltal error. it seams to be the run error.
|
|
|
|
|
Then a message box pops up with the error? The reason why I ask is I have seen this as a compile error and the fix was to do a clean build by deleting the release and debug folders and recompile however if it is a runtime error I am not sure if this could be the problem.
John
|
|
|
|
|
I'm pretty sure he's getting a compile time error and does not understand what you're asking him.
Christian
I have drunk the cool-aid and found it wan and bitter. - Chris Maunder
|
|
|
|
|
|
You mean it compiles, runs and then you get this error ?
Christian
I have drunk the cool-aid and found it wan and bitter. - Chris Maunder
|
|
|
|
|
no no it does not RUN... it is a compiler error.
Sorry for the mistake.
|
|
|
|
|
OK - could you post the code that is causing the problem ? Can you comment any lines out of stdafx.h and cause it to compile ?
Christian
I have drunk the cool-aid and found it wan and bitter. - Chris Maunder
|
|
|
|
|
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// C RunTime Header Files
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
// TODO: reference additional headers your program requires here
this is all the code i have in stdafx.h!!!
I have not add anything to it!!!!
This is the default file when you want to build a form.net application... and i dont undrestand the pupose of it entirlt.
|
|
|
|
|
hold on a sec
the program will not run
but in the comments it says:
fatal error C1084: cannot read CLR runtime data file c:....stdafx.obj
|
|
|
|
|
I'd do a clean and rebuild all, it's compiling the individual files but cannot read one of them for some reason.
And you should check the 'do not treat <'s as HTML tags' box below when you post anything that could be mistaken for a tag.
Christian
I have drunk the cool-aid and found it wan and bitter. - Chris Maunder
|
|
|
|
|
Thanks Christan. I dont know why it happens sometimes but I copied another sdfxa.cpp file from another project and it works fine now ;)
|
|
|
|
|
|
Hi, I would appreciate any help here: I have written a program to read data from a serial input and display the character value one at a time. I would like to alter the program to read binary data from the serial input, store the data as an array, and display the entire array at once. The new data should be integers. Right now, the data is displayed one at a time. I have very limited knowledge of Visual C++ and really need some help. Thanks.
|
|
|
|
|
Are you have trouble with stopbits or 7bit characters? What do you mean by "display" are you talking bout plotting it as you mentioned in the subject line or just displaying it numerically?
My neighbours think I am crazy - but they don't know that I have a trampoline. All they see my head bobbing up and down over the fence every five seconds
|
|
|
|
|
I guess my question is really: How do I read binary data from serial port into an array? I would like to have the array displayed on screen according to pixel value, as soon as the array is full, so they should be in an int array.(?) When array is full, it should clear and start reading again. Thank you.
|
|
|
|
|
Open the serial port using CreateFile. Read the data using ReadFile. Close the port using CloseHandle.
Here is some code to open the port:
class COMPort
{
public:
COMPort() {
m_bOpened=FALSE;
m_hCom=INVALID_HANDLE_VALUE;
}
~COMPort() {
if ( m_hCom != INVALID_HANDLE_VALUE ) {
CloseHandle(m_hCom);
}
}
BOOL OpenSerialPort();
public:
BOOL m_bOpened;
HANDLE m_hCom;
};
COMPort::OpenSerialPort()
{
if(!m_bOpened)
{
DCB dcb;
BOOL fSuccess;
COMMTIMEOUTS CommTimeouts;
m_hCom = CreateFile("COM2",
GENERIC_READ | GENERIC_WRITE,
0, NULL,
OPEN_EXISTING,
0, NULL);
if(m_hCom == INVALID_HANDLE_VALUE)
{
return FALSE;
}
fSuccess = GetCommState(m_hCom, &dcb);
if(!fSuccess)
{
return FALSE;
}
dcb.BaudRate = CBR_57600;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
dcb.fBinary = TRUE;
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.fDsrSensitivity = FALSE;
dcb.fOutX = FALSE;
dcb.fInX = FALSE;
dcb.fParity = FALSE;
dcb.fNull = FALSE;
dcb.fRtsControl = RTS_CONTROL_DISABLE;
dcb.fAbortOnError = FALSE;
fSuccess = SetCommState(m_hCom, &dcb);
if(!fSuccess)
{
return FALSE;
}
GetCommTimeouts(m_hCom, &CommTimeouts);
CommTimeouts.ReadIntervalTimeout = 20;
CommTimeouts.ReadTotalTimeoutMultiplier = 20;
CommTimeouts.WriteTotalTimeoutMultiplier = 0;
CommTimeouts.WriteTotalTimeoutConstant = 100;
fSuccess = SetCommTimeouts(m_hCom, &CommTimeouts);
if(!fSuccess)
{
return FALSE;
}
PurgeComm(m_hCom, PURGE_TXABORT | PURGE_RXABORT);
m_bOpened = TRUE;
}
return m_bOpened;
} Here is code to read the data:
COMPort::SomeMemberFunction()
{
DWORD num;
unsigned char data[10];
if(m_bOpened) ReadFile(m_hCom, &data[0], 1, &num, NULL);
} John
|
|
|
|
|
If you don't know the number of int's arriving than you should declare it as a templated vector, or CDWordArray and use SetAtGrow() to add the values. You also need to know if they are 16 bit or 32 bit integers although I suspect that they are 32 bit. If they are 32 bit and are in the correct byte order (look up little endian and big endian) you can just cast them into a memory space containing the data
for example if you read the data into a character array called sData and if you know the integer starts at sData[37], you can just go
int nBuf = (int*)(&(sData[37]));
then increment 4 bytes if it is 32 bits, for the next one, and so on.
Then to transfer it to a CDWordArray dwarData
dwarData.SetAtGrow(nNumValue++, nBuf);
You may be able to find some plotting routines in the MFC / Graphics section of Code Project to plot it.
My neighbours think I am crazy - but they don't know that I have a trampoline. All they see my head bobbing up and down over the fence every five seconds
|
|
|
|
|
BTW you seem to be under the impression that this is a half hour job and it sounds more like the better part of a week job, expecially if you are a beginner programmer in VC++.
My neighbours think I am crazy - but they don't know that I have a trampoline. All they see my head bobbing up and down over the fence every five seconds
|
|
|
|