Convert from C to C#, or make DLL? [closed] - c#

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I am new to C# programming. I have a program that I modified in C, I now need to take the string array that I get from my C program and pass it to a C# program so that it can query an Oracle database using those values.
This program is used to get the serial numbers from all of the iButton devices connected to the computer.
Here is the C code
// function prototypes
void UnLoadTMEX(void);
short LoadTMEX(void);
// globals
static FARPROC Get_Version, TMGetTypeVersion, TMEndSession;
static FARPROC TMSetup, TMNext, TMRom, ExtendedStartSession;
static FARPROC TMReadDefaultPort;
long (__fastcall *TMExtendedStartSession)(short,short,void *);
static HINSTANCE hInst;
unsigned char state_buf[5125];
//--------------------------------------------------------------------------
// Main of iSerial64
//
void main(int argc, char **argv)
{
char refresh,buf[200];
short flag,i,didsetup=0;
short ROM[9];
short PortNum,PortType;
long SHandle;
char serialtmp[2], serial[10][17];
int j = -1;
// load the TMEX driver and get pointers to functions
if (!LoadTMEX())
{
printf("ERROR, could not load IBFS64.DLL\n");
exit(0);
}
// load the TMEX driver and get pointers to functions
TMReadDefaultPort(&PortNum, &PortType);
// get the TMEX driver version
printf("Port number: %d Port type: %d\n",PortNum,PortType);
Get_Version(buf);
printf("Main Driver: %s\n",buf);
printf("TYPE%d:",PortType);
if ((short)TMGetTypeVersion(PortType,buf) < 0)
{
printf("\nNo Hardware Driver for this type found!\n");
// Unload the TMEX driver
UnLoadTMEX();
exit(0);
}
printf(" %s\n\n\n",buf);
// check the command line
if (argc > 1)
PortNum = atoi(argv[1]);
// check for valid range of PortNum
if ((PortNum < 1) || (PortNum > 15))
{
printf("ERROR, invalid port requested: %d\n",PortNum);
exit(0);
}
// loop to display the rom numbers until key hit
do
{
// get a session handle to the requested port
SHandle = TMExtendedStartSession(PortNum,PortType,NULL);
if (SHandle > 0)
{
// check to see if TMSetup has been done once
if (!didsetup)
{
flag = (short)TMSetup(SHandle);
if (flag == 1 || flag == 2)
{
printf("TMSetup complete %d\n",flag);
didsetup = 1;
}
else
{
printf("ERROR doing setup %d\n",flag);
break;
}
}
// only get the next rom after setup complete
else
{
//j was added to keep track of the serial number strings
j++;
memset(serial[j], 0, strlen(serial[j]));
flag = (short)TMNext(SHandle,(void far *)&state_buf[0]);
if (flag > 0)
{
ROM[0] = 0;
flag = (short)TMRom(SHandle, (void far *)&state_buf[0], (short far *)&ROM[0]);
for (i = 7; i >= 0; i--)
{
//This section was changed from the original
//copies raw number into string
sprintf(serialtmp, "%02X", ROM[i]);
strcat(serial[j], serialtmp);
}
printf("%s ", serial[j]);
printf("\n");
}
else
printf("end of search\n");
}
// close the opened session
TMEndSession(SHandle);
}
}
while (flag > 0);
// Unload the TMEX driver
UnLoadTMEX();
printf("iSERIAL64 end\n");
}
//--------------------------------------------------------------------------
// Load the TMEX driver and get a pointers to the functions
//
short LoadTMEX(void)
{
// attempt to get a SHandle to the TMEX driver
hInst = LoadLibrary(L"IBFS64.DLL");
// get a pointer to the function needed by loopit64
if (hInst != NULL)
{
ExtendedStartSession = GetProcAddress(hInst,"TMExtendedStartSession");
TMEndSession = GetProcAddress(hInst,"TMEndSession");
TMSetup = GetProcAddress(hInst,"TMSetup");
TMNext = GetProcAddress(hInst,"TMNext");
TMRom = GetProcAddress(hInst,"TMRom");
Get_Version = GetProcAddress(hInst,"Get_Version");
TMGetTypeVersion = GetProcAddress(hInst,"TMGetTypeVersion");
TMReadDefaultPort = GetProcAddress(hInst, "TMReadDefaultPort");
// check to make sure got ALL of the functions needed
if ((ExtendedStartSession == NULL) || (TMEndSession == NULL) ||
(TMSetup == NULL) || (TMNext == NULL) ||
(TMRom == NULL) || (Get_Version == NULL) ||
(TMGetTypeVersion == NULL) || (TMReadDefaultPort == NULL))
{
printf("ERROR, could not get a pointer to all"
" of the TMEX functions needed\n");
return 0;
}
// get a function pointer that returns a long
TMExtendedStartSession = (long (__fastcall *)(short,short,void *))ExtendedStartSession;
return 1;
}
else
return 0;
}
//--------------------------------------------------------------------------
// UnLoad the TMEX driver
//
void UnLoadTMEX(void)
{
// release the TMEX driver
FreeLibrary(hInst);
}
Should I attempt to convert this, or just create a C DLL and import that into my C# program? Like I said, I haven't really worked with C#, I'm an intern and my boss is giving me this project so that I can learn C#. Any help is greatly appreciated

