Solved

WriteFileEx C++ and threads

Posted on 1998-05-05
3
1,433 Views
Last Modified: 2013-11-20
I have spawned four threads that write to four different serial ports. Each is spawned as an instance of the class Centrix.  I am using C++ and the call WriteFileEx to write to the ports.  The problem is with the IOCOMPLETION routine for writefileex. I seem to be only able to to declare the call back routine in the class as follows
      static void WINAPI CCentrix::WriteCompletionRoutine(DWORD dwErrorCode, DWORD dwNumberOfNytesTransferred, LPOVERLAPPED pOverlapped);
 
Within the callback routine I want to compare the number of bytes transferred with the number of bytes to transfer.
void WINAPI CCentrix::WriteCompletionRoutine(DWORD dwErrorCode, DWORD dwNumberOfNytesTransferred, LPOVERLAPPED pOverlapped)
{

if (dwNumberOfNytesTransferred != m_DWBytesToWrite)
      {
      TRACE("WARNING: WriteFileEx() error.. Bytes Sent: %d; Message Length: %d\n", m_DWBytesToWrite, dwNumberOfNytesTransferred);
      }
}

The variable m_DWBytesToWrite is a class member of Centrix(my own class).  Because the routine is static I don't get a this pointer so therefore I cannot access the class member variable m_DWBytesToWrite If I declare the variable static it does not exist for a particular instance of the object which defeats the purpose of having a different instance of the class for each thread.

What I want to do is to be able to access the class member variables within the callback routine.Also I want the callback routine tied to a particular instance of the object.The solution would be to delcare the callback routine as follows
void WINAPI CCentrix::WriteCompletionRoutine(DWORD dwErrorCode, DWORD dwNumberOfNytesTransferred, LPOVERLAPPED pOverlapped)
but this gives me a compile error in the call to WriteFileEx. If anyone knows how I can declare the WriteCompletionRoutine as not being static or some other way of solving this problem I would be gratefull. I know that I can use the call WriteFile instead but I want to use the WriteFileEx call.

Regards,
Eddie.

Eddie
 
0
Comment
Question by:epmcevoy
  • 2
3 Comments
 
LVL 4

Accepted Solution

by:
piano_boxer earned 100 total points
ID: 1307537
Your right in that you can only declare the callback as a static member function of your class.

To get to the correct class from the callback, derive a new class from OVERLAPPED and include a pointer to the class in it.

class COverlapped : public OVERLAPPED
{
    CCentrix* m_pClass;
}

Replace your OVERLAPPED structs with this new class and before using it initialize m_pClass to the object that 'owns' the overlapped operation.

Then in your WriteCompletionRoutine cast the pOverlapped param to COverlapped

    COverlapped* pOL = (COverlapped*)pOverlapped;
    CCentrix* pClass = pOL->m_pClass;

One other thing you could do with the COverlapped class is to make the constructor initialize the OVERLAPPED struct:

COverlapped::COverlapped()
{
    Internal = 0;
    InternalHigh = 0;
    Offset = 0;
    OffsetHigh = 0;
    hEvent = NULL;
}

REMEMBER: Treat the class COverlapped as a normal overlapped structure.

   
0
 

Author Comment

by:epmcevoy
ID: 1307538
Thanks, I have implemented your soultion and I can now access the class members. I have one addition that I was wondering if you could answer.. Because the callback proc is static do I have to do some thread sychncronization before I call the WriteFileEx procedure. Reason being that each thread will be calling the same callback procedure and because it is static it is not owned by the calling class. If this is the case how do I perform simultanious writes to different comports using the WriteFileEx.

See below

void WINAPI CCentrix::WriteCompletionRoutine(DWORD dwErrorCode, DWORD dwNumberOfNytesTransferred, LPOVERLAPPED pOverlapped)
{
      COverlapped* pOL = (COverlapped*)pOverlapped;
      CCentrix* pClass = pOL->m_pClass;

if (dwNumberOfNytesTransferred != pClass->m_DWBytesToWrite)
      {
      TRACE("WARNING: WriteFileEx() error.. Bytes Sent: %d; Message Length: %d\n", pClass->m_DWBytesToWrite, dwNumberOfNytesTransferred);
      }
}


void CCentrix::WriteExCmdToPort(CCentrix* port)
{
//      unsigned short length = port->SerialCmdRec.length;
      char Data[] = "Were getting there....slowly but surely Were getting there....slowly but surely Were getting there....slowly but surely";
      BOOL bResult = TRUE;
      COverlapped            WrtExOverlapped;            // New class with overlapped structure in it.
                                                                  

      WrtExOverlapped.m_pClass = port;            // Init the centrix element of WrtExOverlapped to point to the class we are working on at the moment.

      port->m_DWBytesToWrite = port->SerialCmdRec.length;
       ResetEvent(port->m_hWriteCmdEvent);

       // Gain ownership of the critical section so that we have only one callback routine running at any one particular time.
      EnterCriticalSection(&port->m_csCommunicationSync);

      
      // Initailize variables      
      WrtExOverlapped.Offset = 0;
      WrtExOverlapped.OffsetHigh = 0;

      port->m_ov.Offset = 0;            
      port->m_ov.OffsetHigh = 0;

      // Clear buffer
      PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);

      bResult = WriteFileEx(port->m_hComm,
                                          port->m_szWriteCmdBuffer,
                                          port->m_DWBytesToWrite,
                                          &WrtExOverlapped,
                                          WriteCompletionRoutine);
      

      SleepEx(INFINITE, TRUE);
      
                  
      LeaveCriticalSection(&port->m_csCommunicationSync);



}
0
 
LVL 4

Expert Comment

by:piano_boxer
ID: 1307539
In your case I do not think you need to do any thread sync. It should be safe for you to remove the EnterCriticalSection() / LeaveCriticalSection() calls.

Each time the callback is called, you only touch data belonging to the SAME instance of the CCentrix or COverlapped class as allocated for the thread.

Remember IO completion routines are called in the context of the threads then called WriteFileEx().

Just keep in mind, if two or more threads accesses the same variable (and modyfies it), you need to protect it by a critical section (or simular).

TIP! Use the CCriticalSection/CSingleLock classes, its much easier.
0

Featured Post

Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Add content to output file 4 63
WinWaitActive parameters 12 31
move a line in eclipse 3 99
twoTwo  challenge 35 101
Introduction: Dynamic window placements and drawing on a form, simple usage of windows registry as a storage place for information. Continuing from the first article about sudoku.  There we have designed the application and put a lot of user int…
Introduction: Load and Save to file, Document-View interaction inside the SDI. Continuing from the second article about sudoku.   Open the project in visual studio. From the class view select CSudokuDoc and double click to open the header …
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, just open a new email message. In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…

813 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now