.NET 4.x Маршаллинг между C#-exe и С++-dll

Узнай цену своей работы

Формулировка задачи:

Приветствую. Имеется такой код (C#, exe), который обращается к C++ дллке (не /clr!), перекидывает ей структуру, чтобы та в свою очередь заполнила эту структуру данными и вернула её соответственно обратно в C# exe:
        /// <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));
...вот такую ошибку: Marshal.SizeOf - cannot be marshaled as an unmanaged structure… Укажите пожалуйста, что не делаю не так в этой ситуации? :-\ Наверное многое, ибо всего 3-4 месяца изучаю C# с С++, так что не пинайте сильно пжалста И просто для референса, на стороне С++ структуры выглядят так:
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;
};
И потом в С++ной части в функции dll_TorrentGetInfo я вызываю функцию для копирования в структуру которая потом возвращается в C#:
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)));

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

14   голосов , оценка 4.286 из 5
Похожие ответы