If you want use c dll in c# read this article.
But is better that convert the code to c# code because you can manage this code and update the code easily.

If your boss is giving you this project to learn C#, I'd say go ahead and convert it to C#. It will make future use of the code a lot easier.
I'd recommend looking at the book C# in Depth for a good intro to C#.

Related

How to call C# project function from C++ DLL project

I have two project, say named CPPDLLProject and CSharpProject.
Here in CPPDLLProject, there are few dllexport functions which can be called from CSharpProject and that calling is working fine.
But here I want to call CSharpProject's functions from CPPDLLProject so that can propagate data from C++ DLL to C# project.
Just for more explanation, Would like to add below code example.
Below is the function in the C++ DLL from which would like to call C# functions.
void __stdcall CPPDLLApp::PumpMessageData(int aCode, int aType)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
if (aCode == PUMP_UPDATE_MSG && aData != NULL)
{
switch (aType)
{
case MSG_ADD:
{
// Call the C# function to send the added msg to C# project
GetCPPDLLAppMsg("MSG added");
break;
}
case MSG_DELETE:
{
// Call the C# function to send the deleted msg to C# project
GetCPPDLLAppMsg("MSG deleted");
break;
}
case MSG_UPDATE:
{
// Call the C# function to send the updated msg to C# project
GetCPPDLLAppMsg("MSG updated");
break;
}
}
}
if (aCode == PUMP_STOP_MSG)
{
// Call the C# function to send the stop msg to C# project
break;
}
if (aCode == PUMP_START_MSG)
{
// Call the C# function to send the start msg to C# project
break;
}
}
Below is the C# project's function.
public void GetCPPDLLAppMsg(string aMessage)
{
Console.WriteLine(aMessage);
}
Please suggest how to achieve this goal.
I have done few googling but no luck.
My question might not be clear but any kind of help is appreciated.
I don't really understand your question, but you can use a intermediate dll and the following C++ method:
void *p = (void *)wglGetProcAddress(name);
if (p == 0 ||
(p == (void*)0x1) || (p == (void*)0x2) || (p == (void*)0x3) ||
(p == (void*)-1))
{
HMODULE module = LoadLibraryA("dllname.dll");
p = (void *)GetProcAddress(module, name);
}
name = name of the function
dllname = name of your dll
with this you will be able to load a dll and get the function pointer to wichever function you need, but you may need to compile a C# dll to use this, you can make a bridge or something

if (String.IsNullOrEmpty(myString)) and if (String.IsNullOrWhitespace(myString)) still working for empty strings [duplicate]

