从Arduinostring到Excel BSTR通过c ++ DLL的随机字符

所以在一些Arduino的代码中,我是Serial.print的一些数字( var1=##,var2=##,var3=## )。 我有一个C ++的DLL,我正在得到这个信息,并parsing它到这样一个变种数组( "var1=",##.##,"var2=",##.##,"var3=",##.## )将string部分存储为变体BSTR,将#作为变体加倍。 这个变体数组来自Excel,我的C ++ DLL的目的是允许从Excel和Arduino板进行串行通信。

我的问题是,不是像我想的那样获取信息,而是在最后得到很多额外的乱码,并且不知道它是从哪里来的。 我之前把相关的代码包括在内,因为我知道那个部分是可以肯定的。 现在,Arduino代码只是发送( ##,##,## )然后Serial.println(); 使事情变得简单,因为没有string,只是数字。

VBA代码:

 'collects all rows available currently up to 1000(global numRows) lines each time, stores result in dataArray Public Function getAllData() Dim stringArray() As Variant Dim variantArray() As Variant ReDim stringArray(0 To 3000) As Variant ReDim variantArray(0 To 3000) As Variant If Main.dataCollectionActive Then Dim staringDataRow As Integer staringDataRow = currentDataRow Dim returnValue As Long returnValue = GetAllDataTypes(stringArray(), variantArray(), currentDataRow) If Not (returnValue = 0) Then If Not (returnValue = -1) Then If printWhileCollectingData = True Then ' Call printVariantData Dim row As Integer Dim col As Integer For row = startingDataRow To (currentDataRow - 1) Main.dataBox.Text = Main.dataBox.Text & stringArray(row) For col = 0 To (getNumColumns() - 1) Main.Cells(row + startingRow, col + startingCol).Value = variantArray(col + (row * getNumColumns())) Next col Next row End If End If End If 'only stoped in Main sheets code for stopDataButton or if the array has reached its limit If Not ((currentDataRow * getNumColumns) = UBound(variantArray())) Then Application.OnTime Now + TimeValue("00:00:01"), "getAllData" End If Main.Range("$L$4").Value = currentDataRow End If End Function 

C ++ DLL代码:

 //end1 comes before end2, so end1 = i-1 and end2 = i characters DLL_EXPORT bool WINAPI isEndLine(char end1, char end2){ //check for CRLF if (end1 == '\r') { if (end2 == '\n') { return true; } } //check for normal endLine \0 else if ((end1 == '\0')) { return true; } //check for users own endLine character else{ for(int i = 0; i < MAX_ENDLINE_LENGTH; i++){ if (end1 == endLine[i]){ return true; } } } return false; } //reads a single character from buffer, if there is nothing returned then the global, bufferAvailable is set to false, so that no more characters are asked for, for now DLL_EXPORT char WINAPI readCharFromSerial() { char dataChar[1]; DWORD dwBytesRead = 0; //number of data bytes read in if(!ReadFile(hSerial, dataChar, 1, &dwBytesRead, NULL)) { //gets data if successful, if not then notifies user ErrorExit("ReadFile, reading a character"); } if (dwBytesRead == 0) { bufferAvailable = false; } return dataChar[0]; //returns read in data } //reads a single line by pulling one character at a time until it finds the end of line character, if the buffer has characters in it DLL_EXPORT void WINAPI readLineFromSerialPort(char* line, int length) { bufferAvailable = true; int i = 0; line[i] = readCharFromSerial(); i++; if (bufferAvailable){ do{ line[i] = readCharFromSerial(); i++; }while((!isEndLine(line[i-2], line[i-1])) && (i < length)); if(line[i-2] == '\r') { line[i-2] = '\n'; line[i-1] = '\0'; } if(!(i<length)){ MessageBoxA(NULL, (LPCSTR)("string length not long enough"), TEXT("readLineFromSerialPort"), MB_OK); } } } DLL_EXPORT void WINAPI PlaceDblInVarDbl(varArr* VD, double data) { (VD->ptr[VD->index]).vt = VT_R8; //FIXME add function to do this (VD->ptr[VD->index]).dblVal = data; VD->index++; } DLL_EXPORT void WINAPI PlaceCharPtrInVarBstr(varArr* VD, char* cString) { BSTR bstr = new OLECHAR[MAX_DATA_LENGTH]; const char* Cstring = (const char*)cString; mbstowcs(bstr, Cstring, MAX_DATA_LENGTH); VD->ptr[VD->index].vt = VT_BSTR; SysReAllocString(&((VD->ptr[VD->index]).bstrVal), bstr); VD->index++; } DLL_EXPORT int WINAPI ParseCharPtrToVarBstrAndVarDbl(varArr* VD, char* dataString) { //FIXME perhaps make an array of chars for strings that are allowed without being coppied, this would be added to the if begging with !isdigit (like the '.') bool hasLetters = false; int endIndex = 0; int startIndex = 0; // MessageBoxA(NULL, (LPCSTR)("entered"), TEXT("ParseCharPtrToVarBstrAndVarDbl"), MB_OK); while (!(isEndLine(dataString[endIndex], dataString[endIndex+1]))) { hasLetters = false; startIndex = endIndex; while (!isDelim(dataString[endIndex]) && (!(isEndLine(dataString[endIndex-1], dataString[endIndex])))) { if (!(isdigit(dataString[endIndex])) && !(dataString[endIndex] == ' ') && !(dataString[endIndex] == '.')) { hasLetters = true; } endIndex++; } // MessageBoxA(NULL, (LPCSTR)("delimeter found"), TEXT("ParseCharPtrToVarBstrAndVarDbl"), MB_OK); if((startIndex + 1 == endIndex) || (startIndex == endIndex)/* && !(isEndLine(dataString[endIndex-1], dataString[endIndex]))*/) { //FIXME odd way to fix CRLF problem // MessageBoxA(NULL, (LPCSTR)("triggered if"), TEXT("ParseCharPtrToVarBstrAndVarDbl"), MB_OK); } else if (hasLetters) { //string char smallerString[MAX_DATA_LENGTH]; const char* DStr = (const char*)(&(dataString[startIndex])); strncpy(smallerString, DStr, endIndex-startIndex+1); smallerString[endIndex-startIndex+1] = '\0'; PlaceCharPtrInVarBstr(VD, smallerString); // MessageBoxA(NULL, (LPCSTR)("triggered hasLetters"), TEXT("ParseCharPtrToVarBstrAndVarDbl"), MB_OK); } else { //double //FIXME remove whitespace char* start = &dataString[startIndex]; char* eOS = &(dataString[endIndex]); char** endOfString = &eOS; double data = strtod(start, endOfString); //FIXME do some error checking PlaceDblInVarDbl(VD, data); // MessageBoxA(NULL, (LPCSTR)("triggered does not hasLetters"), TEXT("ParseCharPtrToVarBstrAndVarDbl"), MB_OK); } endIndex++; } //, MessageBoxA(NULL, (LPCSTR)("exited"), TEXT("ParseCharPtrToVarBstrAndVarDbl"), MB_OK); return VD->startingIndex - VD->index; } //first read a lines from the serial port and then parse it into dataArray, does this until there is no data in buffer or array is full //returns how many rows that it read DLL_EXPORT int WINAPI GetAllDataTypes(LPSAFEARRAY* unparsedData, LPSAFEARRAY* parsedData, int* currentDataRow) { bufferAvailable = true; varArr UPD; OpenVariantSafeArray(&UPD, unparsedData, *currentDataRow); if (UPD.failed) { return -1; } varArr PD; OpenVariantSafeArray(&PD, parsedData, *currentDataRow); if (PD.failed) { return -1; } while (bufferAvailable && ((PD.index + 10) < PD.uBound)) { char dataString[MAX_DATA_LENGTH]; readLineFromSerialPort(dataString, MAX_DATA_LENGTH); if (bufferAvailable) { PlaceCharPtrInVarBstr(&UPD, dataString); ParseCharPtrToVarBstrAndVarDbl(&PD, dataString); } } CloseVariantSafeArray(&UPD, unparsedData); if (UPD.failed) { return -1; } CloseVariantSafeArray(&PD, parsedData); if (PD.failed) { return -1; } *currentDataRow += UPD.index - UPD.startingIndex; bufferAvailable = true; return UPD.index - UPD.startingIndex; } 

结果错误:

这是在Excel中的文本框中打印时返回的未parsing的string。

 0.00,0.01,0.00
 0.10,0.02,0.01
 0.20,0.03,0.02
 0.30,0.04,0.03
 0.40,0.05,0.04
 0.50,0.06,0.05
 0.60,0.07,0.06
 0.70,0.08,0.07
 0.80,0.09,0.08
 0.90,0.10,0.09
 1.00,0.10,0.10

但是由VBA for循环打印在单元格中的parsing的string。 仍然有随机字符。 看起来,我的parsing在DLL中有什么问题,因为最后一个double总是以一个string结尾,然后它总是随机的string。

 0.000 0.010“0.00
 “
 -  0.100 0.020
 “0.01
 “ -  0.200
 0.030“0.02
 “ - 
 0.300 0.040“0.03
 “
 -  0.400 0.050
 0.900 0.100“0.09
 “
 -  0.000 0.100
 “0.10
 “ -  0.100
 0.110“0.11
 “ - 
 0.200 0.120“0.12
 “
 -  0.300 0.130
 “0.13
 “ -  0.400
 0.140“0.14
 “ - 
 0.500 0.150“0.15
 “
 -  0.600 0.160
 “0.16
 “ -    
 “0.25
 “ -  0.600
 0.240“0.26
 “ - 
 0.700 0.250“0.27
 “
 -        

DLL代码中ParseCharPtrToVarBstrAndVarDbl()的最后endIndex ++跳过分隔符跳过string中的空终止符。 修正是为string的末尾添加最后的if语句,如果是,则返回。