Я вызываю родную DLL из F #. Это оказалось довольно просто для функций, которые не принимают аргументов или используют только базовые c типы, но у меня много проблем с тем, чтобы заставить мой код работать в противном случае.
Код C ++:
struct CatDef
{
uint8_t cat;
uint8_t arrogance;
CatDef() : cat(0), arrogance(0) {}
};
struct HomeInfo
{
enum { MAX_CATDEF = 5 };
enum {
LONE_CAT = 0x01,
};
CatDef cd[MAX_CATDEF];
uint8_t notoriety;
uint8_t etc;
HomeInfo()
: notoriety(0), etc(0)
{
memset(cd, 0, sizeof(cd));
}
size_t howBig() const
{
size_t hb = 0;
for (; hb < MAX_CATDEF; ++hb)
if (!cd[hb].cat)
break;
return hb;
}
};
struct HomeQuery
{
char addr[ADDR_LENGTH]; // ADDR_LENGTH is 1024
char verifiedAddr[ADDR_LENGTH];
HomeInfo homeData;
unsigned int id;
Status st; // Status is an enum
HomeQuery()
: homeData()
, id(0)
, st(Unprocessed)
{
memset(addr, 0, sizeof(addr));
memset(verifiedAddr, 0, sizeof(verifiedAddr));
}
};
__declspec(dllexport) bool GetHomeInfo(
HomeQuery* queries, size_t qCount, void (*callback)(HomeQuery*, size_t) = 0);
Пока что у меня есть это для F #:
[<Struct>]
type CatDef =
[<DefaultValue>]
val mutable cat : uint8
[<DefaultValue>]
val mutable arrogance : uint8
[<Struct>]
type HomeInfo =
[<DefaultValue; MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)>]
val mutable cd : CatDef array
[<DefaultValue>]
val mutable notoriety : uint8
[<DefaultValue>]
val mutable etc : uint8
[<Struct>]
type HomeQuery =
[<DefaultValue; MarshalAs(UnmanagedType.LPStr, SizeConst = 1024)>]
val mutable addr : string
[<DefaultValue; MarshalAs(UnmanagedType.LPStr, SizeConst = 1024)>]
val mutable verifiedAddr : string
[<DefaultValue>]
val mutable homeData : HomeInfo
[<DefaultValue>]
val mutable id : uint32
[<DefaultValue>]
val mutable st : int
type HomeQueryCallback = delegate of (HomeQuery array * uint) -> unit
module private Wrapper =
[<DllImport(
"Homes.dll",
EntryPoint = "?GetHomeInfo@People@@NA_WBYUHomeQuery@1@IP6AX0I@Z@Z",
CallingConvention = CallingConvention.Cdecl)>]
extern bool GetHomeInfo(HomeQuery[] queries, uint qCount, HomeQueryCallback callback)
[<RequireQualifiedAccess>]
module HomeLib =
let getHomeInfo queries = Wrapper.GetHomeInfo (queries, uint queries.Length, null)
Для правил маршалинга типов я имел в виду https://docs.microsoft.com/en-us/dotnet/standard/native-interop/type-marshaling#default -rules-for-marshaling-common-types .
Когда я вызываю HomeLib.getHomeInfo
и захожу в собственную библиотеку (Homes.dll), я вижу, что поля первого (и единственного) элемента в массиве HomeQuery
содержат искаженную информацию. (qCount
и callback
не повреждены и содержат ожидаемые значения.) Как видите, я пробовал добавить атрибуты MarshalAs
в несколько полей, но это не дало положительного эффекта. Ни один из типов не украшает [<StructLayout(LayoutKind.Sequential)>]
.