This question already has answers here:
string.Replace (or other string modification) not working
(4 answers)
Check if string is empty or all spaces in C#
(5 answers)
Closed 4 years ago.
my goal is to get a message from an other client over a server and work on with that message. Server and other client are in visual basic and if i try to communicate between two vb clients everything is fine, but i need the client in c# for my Unityproject.
My Problem is that there are still empty Messages at the Console, so i think the if() doesn't work correct.
Here is the relevant part of the Code:
try
{
theStream = mySocket.GetStream();
Byte[] inStream = new Byte[mySocket.SendBufferSize];
theStream.Read(inStream, 0, inStream.Length);
serverMsg += Encoding.ASCII.GetString(inStream);
serverMsg = serverMsg.Trim();
//if ((serverMsg == null || serverMsg == "")) doesn't work
//if (String.IsNullOrWhiteSpace(serverMsg)) doesn't work
//if (String.IsNullOrEmpty(serverMsg) || serverMsg.Length <1) doesn't work
INOWS = false;
INOWS = IsNullOrWhiteSpace(serverMsg);
if (INOWS)
{
// do nothing
}
else
{
Debug.Log("[SERVER] -> " + serverMsg);
}
}
catch (Exception e)
{
Debug.Log("[Fehler]" + e);
}
} while (socketReady == true);
public static bool IsNullOrWhiteSpace(string value)
{
if (value != null)
{
for (int i = 0; i < value.Length; i++)
{
if (!char.IsWhiteSpace(value[i]))
{
return false;
}
}
}
return true;
}
Thanks to your hints i tried using IsNullOrWhiteSpace, but this gave me an error "'string' does not contain a definition for IsNullOrWhiteSpace"
So i used this IsNullOrWhitespace but i still get at least one empty string at the console for every korrekt string. console view Do you have any other hints for me?
if (String.IsNullOrWhitespace(serverMsg))
{
// do nothing
}
IsNullOrWhitespace() checks null, whitespace(" ") and empty("")
Try trimming the string: if the string has any whitespace characters in it, it will still fail the IsNullOrEmpty() test.
In such cases (particularly with user or web service input), I generally use something like
if ((s ?? "").Trim() != "")
{
// do whatever processing you need to do here...
...
)

Trouble with reading I2OF5 barcode

I have two barcode scaners - MC9090 and MC9190. Initially under the MC9090 has been written application that reads barcodes and work with SQL databases.On the MC9090 everything works fine on the MS9190 - problem - not read the barcode type I2OF5 (length = min - 6, max - 8 respectively). Modify the default values (14 and 10 respectively) with the help of a piece of code (on MC9090):
myReader.Decoders.I2OF5.MinimumLength = 6;
myReader.Decoders.I2OF5.MaximumLength = 8;
With MC9190 I can read I2OF5 barcodes with default parameters(14 and 10 respectively), but I cant read I2OF5 barcodes with lenght min = 6, max = 8.
Tried to send the complete list of parameters like this (already on MC9190):
myReader.Parameters.CodeIdType = CodeIdTypes.None;
myReader.Parameters.ScanType = ScanTypes.Foreground;
myReader.Decoders.I2OF5.MinimumLength = 6;
myReader.Decoders.I2OF5.MaximumLength = 8;
myReader.Decoders.I2OF5.Redundancy = true;
myReader.Decoders.I2OF5.CheckDigitScheme = I2OF5.CheckDigitSchemes.None;
myReader.Decoders.I2OF5.ConvertToEAN13 = false;
myReader.Decoders.I2OF5.ReportCheckDigit = false;
myReader.Actions.SetParameters();
With these parameters, barcodes are read in the demo applications Motorola's great, but not in mine app.
I do check like this:
if (_scnAPI.Reader.Decoders.I2OF5.Enabled == true)
{
if (_scnAPI.Reader.Decoders.I2OF5.MinimumLength == 6)
{
MessageBox.Show("6");
}
if (_scnAPI.Reader.Decoders.I2OF5.MaximumLength == 8)
{
MessageBox.Show("8");
}
if (_scnAPI.Reader.Decoders.I2OF5.Redundancy == true)
{
MessageBox.Show("Redundancy");
}
if (_scnAPI.Reader.Parameters.CodeIdType == Symbol.Barcode.CodeIdTypes.None)
{
MessageBox.Show("CodeType");
}
if (_scnAPI.Reader.Decoders.I2OF5.CheckDigitScheme == Symbol.Barcode.I2OF5.CheckDigitSchemes.None)
{
MessageBox.Show("CheckDigit");
}
if (_scnAPI.Reader.Parameters.ScanType == Symbol.Barcode.ScanTypes.Foreground)
{
MessageBox.Show("foreground");
}
}
else
{
MessageBox.Show("App Exit!");
Application.Exit();
}
All checks are passed, but it is not clear why there is no reading I2OF5 barcodes with the right length to me? Please help me figure out what the problem is.
P.S.
I use the library Symbol.Barcode, Motorola EMDK 2.4 for .NET. I looked specification of EMDK 2.4 version is compatible with the 9100- series.
https://atgsupportcentral.motorolasolutions.com/content/emb/docs/ReleaseNotes/Release%20Notes%20-%20EMDK-M-020403TnV1.htm
My experience: Code128 barcode settings blocked the I2OF5 reading.
public FormMain()
{
bcl.OnScan +=new Barcode2.OnScanHandler(bcl_OnScan);
bcl.Config.Decoders.I2OF5.Enabled = true;
bcl.Config.Decoders.CODE128.Enabled = false;
bcl.Config.Decoders.I2OF5.MinLength = 6;
bcl.Config.Decoders.I2OF5.MaxLength = 8;
bcl.Scan();
InitializeComponent();
}
Disable the CODE128, enable the I2OF5, and set the parameters of I2OF5. It workes for me!

