Сложный Marshalling DirectX массив структур из C ++ в C #

Цель: Marshal C ++ (указатель на?) Массив структур на C #.

C ++: CreateVertexDeclaration ()

   HRESULT CreateVertexDeclaration(
[in]           const D3DVERTEXELEMENT9 *pVertexElements,
[out, retval]  IDirect3DVertexDeclaration9 **ppDecl
);

C #:

я использую этот определить D3DVERTEXELEMENT9 состав. SharpDX — это управляемая библиотека DirectX генерируется непосредственно из заголовков DirectX SDK C ++, так что он предположительно вполне совместим для COM-взаимодействия. На самом деле у меня уже есть 10 других хуков, которые работают отлично, но это первый с указателем на массив структур.

На случай, если определение структуры SharpDX не работает, я также попытался заменить его своим собственным определением:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class D3DVERTEXELEMENT9
{
public short Stream;
public short Offset;
public DeclarationType Type;      // Enum
public DeclarationMethod Method;  // Enum
public DeclarationUsage Usage;    // Enum
public byte UsageIndex;
}

Я пробовал следующие сигнатуры метода C #:

Примечание: наличие IntPtr devicePointer в качестве первого параметра не должно быть проблемы. У меня есть еще 10 крючков, которые успешно работают.

Примечание. Это хуки Direct3D API. Таким образом, моя программа передает данные, которые мне нужны, чтобы собрать из неуправляемой среды C ++ в управляемую среду C #.

1:

CreateVertexDeclaration(IntPtr devicePointer, D3DVERTEXELEMENT9[] vertexElements, out IntPtr vertexDeclaration)

Результат: массив имеет один элемент, но его значения по умолчанию (не имеет смысла). Это означает, что short Stream, short Offset, Type, Method, Usage, а также UsageIndex все 0 (перечисления принимают свое первое значение).

2:

CreateVertexDeclaration(IntPtr devicePointer, ref D3DVERTEXELEMENT9[] vertexElements, out IntPtr vertexDeclaration)

Результат: сам массив является нулевым.

3:

CreateVertexDeclaration(IntPtr devicePointer, [In, Out] D3DVERTEXELEMENT9[] vertexElements, out IntPtr vertexDeclaration)

То же, что и 1. Никакой выгоды.

4:

CreateVertexDeclaration(IntPtr devicePointer, D3DVERTEXELEMENT9 vertexElements, out IntPtr vertexDeclaration)

То же, что 1, ничего не меняет. Я получаю дефолтную структуру. То же самое, если бы я позвонил new D3DVERTEXELEMENT9(),

5:

CreateVertexDeclaration(IntPtr devicePointer, ref D3DVERTEXELEMENT9 vertexElements, out IntPtr vertexDeclaration)

Я забыл результат, но он не сработал. Я думаю, что это на самом деле разбил крючки.

6:

CreateVertexDeclaration(IntPtr devicePointer, IntPtr vertexElements, out IntPtr vertexDeclaration)

Я думаю, что это # ​​6 или # 1 / # 2 должны быть правильными. Я, наверное, испортил реализацию этого метода?

Я пытался использовать этот код с ним:

var vertex = (D3DVERTEXELEMENT9)Marshal.PtrToStructure(vertexElements, typeof(D3DVERTEXELEMENT9));

Но это не работает! Это так же, как # 1. Мой маршаллированный указатель на структуру является структурой по умолчанию, так же, как если бы я звонил new D3DVERTEXELEMENT9(),

7:

CreateVertexDeclaration(IntPtr devicePointer, ref IntPtr vertexElements, out IntPtr vertexDeclaration)

Ноль или ноль; недействительный.


Для метода № 6 (с использованием IntPtr) я попытался просмотреть область памяти в Visual Studio. Следующие 50 байтов или около того были все нули. Был, может быть, один 2 байт в поле 50 нулей. Но это были почти 49 байтов нулей, начиная с IntPtr, предоставленного методу.

Разве это не проблема? Не означает ли это, что указанный указатель уже неверен? Поэтому я понял, что у меня неправильная подпись метода. Проблема в том, что я пробовал всевозможные комбинации, и они либо приводили к сбою программы, либо давали мне массив по умолчанию, такой же, как если бы я звонил new D3DVERTEXELEMENT9(),

Вопрос: Как правильно распознать pVertexElements массив структур из C ++ в C #, и почему мои текущие подписи неверны?

Дополнительное примечание: в C ++ длина этого конкретного массива определяется суффикс D3DDECL_END. Я понятия не имею, как я должен получить соответствующую длину массива в C # без какого-либо переданного параметра длины.


Другие рабочие крючки:

C ++:

BeginScene(LPDIRECT3DDEVICE9 pDevice)
BeginStateBlock(LPDIRECT3DDEVICE9 pDevice)
Clear(LPDIRECT3DDEVICE9 pDevice, DWORD Count,CONST D3DRECT* pRects,DWORD Flags,D3DCOLOR Color,float Z,DWORD Stencil)
ColorFill(LPDIRECT3DDEVICE9 pDevice, IDirect3DSurface9* pSurface,CONST RECT* pRect,D3DCOLOR color)
CreateAdditionalSwapChain(LPDIRECT3DDEVICE9 pDevice, D3DPRESENT_PARAMETERS* pPresentationParameters,IDirect3DSwapChain9** pSwapChain)
CreateCubeTexture(LPDIRECT3DDEVICE9 pDevice, UINT EdgeLength,UINT Levels,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DCubeTexture9** ppCubeTexture,HANDLE* pSharedHandle)

