I am trying to port some code from our C++ application to ensure that the licence files are compatible with both applications.
I've tried marking the functions as external, however that opened a whole other can of worms that I wouldn't like to delve into considering this is my last week at my current employer.
The C++ code I'd like to port is as follows:
std::fstream licenceFile(filePath, std::ios::in | std::ios::binary);
licenceFile.read((char *) &this->m_FileData, sizeof(this->m_FileData));
m_FileData is a struct and is as follows:
struct LicManKeyFileData
{
BYTE m_EncryptedKey[255];
WCHAR m_MacAddress[33];
WCHAR m_PreviousMacLicense[33];
WCHAR m_SoftwareName[16];
WCHAR m_ClientName[65];
BYTE m_Version;
BYTE m_EncryptionLength;
time_t m_LicenseTime;
};
I have tried several methods of replicating this in C#, firstly reading the file member by member, for example:
BinaryReader reader = new BinaryReader(licenceFileStream, Encoding.BigEndianUnicode);
licenceFileData.EncryptedKey = reader.ReadBytes(licenceFileData.EncryptedKey.Length);
byte[] mac = new byte[sizeof(char) * licenceFileData.MacAddress.Length];
mac = reader.ReadBytes(mac.Length);
Something strange I noticed about this method is that a lot of the values were being set as 204 seemingly arbitrarily, when they are read correctly in the C++ application, so I've had to add this:
if (mac[0] == 204)
mac[0] = 0;
Which makes no sense to me, it's not an alignment issue, reading from a byte before or after that gives totally garbage values (chinese characters) and this check and assigning 0 to the first index allows me to get the proper value.
Another method I've tried was found on here on StackOverflow, and is as follows:
public static T ReadStruct<T>(this BinaryReader reader) where T : struct
{
Byte[] buffer = new Byte[Marshal.SizeOf(typeof(T))];
reader.Read(buffer, 0, buffer.Length);
GCHandle handle = default(GCHandle);
try
{
handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
return (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
}
finally
{
if (handle.IsAllocated)
handle.Free();
}
}
Oddly, this method also returns some values as 204 where the C++ application reads them as the correct value.
The struct I'm using in C# looks like this:
unsafe struct LicenceFileDataS
{
internal fixed byte m_EncryptedKey[255];
internal fixed char m_MacAddress[33];
internal fixed char m_PreviousMacLicense[33];
internal fixed char m_SoftwareName[16];
internal fixed char m_ClientName[65];
internal byte m_Version;
internal byte m_EncryptionLength;
internal long m_LicenseTime;
}
Does anyone know a better method for porting this code or how I can fix the values that are being read as 204? It works perfectly in C++. My apologies for the wall of text.
Related
In our project we communicate two applications, one in C# and the other in C++, via named pipes. Our intention is to pass memory pointers between them and be able to access the objects pointed by them in either application. Our current code rises a System.AccessViolationException:
System.AccessViolationException:
Attempted to read or write protected memory. This is often an
indication that other memory is corrupt.
So far we are using a shared_ptr that points to a custom struct and writting the pointer to the buffer in C++ as seen below:
typedef struct {
int one;
int a;
int two;
int b;
} DATA_STRUCT; // C++ struct
DATA_STRUCT ds;
ds.one = 10;
ds.a = 5;
ds.two = 99;
ds.b = 0;
shared_ptr<DATA_STRUCT> ptr_ds(new DATA_STRUCT);
shared_ptr<DATA_STRUCT> p(ptr_ds);
*ptr_ds = ds;
const int size = BUFFER_SIZE;
char buf[size];
memset(buf, 0xCC, 100);
while (keepReading)
{
printf("Write message:");
scanf("%s", buf);
memcpy(buf, &p, sizeof(shared_ptr<DATA_STRUCT>));
if (strcmp(buf, "quit") == 0)
keepReading = false;
else
{
WriteFile(hPipe1, buf, dwBytesToWrite, &cbWritten, NULL);
memset(buf, 0xCC, 100);
}
}
Then, in C# we read the whole buffer, we keep the bytes with the relevant information in another buffer (Rc) and convert the byte array to our custom data structure using unsafe IntPtr as you can see below:
buffer = new byte[BUFFER_SIZE];
bytesRead = clientCSharp.stream.Read(buffer, 0, BUFFER_SIZE);
public struct DATA_STRUCT
{
public int one;
public int a;
public int two;
public int b;
}; // C# struct
unsafe
{
Buffer.BlockCopy(buffer, 0, Rc, 0, ReadLength);
DATA_STRUCT ds = new DATA_STRUCT();
IntPtr aux_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)));
IntPtr final_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)));
Marshal.Copy(Rc, 0, aux_ptr, 4);
final_ptr = (IntPtr)Marshal.PtrToStructure(aux_ptr, typeof(IntPtr));
ds = (DATA_STRUCT)Marshal.PtrToStructure(final_ptr, typeof(IntPtr));
}
The exception rises when we try to access the final_ptr in order to load the DATA_STRUCT, the last code line presented above. Here I give some Debug images:
C++ Debug image with Pointer value written to the named pipe buffer
C# Debug image with Pointer value read from the named pipe reduced buffer (Rc)
Could it be something related to the pointer length? As it seems to me in the C++ application it has 8bytes and in the C# application it has 16bytes? Dhould we declare a safe memory location for C# and C++? If yes, then how could it be done?
Note: Our goal is to work with the unsafe IntPtr in the C# application. In this example we are loading the DATA_STRUCT object because we wanted to be sure that in the C# application we are retrieving the same object passed in the C++ application. The final applications is meant to be used in Windows.
Application data spaces are completely distinct, and have been for many years. you can't simply pass a raw pointer between applications and expect to access the same memory.
The normal approach is to serialise the content of your object, squirt it through your pipe and then reconstruct the object at the receiver.
You can set up named shared memory regions, and these are faster to share large objects (in unix, and I assume in windows), but these shared regions will probably not be located at the same address, so still only good for raw data.
I have a problem with a variable type from a dll which i am importing in C#. It is written in object oriented pascal and it says it is developed with the Delphi Development Tool.
On the manual of the library it says that shortstring is a packed array of bytes. The first byte is the length and the following are exaclty 255 bytes with the string data that i need.
So after importing the dll in C# i wrote:
[return: MarshalAs(UnmanagedType.LPArray)]
Then called the function from the dll:
public static extern byte[] xxxx();
But i am getting the following error:
Cannot marshal 'return value': invalid managed/unmanaged type combination
On the other hand i tried the following:
[return: MarshalAs(UnmanagedType.SafeArray)]
This time i get the error:
SafeArray of rank 18727 has been passed to a method expecting an array of rank 1
Can you please tell me what i am doing wrong, and firstly is correct like this to get a shortstring from a compiled library?
Regards
I think the cleanest way to marshal a Delphi short string is to wrap it in a struct.
[StructLayout(LayoutKind.Sequential)]
public struct DelphiShortString
{
private byte length;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=255)]
private byte[] payload;
public string Value
{
get
{
return Encoding.Default.GetString(payload, 0, length);
}
set
{
length = (byte)Math.Min(value.Length, 255);
payload = Encoding.Default.GetBytes(value.Substring(0, length));
}
}
}
This type is not blittable and so cannot be used as a function return value. If you have control of the Delphi code, then you can ensure that you don't use short strings as function return types. However, I suspect that you don't have control of it. In which case you'd need a blittable version of the struct. Which would look like this:
[StructLayout(LayoutKind.Sequential)]
public unsafe struct DelphiShortString
{
private byte length;
private fixed byte payload[255];
public string Value
{
get
{
{
byte[] bytes = new byte[length];
fixed (byte* ptr = payload)
{
Marshal.Copy((IntPtr)ptr, bytes, 0, length);
}
return Encoding.Default.GetString(bytes, 0, length);
}
}
set
{
byte[] bytes = Encoding.Default.GetBytes(value);
length = (byte)Math.Min(bytes.Length, 255);
fixed (byte* ptr = payload)
{
Marshal.Copy(bytes, 0, (IntPtr)ptr, length);
}
}
}
}
It is indicative of poor design for a DLL to export a Delphi short string. That suggests that the author of the library has not designed it to be compatible with other compilers. Which in turn suggests that the functions may well use the default Delphi calling convention. Which is register and is not supported by Microsoft tools. If my hunch is right, then this DLL cannot be consumed directly. You would need to write an adapter DLL that exposed a more interop friendly interface.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I have a class
class DataqFmt
{
public:
unsigned short SR_number;
unsigned short SR_numerator;
unsigned char offset;
unsigned char nbytes;
short hdr_bytes;
unsigned long dat_bytes;
char dummy[1144];
};
code c++ :
afl = fopen(path, "rb");
DataqFmt dataqstr;
fread ((char*) &dataqstr, sizeof (dataqstr), 1, afl);
How can i convert this code c++ to c# . Please help me
I'm going to assume that the C++ application that wrote this file was compiled for Win32 x86 and run on Win32 x86. This allows me to make assumptions about that way that DataqFmt was arranged. If these assumptions are wrong, you can adjust them by using the various options of StructLayout and related attributes, like MarshalAs and FieldOffset.
First, we're going to use a C# structure with the same layout as DataqFmt:
[StructLayout(LayoutKind.Sequential)]
struct DataqFmtCs
{
public ushort SR_number; // assuming the C++ type unsigned short is 2 bytes
public ushort SR_numerator;
public byte offset; // assuming the C++ type unsigned char was an unsigned and 1 byte
public byte nbytes;
public short hdr_bytes; // assuming the C++ type short was 2 bytes
public uint dat_bytes; // assuming the C++ type unsigned long was 4 bytes
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1144)]
public sbyte[] dummy; // assuming the C++ type char was signed and 1 byte
}
With that structure, we now need to do file I/O to get the raw bytes.
int dataqfmtSize = Marshal.SizeOf(typeof(DataqFmtCs));
var buffer = new byte[dataqfmtSize];
using (var fs = File.OpenRead("path\\to\\the\\file")) {
int bytesRead = fs.Read(buffer, 0, buffer.Length);
if (bytesRead != buffer.Length) {
// handle this
}
DataqFmtCs someThing = GetDataqFmtFromBuffer(buffer);
}
Finally, we have the conversion routine GetDataqFmtFromBuffer.
private static DataqFmtCs GetDataqFmtFromBuffer(byte[] buffer) {
GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
try {
return (DataFmtCs)Marshal.PtrToStructure(
handle.AddrOfPinnedObject(),
typeof(DataFmtCs));
} finally {
handle.Free();
}
}
Marshal.PtrToStrucutre is doing the vast majority of the conversion work. The rest of the code is just defining the struct and doing basic .NET file I/O.
Another option--and this is often a good solution if you are working with a well-documented protocol that is platform agnostic, as you'll often need to perform endian conversions--is to write a deserialization routine that operates on a Stream using a BinaryReader. I'll leave this as an exercise for you.
If you are using visual studio you could also import the C++ code and compile it into a CLR library to be referenced by any other .net assembly. This is especially a good idea if you need the C++ code to run fast.
If you're willing to acknowledge that the C++ fread() is inherently fragile and non-portable, it might be better to write an abstraction layer to read (and write) the code data types, for example a format like this is useful:
// returns true on success, false on EOF
public static bool Read(Stream stm, out int val)
{ /* ... */ }
public static bool Read(Stream stm, out short val)
{ /* ... */ }
then you can write you code to be something like:
if (!Read(stm, out _someMember))
throw SomeException(); // or return a fail code
if (!Read(stm, out _someOtherMember))
throw SomeException();
or in the case of some of my code, I wrote a method that given an object, a stream, and the name of either a field or a property, reads the appropriate sized value and sets the member (or throws an exception if it can't find it), and then a similar method that works on an object and a collection of names (or really a variable number of string arguments, so initialization can look like this:
public static TTHorizontalHeader FromStream(Stream stm)
{
TTHorizontalHeader header = new TTHorizontalHeader();
if (!Reader.ReadType(stm, header,
"TableVersion", "Ascender", "Descender", "LineGap", "AdvanceWidthMax", "MinLeftSideBearing",
"MinRightSideBearing", "XMaxExtent", "CaretSlopeRise", "CaretSlopeRun", "CaretOffset", "Reserved0",
"Reserved1", "Reserved2", "Reserved3", "MetricDataFormat", "NumberOfHMetrics"))
return null;
return header;
}
but you say, "won't the C++ run faster since it just does one fread()?" And I reply, "Endianess, data type size, structure padding, and changes in object layout are reason enough to not keep propagating the same fragile code under the guise of performance. Any decent buffered stream is going to do only one actual read anyway and the reading work is done by an impartial robot. Besides the cost of I/O, buffered or not, will dwarf the cost of reflection and string iteration.
I want to use c# interop to call a function from a dll written in c. I have the header files.
Take a look at this:
enum CTMBeginTransactionError {
CTM_BEGIN_TRX_SUCCESS = 0,
CTM_BEGIN_TRX_ERROR_ALREADY_IN_PROGRESS,
CTM_BEGIN_TRX_ERROR_NOT_CONNECTED
};
#pragma pack(push)
#pragma pack(1)
struct CTMBeginTransactionResult {
char * szTransactionID;
enum CTMBeginTransactionError error;
};
struct CTMBeginTransactionResult ctm_begin_customer_transaction(const char * szTransactionID);
How do I call ctm_begin_customer_transaction from c#. The const char * mapps well to string, but despite various attempts (looking at stackoverflow and other sites), I fail to marshal the return structure. If I define the function to return IntPtr it works ok...
Edit
I changed the return type to IntPtr and use:
CTMBeginTransactionResult structure = (CTMBeginTransactionResult)Marshal.PtrToStructure(ptr, typeof(CTMBeginTransactionResult));
but it throws AccessViolationException
I also tried:
IntPtr ptr = Transactions.ctm_begin_customer_transaction("");
int size = 50;
byte[] byteArray = new byte[size];
Marshal.Copy(ptr, byteArray, 0, size);
string stringData = Encoding.ASCII.GetString(byteArray);
stringData == "70e3589b-2de0-4d1e-978d-55e22225be95\0\"\0\0\a\0\0\b\b?" at this point. The "70e3589b-2de0-4d1e-978d-55e22225be95" is the szTransactionID from the struct. Where is the Enum? Is it the next byte?
There's a memory management problem hidden in this struct. Who owns the C string pointer? The pinvoke marshaller will always assume that the caller owns it so it will try to release the string. And passes the pointer to CoTaskMemFree(), same function as the one called by Marshal.FreeCoTaskMem(). These functions use the COM memory allocator, the universal interop memory manager in Windows.
This rarely comes to a good end, C code does not typically use that allocator unless the programmer designed his code with interop in mind. In which case he'd never have used a struct as a return value, interop always works much less trouble-free when the caller supplies buffers.
So you cannot afford to let the marshaller do its normal duty. You must declare the return value type as IntPtr so it doesn't try to release the string. And you must marshal it yourself with Marshal.PtrToStructure().
That however still leaves the question unanswered, who owns the string? There is nothing you can do to release the string buffer, you don't have access to the allocator used in the C code. The only hope you have is that the string wasn't actually allocated on the heap. That's possible, the C program might be using string literals. You need to verify that guess. Call the function a billion times in a test program. If that doesn't explode the program then you're good. If not then only C++/CLI can solve your problem. Given the nature of the string, a "transaction ID" ought to change a lot, I'd say you do have a problem.
I hate to answer my own question, but I found the solution to marshal the resulting struct. The struct is 8 bytes long (4 bytes for the char * and 4 bytes for enum). Marshalling the string does not work automatically, but the following works:
// Native (unmanaged)
public enum CTMBeginTransactionError
{
CTM_BEGIN_TRX_SUCCESS = 0,
CTM_BEGIN_TRX_ERROR_ALREADY_IN_PROGRESS,
CTM_BEGIN_TRX_ERROR_NOT_CONNECTED
};
// Native (unmanaged)
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
internal struct CTMBeginTransactionResult
{
public IntPtr szTransactionID;
public CTMBeginTransactionError error;
};
// Managed wrapper around native struct
public class BeginTransactionResult
{
public string TransactionID;
public CTMBeginTransactionError Error;
internal BeginTransactionResult(CTMBeginTransactionResult nativeStruct)
{
// Manually marshal the string
if (nativeStruct.szTransactionID == IntPtr.Zero) this.TransactionID = "";
else this.TransactionID = Marshal.PtrToStringAnsi(nativeStruct.szTransactionID);
this.Error = nativeStruct.error;
}
}
[DllImport("libctmclient-0.dll")]
internal static extern CTMBeginTransactionResult ctm_begin_customer_transaction(string ptr);
public static BeginTransactionResult BeginCustomerTransaction(string transactionId)
{
CTMBeginTransactionResult nativeResult = Transactions.ctm_begin_customer_transaction(transactionId);
return new BeginTransactionResult(nativeResult);
}
The code works, but I still need to investigate, if calling the unmanaged code results in memory leaks.
I have a C++ DLL that interacts with a card reader. It requires a pointer to a data struct, which isn't a problem to do. However, when trying to interact with the DLL in C# I'm getting all kinds of problems. Errors writing to protected memory, the application just shutting down after executing the getData command, etc. Here's what we have.
C++ Method from header
void readCard(cardData* dataBuffer);
C# code
Wrapper.cs
public struct cardData{
Byte[] data01;
Byte[] data02;
}
[dllImport("card.dll")]
public static extern void readCard(ref cardData data);
form1.cs
Wrapper.cardData tmpData = new wrapper.cardData();
tmpData.data01 = new Byte[];
tmpData.data02 = new Byte[];
readCard(ref tmpData);
I've also tried passing cardData as an IntPtr using Marshal.StructureToPtr, which didn't return any data when I returned tried to read the ptr into a struct Marshal.PtrToStructure...
I've been trying to work this out using the help files and other posts because it seems that alot of people have trouble trying to work with C/C++ DLLs. I even tried to write the whole thing in C++ and have it return a string with the data parsed in the C++ DLL but that throws a reading/writing to protected memory error
The biggest problem I see with your code is that you have not given your byte[] members an explicit size. Without this size operator, the marshaller will treat them just like a simple reference type. The resulting struct will have a size of 8 bytes on a 32 bit platform and will almost certainly lead to writing of protected memory.
Assuming the byte arrays are of a fixed size in the C code, you should use the MarshalAs attribute to give the byte arrays the same semantics in managed code. This does entail giving them a fixed size.
[StructLayout(LayoutKind.Sequential)]
public struct cardData{
[MarshalAs(UnmanagedType.ByValArray, SizeConst=300)]
Byte[] data01;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=300)]
Byte[] data02;
}
Change 300 to be whatever size is specified in the native code for the array.
Also you should add the StructLayout attribute as well.
Maybe your cardData needs to use the StructLayoutAttribute. Also you can use Dependency Walker to find the location in card.dll for that method, and add that as a named parameter.
I noticed that your Byte[] have no size associated with them. Do you know what size the arrays are supposed to be? IIRC, the space for the arrays needs to allocated when they're initialized.
If I'm way off base, let me know and I'll delete this post.
The PInvoke Signature Toolkit has helped me in the past.
For example the following C/C++:
struct cardData{
byte[] data01;
byte[] data02;
}
void readCard(cardData* dataBuffer);
It has:
System.Runtime.InteropServices.StructLayoutAttribute( System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct cardData {
/// byte[]
public byte[] data01;
/// byte[]
public byte[] data02;
}
/// Return Type: cardData
///dataBuffer: cardData*
public delegate cardData readCard(ref cardData dataBuffer);
Here's a snippet of a C-DLL wrapper in C# that I've made.
Like Yuriy mentioned, you're missing a StructLayout attribute, and you probably ought to be using native types in your struct and your function declaration. This will probably require you to use the unsafe keyword in a few places, which may or may not be acceptable to you - but it was fine for me.
[StructLayout(LayoutKind.Sequential)]
public unsafe struct X_Message
{
public byte id;
public byte* data;
public DWORD data_length;
}
// ...
[DllImport("x-driver.dll")]
protected unsafe static extern int X_ReadMessage(void* h, X_Message* message);
Ok. So the struct has been set as suggested with the struct layout.
Wrapper.cs
[StructLayout(LayoutKind.Sequential)]
public struct cardData{
[MarshalAs(UnmanagedType.ByValArray, SizeConst=99)]
Byte[] data01;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=101)]
Byte[] data02;
}
[DllImport("card.Dll")]
public static extern void readCard(ref cardData data);
And now it just closes... No errors, no change in data, the app just shuts down.
Use IntPtr instead of byte[]. Your DLL can't handle managed data.