0xC0000005: Access violation reading location 0xffffffffffffffff

I have:
An unmanaged C++ app
A C++/CLI Wrapper
A C# GUI
I am seeing this crash occur only in Release and not debug. The crash also does not occur on neither debug or release when the unmanaged C++ app is run by itself.
All I can say is the crash occurs in this line of code:
if ((std::find(vstrEEDRRMachines.begin(), vstrEEDRRMachines.end(), m_sFrame.strSourceAddress) != vstrEEDRRMachines.end()
&& std::find(vstrEEDRRMachines.begin(), vstrEEDRRMachines.end(), m_sFrame.strDestAddress) != vstrEEDRRMachines.end())
|| (std::find(vstrRRRHMachines.begin(), vstrRRRHMachines.end(), m_sFrame.strSourceAddress) != vstrRRRHMachines.end()
&& std::find(vstrRRRHMachines.begin(), vstrRRRHMachines.end(), m_sFrame.strDestAddress) != vstrRRRHMachines.end()))
{
// Create appropriate buffer size for raw message (i.e. size of payload along with the extra padding
// for decoding)
m_sFrame.iMessageSize = m_sFrame.iPayloadLength;
m_sFrame.iOriginalMessageSize = m_sFrame.iPayloadLength;
m_sFrame.pszMessage = new unsigned char[m_sFrame.iPayloadLength + Constants::RSSL_DECODE_PADDING];
m_sFrame.pszOriginalMessage = new unsigned char[m_sFrame.iPayloadLength + Constants::RSSL_DECODE_PADDING];
}
Although I can't see what's inside vstrEEDRRMachines and vstrRRRHMachines (because we are in release), I can see when in the original C++/CLI wrapper that there are valid string entries in the vector.
The stack trace is as follows:
msvcr100.dll!0000000069abbdc0() [Frames below may be incorrect
and/or missing, no symbols loaded for msvcr100.dll]
DataVerifier.exe!std::_Find,std::allocator
__ptr64,std::basic_string,std::allocator
(std::basic_string,std::allocator > * _First, std::basic_string,std::allocator > *
_Last, const std::basic_string,std::allocator > &
_Val) Line 41 + 0x4a bytes C++
DataVerifier.exe!DataVerifier::CPCAPParser::Parse(const char * szFileName,
std::vector
& vSFramesRWF1Messages, std::vector,std::allocator
,std::allocator,std::allocator
vstrEEDRRMachines, std::vector,std::allocator
,std::allocator,std::allocator
vstrRRRHMachines, RsslDataDictionary & rsslDataDictionary) Line 178 + 0x19 bytes C++ [External Code]
DataVerifierLib.dll!DataVerifierLib::PCAPParserWrapper::ParseWrapper(System::String^
strInputFileNames) Line 136 + 0xf6 bytes C++
DataVerifierGUI.exe!DataVerifierGUI.Form1.button1_Click(object
sender, System.EventArgs e) Line 42 + 0x30 bytes C#
user32.dll!00007fff7a8c250d() user32.dll!00007fff7a8c2367()
System.Windows.Forms.ni.dll!00007fff535368c0()
The crash specifically occurs in c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\algorithm in this part of the code:
// TEMPLATE FUNCTION find
template<class _InIt,
class _Ty> inline
_InIt _Find(_InIt _First, _InIt _Last, const _Ty& _Val)
{ // find first matching _Val
for (; _First != _Last; ++_First)
if (*_First == _Val) <-- CRASH OCCURS HERE
break;
return (_First);
}
I have no idea what's going on, since release mode with C# + C++/CLI + C++ apps is where the crash is occurring. Is there any way I can easily fix this?
EDIT
It seems like this occurs 9 times out of 10, but i've noticed the times it does work, when I check the parameters of the Parse function just as it goes into the function (no lines are executed yet), all 3 vectors have normal values (the 1st one is 0, the second and third contain IP addresses as expected). However, most of the time, as soon as we get into the Parse function, all 3 vectors have negative size and capacities... and when they are used, everything goes boom. I'm going to past the entrance of the Parse function and also the C++/CLI wrapper before it.
bool CPCAPParser::Parse(const char* szFileName, std::vector<CRWFCapsule> &vSFramesRWF1Messages, std::vector<std::string> vstrEEDRRMachines, std::vector<std::string> vstrRRRHMachines, RsslDataDictionary &rsslDataDictionary) // change to a vector of rwf1capsules
{
This is the C++/CLI Wrapper:
// This is the main DLL file.
#include "stdafx.h"
#include "DataVerifierLib.h"
// Constructor Implementation
DataVerifierLib::PCAPParserWrapper::PCAPParserWrapper()
{
}
std::vector<std::string> DataVerifierLib::PCAPParserWrapper::CreateNewMachineCollection(std::vector<std::string> vstrNewMachines, std::vector<std::string> vstrMachine1, std::vector<std::string> vstrMachine2)
{
vstrNewMachines.reserve(vstrMachine1.size() + vstrMachine2.size()); // preallocate memory
vstrNewMachines.insert(vstrNewMachines.end(), vstrMachine1.begin(), vstrMachine1.end());
vstrNewMachines.insert(vstrNewMachines.end(), vstrMachine2.begin(), vstrMachine2.end());
return vstrNewMachines;
}
bool DataVerifierLib::PCAPParserWrapper::ParseWrapper(String^ managedString)
{
// String conversion from c# to c++
String^ managedStringTmp = managedString;
std::string strInputFileNames = msclr::interop::marshal_as<std::string>(managedStringTmp);
std::vector<std::string> vRRMachines;
std::vector<std::string> vRHMachines;
std::vector<std::string> vEEDMachines;
std::vector<std::string> vPorts; // decide on what checks are to be made. Should frame have matching src/dest ports? or just one of them.
std::vector<std::string> vEEDRRMachines;
std::vector<std::string> vRRRHMachines;
std::vector<std::string> vstrLines;
std::string strTxtFile = "ServerIPList.txt"; //argv[2]; // ServerIPList.txt
std::string strLine;
std::ifstream in(strTxtFile);
if (!in)
{
std::cout << "There was a problem opening the file." << std::endl;
std::cerr << "Error: " << strerror(errno) << std::endl;
return -1;
}
while (std::getline(in, strLine))
{
vstrLines.push_back(strLine);
}
for (int i = 0; i < vstrLines.size(); ++i)
{
if (vstrLines[i].substr(0, 2) == "rr")
{
boost::split(vRRMachines, vstrLines[i], boost::is_any_of(","));
if (vRRMachines.size() < 2)
return -1;
else
vRRMachines.erase(vRRMachines.begin());
}
else if (vstrLines[i].substr(0, 2) == "rh")
{
boost::split(vRHMachines, vstrLines[i], boost::is_any_of(","));
if (vRHMachines.size() < 2)
return -1;
else
vRHMachines.erase(vRHMachines.begin());
}
else if (vstrLines[i].substr(0, 3) == "eed")
{
boost::split(vEEDMachines, vstrLines[i], boost::is_any_of(","));
if (vEEDMachines.size() < 2)
return -1;
else
vEEDMachines.erase(vEEDMachines.begin());
}
else if (vstrLines[i].substr(0, 5) == "ports")
{
boost::split(vPorts, vstrLines[i], boost::is_any_of(","));
if (vPorts.size() < 2)
return -1;
else
vPorts.erase(vPorts.begin());
}
}
// Create a vector with EED/RR and RR/RH combined addresses
vEEDRRMachines = CreateNewMachineCollection(vEEDRRMachines, vEEDMachines, vRRMachines);
vRRRHMachines = CreateNewMachineCollection(vRRRHMachines, vRRMachines, vRHMachines);
// Initialise Rssl
RsslRet rsslRet;
RsslError rsslError;
rsslRet = rsslInitialize(RSSL_LOCK_NONE, &rsslError);
if (rsslRet != RSSL_RET_SUCCESS)
return -1;
// Initialise Field Dictionary
// To prevent memory issues, we need to use "malloc" for the data dictionary in order to load RWF.dat and enumtype.def
RsslDataDictionary *rsslDataDictionary = (RsslDataDictionary*)malloc(sizeof(RsslDataDictionary));
RsslBuffer rsslBufferError;
rsslClearDataDictionary(rsslDataDictionary);
if (rsslRet = rsslLoadFieldDictionary("RWF.DAT", rsslDataDictionary, &rsslBufferError) != RSSL_RET_SUCCESS)
{
// Ensure we free the data dictionary memory when finished
free(rsslDataDictionary);
//if (iDisplayType != DISPLAY)
// std::cout << "Could not load RDM Field Dictionary file." << std::endl;
return -1;
}
// Load enum dictionary
if (rsslLoadEnumTypeDictionary("enumtype.def", rsslDataDictionary, &rsslBufferError) != RSSL_RET_SUCCESS)
{
// Ensure we free the data dictionary memory when finished
free(rsslDataDictionary);
//if (iDisplayType != DISPLAY)
// std::cout << "Could not load Enum Type Dictionary file." << std::endl;
return -1;
}
std::string strCombinedFileName;
std::vector<CRWFCapsule> vRWFCapsules;
std::vector<std::string> vstrInputFileNames;
pPcapParser = new CPCAPParser(1,1); // Initiate C++ class instance
boost::algorithm::split_regex(vstrInputFileNames, strInputFileNames, boost::regex(","));
// Let's iterate through each PCAP file and parse it.
for (int i = 0; i < vstrInputFileNames.size(); ++i)
{
if (false == strCombinedFileName.empty())
{
strCombinedFileName.append("-");
}
if (false == pPcapParser->Parse(vstrInputFileNames[i].c_str(), vRWFCapsules, vEEDRRMachines, vRRRHMachines, *rsslDataDictionary))
{
delete pPcapParser;
// Ensure we free the data dictionary memory when finished
free(rsslDataDictionary);
vRWFCapsules.clear();
return -1;
}
strCombinedFileName = strCombinedFileName.append(pPcapParser->GetFileName());
}
//if (iDisplayType != NO_DISPLAY)
// std::cout << "Clearing up..." << std::endl;
delete pPcapParser;
if (rsslRet = rsslDeleteDataDictionary(rsslDataDictionary) != RSSL_RET_SUCCESS)
{
// Ensure we free the data dictionary memory when finished
free(rsslDataDictionary);
//if (iDisplayType != NO_DISPLAY)
// std::cout << "Problem deleting dictionary." << std::endl;
return -1;
}
// Ensure we free the data dictionary memory when finished
free(rsslDataDictionary);
if (vRWFCapsules.empty())
return -1;
CMessageSorter msgSorter(vEEDMachines, vRRMachines);
std::map<std::string, SMessageInfo> m_msMessageInfo;
std::map<std::string, SSystemInfo> m_msSystemInfo = msgSorter.SortMessages(vRWFCapsules, 1, m_msMessageInfo);
if (m_msSystemInfo.empty())
return -1;
CDataVerifier dataVerifier(strCombinedFileName, 1, 1);
dataVerifier.CreateOutputForAllMessages(m_msMessageInfo);
dataVerifier.Process(m_msSystemInfo);
// When clearing the vector, we have to make sure that the destructor of the RWF message is being called... so everything destroys itself correctly.
// Will need to check if destruction is down properly. However, how can we delete RWF Capsules encapsulated in eachother?...
vRWFCapsules.clear();
}
And its appropriate header file:
// DataVerifierLib.h
#pragma once
#include "../DataVerifier/CRWFCapsule.h"
#include "../DataVerifier/ISystem.h"
#include "../DataVerifier/CFrameAnalyser.h"
#include "../DataVerifier/CPCAPParser.h"
#include "../DataVerifier/CMessageSorter.h"
#include "../DataVerifier/CDataVerifier.h"
#include "../DataVerifier/CSourceDirectoryResponse.h"
#include "../DataVerifier/CDataVerifierConstants.h"
#include <vector>
#include <fstream>
#include <sstream>
#include <stdexcept>
#include <boost/algorithm/string.hpp>
#include <msclr/marshal_cppstd.h>
using namespace System;
using namespace DataVerifier;
namespace DataVerifierLib {
public ref class PCAPParserWrapper
{
// TODO: Add your methods for this class here.
public:
// Constructor
PCAPParserWrapper();
// Wrapper Methods
bool ParseWrapper(String^ strInputFileNames);
// Fill vectors with appropriate RR/EED/RH addresses
std::vector<std::string> CreateNewMachineCollection(std::vector<std::string> vstrNewMachines, std::vector<std::string> vstrMachine1, std::vector<std::string> vstrMachine2);
// Public Variable
double initVal;
private:
CPCAPParser *pPcapParser; // an instance of class in C++
};
}
Don't know why I have received down votes for this, as the solution could be quite useful to people mixing C# and a C++/CLI wrapper.
I realized that the suspect line was actually this line:
//String^ managedStringTmp = managedString;
//std::string strInputFileNames = msclr::interop::marshal_as<std::string>(managedStringTmp);
std::string strInputFileNames = marshalString<E_UTF8>(managedString);
I've obviously changed it so that it is using this new "marshalString" function. I used a marshal string template class from the link here, as it seems to address performance issues.
http://blog.nuclex-games.com/mono-dotnet/cxx-cli-string-marshaling/
Now all I need to do is figure out why returning true from the wrapper and assigning it to a boolean in C# returns false... but hopefully this will help some people out.
UPDATE
This explains why returning false or true in the wrapper back to C# won't work, and that we either need to use marshalling of the function (didn't want to do) or return 0 for false and 1 for true.
C# DllImport with C++ boolean function not returning correctly

C#-Arduino Communication Mismatch?

I'm trying to write a program in C# to communicate with my Arduino UNO from my computer via a serial connection. At the moment I'm just writing a simple application that establishes contact with the Arduino, and then with several controls to control each pin on the arduino; either read a value from it or write a value to it.
I've managed to establish contact with the Arduino and to set pin-values, but it doesn't always want to obey my commands. I set up a few check boxes, and when I check a box, an LED should turn on, and off when I un-check it. The problem is that sometimes the LED's just stay on or off and I have to click the box a few times before it responds again, or reset my circuit...
I was trying to do some fault-finding, but couldn't get to the root of the problem: is it my app or is it the Arduino code?
Here are the relevant pieces of my code:
private void sendValue(int RW, int _Pin, int Val) //send from my app to serial port
{
if (CommPort.IsOpen)
{
CommPort.WriteLine(RW.ToString() + "," + _Pin.ToString() + "," + Val.ToString());
}
}
private void chP9_CheckedChanged(object sender, EventArgs e) //call the sendValue routine
{
if (chP9.Checked)
{
sendValue(1, 9, 255); //('Write', to pin 9, 'On')
}
else
{
sendValue(1, 9, 0); //('Write', to pin 9, 'Off')
}
}
This is my C# code, it compiles a comma-delimited string to send over the serial port to be read by the Arduino.
Here's the Arduino code:
int RW; //0 to read pin, 1 to write to pin
int PN; //Pin number to read or write
int Val; //Value to write to pin
void setup() {
Serial.begin(38400);
}
void loop() {
ReadIncoming();
ProcessIncoming();
}
void ReadIncoming()
{
if(Serial.available() > 0)
{
RW = Serial.parseInt();
PN = Serial.parseInt();
Val = Serial.parseInt();
}
while(Serial.available() > 0) //Clear the buffer if any data remains after reading
{
Serial.read();
}
}
void ProcessIncoming()
{
if(RW == 0)
{
pinMode(PN, INPUT);
}
else
{
pinMode(PN, OUTPUT);
analogWrite(PN, Val);
}
}
parseInt just takes out the first integer value it finds, stores it and throws away the comma, and does it again and again, but it seems a bit counter-intuitive.
I think my problem lies here:
while(Serial.available() > 0) //Clear the buffer if any data remains after reading
{
Serial.read();
}
I think the App is sending data faster than the Arduino code could handle, especially with this loop, but what do I do with excess data?
I don't like to use the parseInt, but it's the only way I could find to read my instructions correctly. How do I send a byte array from C# and read that array into an array in Arduino?
I've pointed out my hypotheses, and explored alternatives but couldn't get any solutions. What suggestions do you guys have for me?
It is not that clear to me why it works at all. You ought to consider a smarter way to encode the command. You need only three bytes:
private void sendValue(int RW, int _Pin, int Val) {
var cmd = new byte[] { (byte)RW, (byte)_Pin, (byte)Val };
ComPort.Write(cmd, 0, cmd.Length);
}
Then you just need to read those 3 bytes on the Arduino end:
void ReadIncoming() {
if (Serial.available() >= 3) {
RW = Serial.read();
PN = Serial.read();
Val = Serial.read();
ProcessIncoming();
}
}

Categories

Resources