1
Answer

Performance issue when using DLL Import to call C++ function from C#

Galit

Galit

16y
6k
1

Hi,

We are using a C++ dll from our C# code.
The C++ code reads data from a serial communication port, and fills up a buffer with the data read.

We are sometimes experiencing a big delay (around 5 seconds) when the C++ function returns.

The C# code looks something like this:

class Program   
{

 

[DllImport("SerialCommunication.dll", EntryPoint = "SerialCommRead", SetLastError = true)]

protected static extern unsafe SERIAL_COM_STATUS SerialCommRead(uint handle,
   [MarshalAs(UnmanagedType.LPArray)] byte[] buffer,
    uint length, [MarshalAs(UnmanagedType.LPArray)] uint[] bytesRead);

 

protected void Read()

{

  StreamWriter logWriter = new new StreamWriter("test.log", true);

  SERIAL_COM_STATUS status = SerialCommRead(m_PortHandle, m_ReadBuffer,(uint)m_ReadBuffer.Length, bytesRead);
  DateTime t = DateTime.Now;

  logWriter.Write(t.Day.ToString() + "/" + t.Month.ToString() + "/" + t.Year.ToString() + " " +

     t.Hour.ToString() + ":" + t.Minute.ToString() + ":" + t.Second.ToString() + "." +
     t.Millisecond.ToString() + " ");

  logWriter.WriteLine("After SerialCommRead(), status: " + status.ToString() + " bytesRead: " +
     bytesRead[0].ToString());

  logWriter.Flush();

}

}

 

 

The C++ code:

 

__declspec(dllexport) SERIAL_COM_STATUS SerialCommRead(HANDLE handle, unsigned char *buffer,

unsigned int length, unsigned int *bytesRead)

{          

            COMSTAT ComStat;

            DWORD errorFlags, err;

            *bytesRead = 0;

            OVERLAPPED overlappedRead;

            memset(&overlappedRead, 0, sizeof(OVERLAPPED));

            overlappedRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

            if (!overlappedRead.hEvent) {

                        err = GetLastError();

                        return(SER_COM_CREATE_EVENT_ERROR);

            }

            if (!ClearCommError(handle, &errorFlags, &ComStat)) {

                        err = GetLastError();

                        CloseHandle(overlappedRead.hEvent);

                        return(SER_COM_READ_ERROR);

            }

            if (!ComStat.cbInQue) {

                        CloseHandle(overlappedRead.hEvent);

                        return(SER_COM_OK); // There is nothing in queue to read

            }

            DWORD numOfBytesRead = 0;

            if (!ReadFile(handle, (LPVOID)buffer, (DWORD)length, &numOfBytesRead, &overlappedRead)) {

                        err = GetLastError();

                        if (ERROR_IO_PENDING == err) {

                                    DWORD res = WaitForSingleObject(overlappedRead.hEvent, SER_COM_OVERLAP_READ_TIMEOUT);

                                    switch (res) {

                                                case WAIT_OBJECT_0:

                                                            if (!GetOverlappedResult(handle, &overlappedRead, &numOfBytesRead, TRUE)) {

                                                                        err = GetLastError();

                                                                        CloseHandle(overlappedRead.hEvent);

                                                                        return(SER_COM_GET_OVERLAP_ERROR);

                                                            }

                                                            break;

                                                case WAIT_TIMEOUT:

                                                            *bytesRead = (unsigned int)numOfBytesRead;

                                                            CloseHandle(overlappedRead.hEvent);

                                                            return(SER_COM_TIMEOUT_ERROR);

                                                case WAIT_FAILED:

                                                            err = GetLastError();

                                                            *bytesRead = (unsigned int)numOfBytesRead;

                                                            CloseHandle(overlappedRead.hEvent);

                                                            return(SER_COM_WAIT_ERROR);

                                                default:

                                                            *bytesRead = (unsigned int)numOfBytesRead;

                                                            CloseHandle(overlappedRead.hEvent);

                                                            return(SER_COM_ERROR);

                                    }

                        } else {

                                    CloseHandle(overlappedRead.hEvent);

                                    return(SER_COM_READ_ERROR);

                        }

            }

            CloseHandle(overlappedRead.hEvent);

            *bytesRead = (unsigned int)numOfBytesRead;

            PrintToFile("SerialCommRead(): going to return");

            return(SER_COM_OK);

}

 

void PrintToFile(char *str)

{

            struct _timeb timebuffer;

            _ftime( &timebuffer );

            char timeline[26];

            ctime_s( timeline, 26, & ( timebuffer.time ) );

            static FILE *fHandle = NULL;

            if (NULL == fHandle)

            {

                        // First time, open th file

                        fHandle = fopen(“test2.log”, "wt");

            }

            if (fHandle) {

                        fprintf(fHandle, "%.19s.%hu ", timeline, timebuffer.millitm);

                        fprintf(fHandle, "%s\n", str);

                        fflush(fHandle);

            }

}

 

In file “test2.log” the printout of “SerialCommRead(): going to return” appears with a timestamp that is sometimes 5 seconds earlier than the printout to “test.log” from the C# code.

Looks like it takes the C++ function 5 seconds to return…

 

Any ideas?

 

Thanks,

 

            Galit.

Answers (1)