.NET 4.x Маршаллинг между C#-exe и С++-dll
Формулировка задачи:
Приветствую.
Имеется такой код (C#, exe), который обращается к C++ дллке (не /clr!), перекидывает ей структуру, чтобы та в свою очередь заполнила эту структуру данными и вернула её соответственно обратно в C# exe:
После того, как было добавлено (Это стало продуцировать на этой строке:
...вот такую ошибку: Marshal.SizeOf - cannot be marshaled as an unmanaged structure…
Укажите пожалуйста, что не делаю не так в этой ситуации? :-\
Наверное многое, ибо всего 3-4 месяца изучаю C# с С++, так что не пинайте сильно пжалста
И просто для референса, на стороне С++ структуры выглядят так:
И потом в С++ной части в функции dll_TorrentGetInfo я вызываю функцию для копирования в структуру которая потом возвращается в C#:
/// <summary>
/// Represent info about particular file within a .torrent file.
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct TorrentInfoType_FilesList
{
// Full file path within a .torrent
[MarshalAs(UnmanagedType.LPWStr)]
public string filepath;
// Filename of a file within a .torrent
[MarshalAs(UnmanagedType.LPWStr)]
public string filename;
// Filesize of a file within a .torrent
public Int64 filesize;
}
/// <summary>
/// Represent general information about a .torrent file.
/// </summary>
/// <see cref="DLL->TorrentInfo.cpp/h"/>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct TorrentInfoType
{
// Is torrent valid?
[MarshalAs(UnmanagedType.U1)]
public bool IsValid;
// Torrent name/title.
[MarshalAs(UnmanagedType.LPWStr)]
public string name;
// Torrent sha1 hash.
[MarshalAs(UnmanagedType.LPWStr)]
public string hash;
// Torrent creation date
public Int64 creationDate;
// Torrent creator (usually, software дшлу uTorrent/3310)
[MarshalAs(UnmanagedType.LPWStr)]
public string creator;
// Torrent author's comment.
[MarshalAs(UnmanagedType.LPWStr)]
public string comment;
// Is torrent private?
[MarshalAs(UnmanagedType.U1)]
public bool IsPrivate;
// Total number of bytes the torrent-file represents (all the files in it).
public Int64 totalSize;
// Files in torrent.
public int filesCount;
public int pieceLength;
public int piecesCount;
// Files list in .torrent
[MarshalAs(UnmanagedType.LPArray)]
public TorrentInfoType_FilesList[] files;
}
[DllImport(Globals.WRAPPER_DLL, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]
private static extern TORRENT_ERROR dll_TorrentGetInfo(string filepath, IntPtr infoStruct);
...
/// <summary>
/// Retrieves .torrent information (creator, comment, files count and so on)
/// </summary>
/// <param name="filepath">full path to .torrent file (ex. C:\torr.torrent)</param>
/// <returns></returns>
public static bool GetTorrentInfo(string filepath, out TorrentInfoType info)
{
// Init structure with default values.
info = new TorrentInfoType()
{
IsValid = false,
name = "Unknown",
hash = "",
creationDate = 0,
creator = "Unknown creator",
comment = "",
IsPrivate = false,
totalSize = 0,
filesCount = 0,
pieceLength = 0,
piecesCount = 0,
files = new TorrentInfoType_FilesList[]
{
}
};
// Is .torrent exists?
if (!File.Exists(filepath))
{
AppCore.ShowErr(
String.Format(AppCore.LS("Error.FileNotExists"), filepath)
);
return false;
}
// Allocate structure to be ready marshalled in/out DLL.
int tempSize = Marshal.SizeOf(typeof(TorrentInfoType));
IntPtr pInfo = Marshal.AllocHGlobal(tempSize);
Marshal.StructureToPtr(info, pInfo, false);
// Query info.
var err = dll_TorrentGetInfo(filepath, pInfo);
if (err == TORRENT_ERROR.TE_INFO_INVALIDTORRENT)
{
Marshal.FreeHGlobal(pInfo);
return false;
}
// Update info structure with received data.
info = (TorrentInfoType)(Marshal.PtrToStructure(pInfo, typeof(TorrentInfoType)));
// Free memory.
Marshal.FreeHGlobal(pInfo);
DumpTorrentInfoData(info);
return true;
}так как появилась необходимость получить список файлов в торренте и отдать его вместе с базовыми данными по нему, которые уже и так возвращаются нормально
) в C# TorrentInfoType структуру вот этот кусок (и в С++ часть свой аналог - std::vector<TorrentInfoType_FilesLi st>... - соответственно тоже
):// Files list in .torrent [MarshalAs(UnmanagedType.LPArray)] public TorrentInfoType_FilesList[] files;
int tempSize = Marshal.SizeOf(typeof(TorrentInfoType));
struct TorrentInfoType_FilesList
{
wchar_t* filepath;
wchar_t* filename;
long long filesize;
};
struct TorrentInfoType
{
bool IsValid;
wchar_t* name;
wchar_t* hash;
long long creationDate;
wchar_t* creator;
wchar_t* comment;
bool IsPrivate;
long long totalSize;
int filesCount;
int pieceLength;
int piecesCount;
std::vector<TorrentInfoType_FilesList> files;
};void TorrentInfo::CopyInfo(TorrentInfoType* dest) const
{
dest->IsValid = IsValid();
dest->name = _wcsdup(GetNameW().c_str());
dest->hash = _wcsdup(GetHashW().c_str());
dest->creationDate = GetCreationDate();
dest->creator = _wcsdup(GetCreatorW().c_str());
dest->comment = _wcsdup(GetCommentW().c_str());
dest->IsPrivate = IsPrivate();
dest->totalSize = GetTotalSize();
dest->filesCount = GetFilesCount();
dest->pieceLength = GetPieceLength();
dest->piecesCount = GetPiecesCount();
// TODO: Fill files list.
// ...
}Решение задачи: «.NET 4.x Маршаллинг между C#-exe и С++-dll»
textual
Листинг программы
info = new TorrentInfoType(); ......................................... ............................................. // Update info structure with received data. info = (TorrentInfoType)(Marshal.PtrToStructure(pInfo, typeof(TorrentInfoType)));