C++ DLL in C# einbinden, Probleme mit der Übergabe von Strukturen



  • Hallo

    ich hab eine C++ Dll, in der sich Funktionen befinden, die Strukturen als Parameter erwarten. Ich hab diese Strukturen in C# möglichst exact nachgebaut, aber es funktioniert trotzdem nicht richtig.

    ich hab mal einen kleinen Beispiel Code geschrieben:

    die DLL

    // testDLL.cpp : Defines the entry point for the DLL application.
    //
    
    #include "stdafx.h"
    
    #ifdef _MANAGED
    #pragma managed(push, off)
    #endif
    #define DLLDIR __declspec(dllexport) 
    
    struct content
    {
    TCHAR* sth;
    int number;
    };
    
    extern "C"
    {
    BOOL APIENTRY DllMain( HMODULE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
    					 )
    {
        return TRUE;
    }
    
    int DLLDIR init(int id,int* retCount, content** con,int** arr)
    {
    	int i = id%3;
    	if(i==0) return 1;
    	*con = new content[i];
    	*arr = new int[5];
    	for(int i=0;i<5;i++)
    	{
    	(*arr)[i]=i;
    
    	}
    	for(int n=0;n<i;n++)
    	{
    		(*con)[n].sth = _T("Hallo");
    		(*con)[n].number= n;
    	}
    	*retCount = i;
    	return 0;
    }
    
    }
    #ifdef _MANAGED
    #pragma managed(pop)
    #endif
    

    C# programm

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    
    namespace testapp
    {
    
        public partial class Form1 : Form
        {
    
            public Form1()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                // test funktion
                int retCount;
                int ret;
                int[] arr = new int[5];
                content[] con;
                ret = wrapper.init(4, out retCount, out con,out arr);
                foreach (content c in con)
                {
                    MessageBox.Show(c.sth);
                }
                foreach (int i in arr)
                {
    
                    MessageBox.Show(i.ToString());
                }
                MessageBox.Show(con.Length.ToString());
                MessageBox.Show(retCount.ToString());
            }
        }
         public class wrapper
        {
             [DllImport("testDLL.dll", CharSet = CharSet.Unicode)]
             public static extern int init(int id, out int retCount, out content[] Content, out int[] arr);
    
        }
    
        public struct content
        {
            public String sth;
            public int number;
        }
    
    }
    

    leider werden die Strukturen nicht korrekt übergeben.
    Hat jemand Rat für mich?

    mfg walljumper



  • Ich vermute jetzt mal, dass das 'out Content[]' nicht stimmt, denn das müsste einem 'content**' in C entsprechen. Lass mal das 'out' weg, das sollte dann eigentlich klappen.

    /EDIT: Na gut, ich habe mir jetzt mal den Inhalt der Funktion angeschaut; Du willst anscheinend wirklich einen 'out'-Parameter, also änder den Parametertypen von 'content*' zu 'content**'.



  • danke schonmal, aber leider funktioniert es noch immer nicht.

    ich hab das selbe auch mal mit einem ganz normalen int probiert, das funktioniert auch nicht 😞

    ich passe den code im Einleitungspost mal an.



  • Das kann so meines Erachtens nach auch nicht funktionieren.
    1. Deine C Struktur weist nur einen Zeiger auf eine Zeichenkette auf
    2. In deiner C# Struktur ist nichts von unmanaged Code zu erkennen
    3. Woher soll das System wissen, wieviel Speicher der Zeichenkette zur Verfügung steht (weder in der C-Struktur - hier nur ein Zeiger vorhanden - noch in der C#-Struktur ersichtlich), noch um welche Art es sich handelt
    Wenn du mit CharSet.Unicode 'arbeitest', solltest die DLL auch Unicode sein, sonst musst du in deiner C Struktur WCHAR verwenden.

    die C-Struktur könnte dann folgendermaßen aussehen:

    struct content
    {
    	WCHAR sth[128];
    	int number;
    };
    

    C# Struktur

    [StructLayout(LayoutKind.Sequential)]
    public struct content
    {
    	[MarshalAs(UnmanagedType.LPWStr)]
    	public string sth;
    	public int number;
    };
    

    Sieh dir dazu auch noch mal in der MSDN das Thema zu UnmanagedType an.
    Kann allerdings nicht garantieren, ob das so funktioniert (nicht getestet).



  • Analog Bit schrieb:

    C# Struktur

    [StructLayout(LayoutKind.Sequential)]
    public struct content
    {
    	[MarshalAs(UnmanagedType.LPWStr)]
    	public string sth;
    	public int number;
    };
    

    Also, 'LayoutKind.Sequential' ist seit C# 2.0 Standard, muss also nicht unbedingt explizit angegeben werden. Beim String sollte man sich evtl. überlegen, einfach einen 'StringBuilder' zu übergeben, der Speicher vorreserviert hat ('Capacity' gesetzt) und dann die Kapazität ebenfalls zu übergeben.



  • habs leider noch immer nicht hinbekommen, ich versuche jetzt das Problem zu umgehen indem ich einen COM-Server dafür schreibe.

    http://www.c-plusplus.net/forum/viewtopic-var-p-is-1340754.html#1340754


Anmelden zum Antworten