|
Without knowing your exact problem I have a feeling that you should have another design session.
It seems to me like you are writing both the driver and some app that uses the driver and you have mixed up the responsabilities for a successful write operation between the two.
I assume we are talking about a blocking call, otherwise I don't see the problem.
The return value from the write operation in the driver should tell the caller whether the operation was successful or not. For the write operation to be successful an ACK is required from the device.
Usually I tend to solve problems like this by having a thread that reads incoming data and maybe even interpret the data. In case of an ACK I would set an event that the write function waits for before returning with a call to WaitForSingleObject. The timeout should be reasonably short to be able to return as fast as possible, but yet long enough to give the device a chance to respond.
In case of a timeout the write operation should return a value that informs the caller that the operation failed and why, if possible.
If I'm wrong in my assumptions above, here's what you asked for:
if( ::WaitForSingleObject( hThread, 100 ) == WAIT_TIMEOUT )
{
::ExitThread( hThread );
}
::CloseHandle( hThread );
Note that ::CloseHandle does not terminate the thread, you have to use ::ExitThread() for that and afterwards close all handles to the thread.
Hope this helps
--
Roger
|
|
|
|
|
Thanks for your time and reply,
i tried ExitThread() Function. It gave me following error.
error C2664: 'ExitThread' : cannot convert parameter 1 from 'void *' to 'unsigned long'
And when i tried to use it as follows
::ExitThread(0);
It sometimes exits the main application thread. I feel this happens when thread successfully executes and returns before the time out.
Can i get some more info regarding this
|
|
|
|
|
Hello...
Roger Stoltz wrote:
if( ::WaitForSingleObject( hThread, 100 ) == WAIT_TIMEOUT ){ ::ExitThread( hThread );}::CloseHandle( hThread );
This is wrong, ExitThread must be always called from that thread which should be end... That means inside the worker thread...
When you like to end a thread outside from worker thread then must use GetExitCodeThread and TerminateThread...
But in the most situations it exists an better solution...
|
|
|
|
|
your are right,
i use the following code and it is working (still not tested vigorously)
WaitForSingleObject(hThread, nTimeout);
DWORD dwWaitReturn;
GetExitCodeThread(hThread, &dwWaitReturn);
if(STILL_ACTIVE == dwWaitReturn)
{
AfxMessageBox("Write Error. Please retry");
ExitThread( 0 );
CloseHandle(hThread);
}
I do not use TerminateThread() function as it doesn't deallocates resources allocated to the thread.
and yes, i will use AfxBeginThread() to start my thread.
Thanks for your Efforts
|
|
|
|
|
HumanOsc wrote:
This is wrong, ExitThread must be always called from that thread which should be end... That means inside the worker thread...
Of course this is wrong! My mistake.
I virtually never use these functions to end a thread, I consider it a design problem and always try to find another solution, like you suggested.
I was too lazy to look up the name of the function I was looking for and mistook ::TerminateThread for ::ExitThread.
Really sorry.
Calling ::ExitThread does just what it sounds like: it exits the calling thread, like the main thread if the call is made from it.
However, the use of ::TerminateThread is not recommended since it too does what the name of the function sounds like: it terminates the thread in question.
"Terminate" as in Arnold Schwarzenegger "Hasta la vista, baby!" without letting the system reclaim allocated resources such as critical sections, heap, loaded DLLs and so on.
Due to the possible side effects of this function I always try to find another solution by refactoring.
I still consider the original problem a design problem.
--
Roger
|
|
|
|
|
Well, I am new to all this. When you said there design problem and explained it, i didn't understood much. Can you suggest me why it is a design problem, and How it should be designed to avoid the problems.
thanks a lot.
|
|
|
|
|
Please note that the following are recommendations and suggestions due to how I interpret the problem and your solution.
Why do I consider this a design problem?
There are two ways of solving problems like this:
1. sequential (blocking calls, synchronous, one thread)
2. parallel (non-blocking calls, asynchronous, multiple threads)
Whenever you are thinking "I start a thread here and wait for it to end" you are trying to solve a parallel problem in a sequential way or vice versa.
This is bad design.
Either you solve it in a sequential way by having a blocking call to your write function and when you have actually written the data it polls for an acknowledge before returning...or
you solve it in a parallel way by having a thread polling for acknowledgements and set an event when such an ack has been received.
In the latter case you will wait for the event to be signaled in your write function with ::WaitForSingleObject or similar. If the device doesn't respond within proper time your wait function will return WAIT_TIMEOUT and you know that the data was not written. You should select your timeout so that the user doesn't feel that the application has hung, e.g. < 1s.
The whole idea with a worker thread is to perform a task in the background and signal the main thread when the job is done, either by setting an event that another thread may be waiting for or posting a message.
If I have understood your problem correctly it all boils down to the fact that you want to write some data and to know if the data was properly written you are waiting for an acknowledge.
I understand this as the core of your problem.
As I understand it the ACK you are waiting for consists of data, i.e. to be able to know if you have received the ACK you have receive data.
What I would do is have a thread that receives data and interprets it, at least to know if the data received is an ACK and if it is use ::SetEvent() to signal an event. In the write function I would write the data and then call ::WaitForSingleObject with the handle of the event mentioned above as input parameter. If ::WaitForSingleObject returns WAIT_TIMEOUT I can return FALSE, -1 or whatever to notify the caller that the operation failed.
The receiving thread will be terminated when the connection to the device is closed.
HumanOsc recommended you an article written by Joseph Newcomer about worker threads. Joe has written lots of stuff that is absolutely worth reading at his own site: http://www.flounder.com/mvp_tips.htm[^]
The essential essays are in my opinion are about worker threads, message management, time management and "The n Habits of Highly Defective Windows Programs" since they address issues that one have to know as a windows developer combined with healthy coding standards and tips.
Hope this helped you
--
Roger
|
|
|
|
|
How to split the string based on new line character.
I have a string i.e.,
C:\MyDocuments\myDialog\release\myapp.exe
I want to retrive exe name . (ie., myapp.exe)
How it is possible.
I want to retrive right last exe name for all paths.
Give a flexible code.
Praveen Chowdam Kumar
|
|
|
|
|
hey buddy
use CStringT::Tokenize (as far as i think CString and CStringT functions same).
following is an exmple i found for you form msdn go through it.
Example:
The following example demonstrates the use of CStringT::Tokenize.
//typedef CStringT< TCHAR, StrTraitATL< TCHAR > > CAtlString;
CAtlString str( "%First Second#Third" );
CAtlString resToken;
int curPos= 0;
resToken= str.Tokenize("% #",curPos);
while (resToken != "")
{
printf("Resulting token: %s\n", resToken);
resToken= str.Tokenize("% #",curPos);
};
Output:
Resulting Token: First
Resulting Token: Second
Resulting Token: Third
|
|
|
|
|
CString str="C:\MyDocuments\myDialog\release\myapp.exe"
int indx=str.ReverseFind('\\');
if (indx!=-1)
CString fileName=str.Right(indx);
|
|
|
|
|
Why don't you check out the Class Members in CString?
Well, here goes:
Solution 1, CString:
CString cs = "C:\\MyDocuments\\myDialog\\release\\myapp.exe";
CString pureFileName;
int lastSlashOffset = cs.ReverseFind((TCHAR) '\\');
if(lastSlashOffset >= 0 && cs.GetLength > (lastSlashOffset + 1)) {
pureFileName = cs.Mid(pureFileName + 1);
}
// pureFileName contains the file name.
Solution 2 (good old splitpath):
#include <stdlib.h>
#include <stdio.h>
void main( void )
{
char path_buffer[_MAX_PATH];
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
strcpy(path_buffer, "C:\\MyDocuments\\myDialog\\release\\myapp.exe");
_splitpath( path_buffer, drive, dir, fname, ext );
printf( "Path extracted with _splitpath:\n" );
printf( " Drive: %s\n", drive );
printf( " Dir: %s\n", dir );
printf( " Filename: %s\n", fname );
printf( " Ext: %s\n", ext );
}
Output
Path extracted with _splitpath:
Drive: c:
Dir: \MyDocuments\myDialog\release\
Filename: myapp
Ext: .exe
|
|
|
|
|
This is the code that i have Tested with VC.6
it is actually the correction of the answer posted to the
quetion .
If ur using CString so its VC++ and for VC++ this format
is preferable.
<br />
CString str1="C:\\MyDocuments\\myDialog\\release\\myapp.exe";<br />
int indx=str1.ReverseFind('\\');<br />
indx++;<br />
if (indx!=-1)<br />
CString fileName=str1.Mid(indx);<br />
Vikas Amin
Embin Technology
Bombay
vikas.amin@embin.com
|
|
|
|
|
OOps ! I forgot to increment. thanks Vikas.
|
|
|
|
|
#include "shlwapi.h"
CString strPathName = _T("C:\\MyDocuments\\myDialog\\release\\myapp.exe");
LPTSTR pszFileName = PathFindFileName(strPathName);
CString strFileName = pszFileName;
Never forget to search MSDN.
That's all, folks!
One always gets the deserved.
|
|
|
|
|
YoSilver wrote:
PathFindFileName(strPathName);
Similarly you can use _tSplitPath() api also
"Opinions are neither right nor wrong. I cannot change your opinion. I can, however, change what influences your opinion." - David Crow
cheers,
Alok Gupta
VC Forum Q&A :- I/ IV
|
|
|
|
|
i want to chang the data of VT_DATE to the one of VT_BSTR with the VariantChangeTypeEx(&vargDest,&varSrc,2052,0,VT_BSTR) function, but only a part of the data is changed. for example,2005-12-20 0:00:00 is converted to 2005-12-20 of VT_BSTR, but 1899-12-30 21:30:00 is converted to 21:30:00 of VT_BSTR. both 2005-12-20 0:00:00 and 1899-12-30 21:30:00 are from sql server, and 2005-12-20 0:00:00 is smalldatetime; 1899-12-30 21:30:00 is datetime. how can i get the complete VT_BSTR data?
|
|
|
|
|
hi everyone, i want to write some letters on a sphere to give the letters third dimension, and i don't want to use openGl or DirectX, how ?
thanks in advance!
|
|
|
|
|
why not use one of them? If you want to do it yourself then you need to understand the maths involved.
If you just want a simple solution then draw the letters at the middle of the string bigger than at each end.
|
|
|
|
|
sounds like a good idea, i'll try. thanks again
|
|
|
|
|
i have tried,it looks uglily, maybe it is the time to review maths
|
|
|
|
|
In vc6 project with vss, what do the two icons in front of each file mean (one with a downward arrow, one without)? Thanks.
|
|
|
|
|
I have referred to the FAQ but the answer does not solve the problem actually...
Below is my code of creating srevice:
--------------------------------------------------------------------------------------------------
SC_HANDLE hService =
::CreateService(
handle, // handle to SCM database
servicename.c_str(), // name of the service to install
servicename.c_str(), // name that is displayed on SCM
SERVICE_ALL_ACCESS, // can be accessed only by administrators
SERVICE_WIN32_OWN_PROCESS, // service runs its own process
SERVICE_AUTO_START, // started by SCM when StartService() is called
SERVICE_ERROR_IGNORE, // error logged but service started
ss, // pathname of the executable
NULL, // service does not belong to any group
NULL, // service does not use a tag
NULL, // requires NtLmsSp and EventLog service to be running
".\\Administrator", // user name to log on
"s" // password
);
--------------------------------------------------------------------------------------------------
|
|
|
|
|
Hi!Dear,
I got a Link error when compile my windows app on visual studio c++ 6.0.
It says:
"LINK:fatal error LNK1104:can not open file '..\..\baseclasses\debug_unicode\quartz.lib'".
My Project Options:..\..baseclasses\debug_unicode\quartz.lib kernel32.lib ...
And when I changed by Project Options as:
:..\..baseclasses\debug_unicode\kernel32.lib quartz.lib ...
then the link error says:
"LINK:fatal error LNK1104:can not open file '..\..\baseclasses\debug_unicode\kernel32.lib'"
But I am quite sure that I have added the directories of these libray files.
Then,how to kill this matter?
Thanks!
|
|
|
|
|
momer wrote:
"LINK:fatal error LNK1104:can not open file '..\..\baseclasses\debug_unicode\quartz.lib'".
Do these files exist ? Apparently, they are not visible to the compiler.
momer wrote:
But I am quite sure that I have added the directories of these libray files.
Yes, but if you've added their directories to VC, then you need to link to just the file, and not a relative path to the file. Try removing all but the lib name and see how you go.
Christian Graus - Microsoft MVP - C++
|
|
|
|
|
If I remember correectly, quartz.lib is part of media player 9 so reinstall that.
Elaine
PS "Madam, can you help me" was appropriate here
The tigress is here
|
|
|
|