2009-08-21 15 views
16

Mam następujący C definicja ++ funkcja, której staram się wywołać poprzez PInvoke od kodu zarządzanego:Prawidłowy sposób na dowódcę SIZE_T *?

bool FooBar(SIZE_T* arg1); 

Moja udało deklaracja wyglądała następująco:

[DllImport("mydll", SetLastError=true, CharSet=CharSet.Unicode)] 
private static extern bool FooBar(ref uint arg1); 

Niektórzy z was mogą zauważyć takie same W końcu to robiłem. To nie jest 64-bitowy przenośny. SIZE_T ma zmienną wielkość (32-64 bitów), podobnie jak wskaźnik do niego. Na zarządzanym rozmiarze wskaźnik poprawnie przekłada się na 64-bitowy, ale uint tego nie robi i możesz skończyć z kosza w górnych bitach arg1. Było to szczególnie uporczywy błąd od śmieci było często tylko zer :(

Jedynym rozwiązaniem Dostałem do pracy jest następujący udało deklaracja:

[DllImport("mydll", SetLastError=true, CharSet=CharSet.Unicode)] 
private static extern bool FooBar(ref IntPtr arg1); 

Działa to oczywiście dlatego IntPtr można zmieniać jego rozmiar W moim kodzie właśnie traktuję IntPtr jako liczbę całkowitą, i działa, chociaż wygląda na brzydkie hack.Myślę, że powinien być jakiś sposób, aby określić to poprawnie, być może za pomocą UnmanagedType.SysUInt, ale byłem nie można znaleźć innego działającego rozwiązania:

Odpowiedz

19

Używanie IntPtr i/lub UIntPtrjest robi to właściwie - typy są tam specjalnie do tego celu! Nie rozumiem, dlaczego uważasz to za "brzydkie włamanie". Nie jestem również pewny, jaka byłaby proponowana przez ciebie alternatywa - każdy rodzaj atrybutu umożliwiający mapowanie wartości do uint byłby z natury błędny, ponieważ C# uint ma 32-bitową pewność, niezależnie od architektury, i tak na 64- bitową platformę, aby poprawnie ją obsłużyć, musiałaby przyciąć połowę, tracąc dane i prawdopodobnie powodując, że wynik byłby bezużyteczny.

+1

Uważam to za brzydkie hackowanie, ponieważ IntPtr powinien reprezentować wskaźnik na coś. Po prostu traktuję to bezpośrednio jako liczbę całkowitą. SysUInt w szczególności stwierdza, że ​​jest to reprezentacja rozmiaru zmiennego uint. Dokładnie to, czego chcę, z wyjątkiem tego, że nie potrafię wymyślić, jak poprawnie go sformułować jako wskaźnika SysUInt, a nie SysUInt. – sooniln

+0

Używasz wskaźnika do SIZE_T jako argumentu, Soonil. IntPtr wygląda bardzo dobrze –

+0

Zauważysz, że nie używam IntPtr, ale używam ref IntPtr. – sooniln

12

UIntPtr to poprawny typ do użycia.

size_t to niepodpisana liczba całkowita o wielkości wskaźnika i właśnie to oznacza UIntPtr. "Ptr" w nazwie może być nieco mylące, zgadzam się. Nie oznacza to w rzeczywistości "jest to wskaźnik", to znaczy "jest to o rozmiarze" o rozmiarze całkowitym ". Tak więc twoja deklaracja byłaby:

[DllImport("mydll", SetLastError=true, CharSet=CharSet.Unicode)] 
private static extern bool FooBar(ref UIntPtr arg1); 
+0

Ah bardzo dobrze wtedy :) Nie byłby pierwszym źle nazwanym API, heh. – sooniln

+0

Właściwie to rodzaj wspólnej nazwy dla tego rodzaju. typedefs 'INT_PTR' i' UINT_PTR' .I ISO C99 ma 'intptr_t' i' uintptr_t' w ''. Chociaż może to być mylące, jest to obecnie tradycyjne. –

Powiązane problemy