PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Portierung zweier Structs von C++ nach C#


minos5000
2008-09-02, 17:09:50
Hi,

ich benötige für ein C# Programm zugriff auf eine unmanaged DLL und habe nun das Problem, dass sich die Anwendung beim Aufruf der aus der DLL importierten Funktion aufhängt. Ich habe die Theorie, dass die DLL Probleme hat mit der Referenz die ich beim Aufruf übergebe.

Ich habe bisher noch nie was mit Marshalling gemacht und wollte die Profis hier bitten sich meine C# Structs mal anzusehen, ob darin ein Fehler ist.

Die Originalstructs aus den zur DLL gehörigen Headerdateien und der Aufruf der Funktion sehen so aus:

struct SWI_STRUCT_ApiStartup
{
unsigned long sizeStruct;
SWI_STRUCT_Logging sLogging;
};

struct SWI_STRUCT_Logging
{
unsgined long sizeStruct;
TCHAR szFileName[LENGTH_LogFileName];
bool bEnable;
};

SWI_API SWI_RCODE SwiApiStartup(SWI_STRUCT_ApiStartup *pOpenParams);


Und hier meine Versuche, das ganze unter C# zum laufen zu bekommen:

[StructLayout(LayoutKind.Sequential)]
public struct SWI_STRUCT_ApiStartup
{
[MarshalAs(UnmanagedType.U4)]
public UInt32 sizeStruct;
public SWI_STRUCT_Logging sLogging;
}

[StructLayout(LayoutKind.Sequential)]
public struct SWI_STRUCT_Logging
{
[MarshalAs(UnmanagedType.U4)]
public UInt32 sizeStruct;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public byte[] szFileName;
public bool enabled;
}

public enum SWI_TYPE_Device{...}

[DllImport(@"c:\\SwiApiInterface.dll")]
public static extern SWI_RCODE SwiApiStartup(ref SWI_STRUCT_ApiStartup sOpenParams);



Besten Dank
minos

robobimbo
2008-09-02, 21:41:25
Also ich hab mir aus dem Netz für die Einbindung der wininet.dll unter C# folgenden Code gezogen:

zuerst das

using System.Runtime.InteropServices;


dann die definition des structs:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct INTERNET_CACHE_ENTRY_INFO
{
public int dwStructSize;
[MarshalAs(UnmanagedType.LPTStr)]
public String lpszSourceUrlName;
[MarshalAs(UnmanagedType.LPTStr)]
public String lpszLocalFileName;
public int CacheEntryType;
public int dwUseCount;
public int dwHitRate;
public int dwSizeLow;
public int dwSizeHigh;
public System.Runtime.InteropServices.ComTypes.FILETIME LastModifiedTime;
public System.Runtime.InteropServices.ComTypes.FILETIME ExpireTime;
public System.Runtime.InteropServices.ComTypes.FILETIME LastAccessTime;
public System.Runtime.InteropServices.ComTypes.FILETIME LastSyncTime;
public IntPtr lpHeaderInfo;
public int dwHeaderInfoSize;
public IntPtr lpszFileExtension;
public int dwExemptDelta;
}


Und ein exemplarischer Aufruf:
NativeMethods.FindFirstUrlCacheEntry(null, IntPtr.Zero, ref neededBytes);
if (Marshal.GetLastWin32Error() == ERROR_NO_MORE_ITEMS)
{
// nothing to do
return;
}

Funktioniert so wunderbar

minos5000
2008-09-03, 09:27:36
Gegoogelt hab ich auch schon, aber nichts gefunden, was ich 1:1 für meinen Fall übernehmen kann.

Z.B. ist mir nicht klar, ob ich das "unsigned long" überhaupt marshallen muss. Das Byte-Array dagegen sicherlich, aber ich weiß nicht, ob ich die Größe 1:1 aus C++ übernehmen darf. Ich hatte mal was gelesen, dass sich die Größen von Datenstrukturen zwischen den beiden Sprachen unterscheiden können.

Novox
2008-09-03, 10:47:41
Hm, TCHAR ist doch 16 Bit breit, soweit ich weiß (UTF-16?). In dem Fall müsstest Du in C# in char[] verwenden (in C# ist ein char ein UTF-16-Zeichen).

Fixed-Size-Buffers kann man in C# 2.0 übrigens mit dem fixed-Keyword definieren, z.B.

unsafe struct MyStruct
{
public fixed char myBuffer[128];
}