C #:

Примечание: я использую перечисления и структуры SharpDX для всех этих делегатов, и они работают нормально. Они также все начинаются с IntPtr devicePointer,

BeginSceneDelegate(IntPtr devicePointer);
BeginStateBlocKDelegate(IntPtr devicePointer);
ClearDelegate(IntPtr devicePointer, int count, IntPtr rects, ClearFlags flags, ColorBGRA color, float z, int stencil);
ColorFillDelegate(IntPtr devicePointer, IntPtr surface, IntPtr rect, ColorBGRA color);
CreateAdditionalSwapChainDelegate(IntPtr devicePointer, [In, Out] PresentParameters presentParameters, out SwapChain swapChain);
CreateCubeTextureDelegate(IntPtr devicePointer, int edgeLength, int levels, Usage usage, Format format, Pool pool, out IntPtr cubeTexture, IntPtr sharedHandle);
...

Журнал переданных параметров для других хуков:

DLL injection suceeded.
Setting up Direct3D 9 hooks...
Activating Direct3D 9 hooks...
CreateDepthStencilSurface(IntPtr devicePointer: 147414976, Int32 width: 1346, Int32 height: 827, Format format: D24S8, MultisampleType multiSampleType: None, Int32 multiSampleQuality: 0, Boolean discard: False, IntPtr& surface: (out), IntPtr sharedHandle: 0)
CreateDepthStencilSurface(IntPtr devicePointer: 147414976, Int32 width: 1346, Int32 height: 827, Format format: D24S8, MultisampleType multiSampleType: None, Int32 multiSampleQuality: 0, Boolean discard: False, IntPtr& surface: (out), IntPtr sharedHandle: 0)
Clear(IntPtr devicePointer: 147414976, Int32 count: 0, IntPtr rects: (Empty), ClearFlags flags: Target, ColorBGRA color: A:0 R:0 G:0 B:0, Single z: 1, Int32 stencil: 0)
Clear(IntPtr devicePointer: 147414976, Int32 count: 0, IntPtr rects: (Empty), ClearFlags flags: Target, ColorBGRA color: A:0 R:0 G:0 B:0, Single z: 1, Int32 stencil: 0)
BeginScene(IntPtr devicePointer: 147414976)
Clear(IntPtr devicePointer: 147414976, Int32 count: 0, IntPtr rects: (Empty), ClearFlags flags: Target, ColorBGRA color: A:0 R:0 G:0 B:0, Single z: 1, Int32 stencil: 0)
Clear(IntPtr devicePointer: 147414976, Int32 count: 0, IntPtr rects: (Empty), ClearFlags flags: Target, ColorBGRA color: A:0 R:0 G:0 B:0, Single z: 1, Int32 stencil: 0)
Clear(IntPtr devicePointer: 147414976, Int32 count: 0, IntPtr rects: (Empty), ClearFlags flags: ZBuffer, ColorBGRA color: A:0 R:0 G:0 B:0, Single z: 1, Int32 stencil: 0)
BeginScene(IntPtr devicePointer: 147414976)

Сигнатура метода, наиболее похожая на эту CreateVertexDeclaration() кажется Clear(), Вот моя реализация Clear():

private Result Clear(IntPtr devicePointer, int count, IntPtr rects, ClearFlags flags, ColorBGRA color, float z, int stencil)
{
try
{
var structSize = Marshal.SizeOf(typeof (Rectangle));
var structs = new Rectangle[count];
for (int i = 0; i < count; i++)
{
structs[i] = (Rectangle) Marshal.PtrToStructure(rects, typeof (Rectangle));
}
// Seems to work fine, not sure why it doesn't work for CreateVertexDeclaration

var rectangles = structs;
Log.LogMethodSignatureTypesAndValues(devicePointer, count, rectangles.PrintTypesNamesValues(), flags,
color, z, stencil);
GetOrCreateDevice(devicePointer);
if (rectangles.Length == 0)
Device.Clear(flags, color, z, stencil);
else
Device.Clear(flags, color, z, stencil, rectangles);
}
catch (Exception ex)
{
Log.Warn(ex.ToString());
}

return Result.Ok;
}

7

Решение

Во-первых, объявление в SharpDX использует Pack = 2 (а не Pack = 1):

[StructLayout (LayoutKind.Sequential, Pack = 2)]
публичная частичная структура VertexElement {
...
}

Также, если вы хотите быть уверенным в маршале, предпочитайте использовать unsafe, чем Marshal.StructureToPtr или любой другой метод маршала, когда это возможно (когда структура отображается непосредственно в эквивалент C #). Вы избежите проблем с производительностью Marshal и будете уверены в расположении памяти (при условии, что структура была правильно объявлена ​​в c #)

public unsafe static void CreateVertexDeclaration (IntPtr devicePointer, IntPtr vertexElementsPtr, out IntPtr vertexDeclaration)
{
var vertexElements = (VertexElement *) vertexElementsPtr;

// Доступ ко всем VertexElement (последний элемент указан Cmacro D3DDECL_END () в d3d9types.h)
...
}
3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]