Is it possible to force a string to be a specific size when defining a struct?

I am marshalling data between a C# and C++ application. In the C# application, I force the size of a string to be some size (say, 256 bytes). I would like to read in that exact same amount in C++ (I will be recreating the structs with reinterpret_cast) so that the data will remain formatted as it was in the C# application. Unfortunately, I'm pretty rusty with C++ and I'm not sure how to force a string's size in a struct in C++.

As requested, an example. I have a struct in C# that looks like this:

[StructLayout(LayoutKind.Sequential)] public struct DataLocater { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string filename; [MarshalAs(UnmanagedType.I4)] public Int32 sizeOfData; public Int32 startLocation; public Int32 encrypted; }

Which I am marshalling several of (along with other data) to a data file. The C++ file is then reading this file in and I will be parsing it back into struct in C++ with the same structure. My first attempt at this struct looked like:

struct DataLocater { std::string filename; int sizeOfData; int startLocation; int encrypted; };

But there is no way for the compiler to know that I want that std::string to be 256 bytes.

edit: adding full header file for example.

#pragma once #include "CoreArea/Singleton.h" class FileReader : public Singleton<FileReader> { friend class Singleton<FileReader>; public: void* GetFileData(std::wstring fileName, int &size); private: FileReader(); ~FileReader(); struct Header { std::string somestring; int numOfFiles; }; struct DataLocater { char[256] filename; int sizeOfData; int startLocation; int encrypted; }; };

-------------Problems Reply------------

In general you're taking the wrong approach here. Mixing non-data only C++ types and PInvoke will lead you to a lot of pain. Types like std::string should not be used in this scenario because the marshaller cannot correctly create them at runtime.

Instead you need to use more primitive types. In this particular scenario, based on the managed signature, the appropriate C struct is the following

struct DataLocater
{
char filename[256];
int sizeOfData;
int startLocation;
int encrypted;
};

Is this what you are looking for?

struct DataLocater
{
char filename[256];
int sizeOfData;
int startLocation;
int encrypted;
};

edit: Consider that you don't NEED to force either string to be of a certain size, you could declare filename as char * and on the C# size you'd use a string with no restrictions. This way you'd only use as much memory as needed (and possibly use more than you initially estimated, avoiding buffer overrun errors).

You can't marshal C# arrays directly into a std::string. The string class has a whole bunch of other stuff in its memory space besides the raw character data: vtable pointer, length specifier, probably a bunch of other stuff too.

You need to specify the filename parameter as a wchar[256], and then later convert the wchar[256] into a std::string.

A std::string isn't fixed length, and typically doesn't store its data in its allocated space but in the heap. You want a fixed length array of characters or bytes, depending on the structure's charset.

Pruning the examples on MSDN for ByValTStr use gives these three:

// C
struct StringInfoA {
char f2[256];
};
struct StringInfoW {
WCHAR f2[256];
};
struct StringInfoT {
TCHAR f2[256];
};

Which correspond to

// C#
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
struct StringInfoA {
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] public String f2;
}

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
struct StringInfoW {
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] public String f2;
}

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
struct StringInfoT {
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] public String f2;
}

Category:c# Views:0 Time:2009-10-05

Related post

Copyright (C) dskims.com, All Rights Reserved.

processed in 0.135 (s). 11 q(s)