1. 程式人生 > >C#呼叫C++ 平臺呼叫P/Invoke 結構體--輸入輸出引數、返回值、返出值、結構體陣列作為引數【五】

C#呼叫C++ 平臺呼叫P/Invoke 結構體--輸入輸出引數、返回值、返出值、結構體陣列作為引數【五】

【1】結構體作為輸入輸出引數

C++程式碼:

typedef struct _testStru1
{
	int		iVal;
	char	cVal;
	__int64 llVal;
}testStru1;
EXPORTDLL_API void Struct_Change( testStru1 *pStru )
{
	if (NULL == pStru)
	{
		return;
	}

	pStru->iVal = 1;
	pStru->cVal = 'a';
	pStru->llVal = 2;

	wprintf(L"Struct_Change \n");
}


C#程式碼:

指定為ref即可

/*   1.以StructLayout來標記結構體,指定結構體記憶體佈局
 *   2.欄位定義的順序 
 *   3.欄位型別 
 *   4.欄位在記憶體中的大小 
 *   5.非託管與託管結構名稱可以不同 
 */ 
//4.1 結構體作為輸入輸出引數
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct testStru1
{
   public int		iVal;
   public sbyte	    cVal;
   public long      llVal;
};
[DllImport("ExportDll.dll", CharSet = CharSet.Unicode)]
public static extern void Struct_Change(ref testStru1 pStru);


測試:

CExportDll.testStru1 stru1 = new CExportDll.testStru1();
CExportDll.Struct_Change(ref stru1);

【2】結構體作為返回值

C++程式碼:

typedef struct _testStru5
{
	int		iVal;
}testStru5;
testStru5	g_stru5;
EXPORTDLL_API testStru5* Struct_Return()
{	
	g_stru5.iVal = 5;
	wprintf(L"Struct_Return \n");
	return(&g_stru5);
}

C#程式碼,定義返回值為IntPtr,再進行解析:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct testStru5
{
    public int	iVal;
};
[DllImport("ExportDll.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr Struct_Return();

測試:

IntPtr struIntPtr = CExportDll.Struct_Return();
CExportDll.testStru5 stru5 = (CExportDll.testStru5)(Marshal.PtrToStructure(struIntPtr, typeof(CExportDll.testStru5)));


【3】結構體陣列作為引數

C++程式碼:

typedef struct _testStru6
{
	int		iVal;
}testStru6;
EXPORTDLL_API void Struct_StruArr( testStru6 *pStru, int len )
{
	if (NULL == pStru)
	{
		return;
	}

	for ( int ix=0; ix<len; ix++)
	{
		pStru[ix].iVal = ix;
	}

	wprintf(L"Struct_StruArr \n");
}

C#程式碼:定義成testStru6[]即可,如果需要返回修改後的值,則需要指定[In,Out]引數

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct testStru6
{
    public int		iVal;
};
[DllImport("ExportDll.dll", CharSet = CharSet.Unicode)]
public static extern void Struct_StruArr([In, Out]testStru6[] pStru, int len);

測試:

CExportDll.testStru6 []stru6 = new CExportDll.testStru6[5];
CExportDll.Struct_StruArr(stru6, 5);


【4】結構體作為返出引數,釋放非託管的記憶體

C++程式碼:

typedef struct _testStru8
{
	int		m;
}testStru8;
EXPORTDLL_API void Struct_ParameterOut( testStru8 **ppStru )
{
	if (NULL == ppStru)
	{
		return;
	}

	*ppStru = (testStru8*)CoTaskMemAlloc(sizeof(testStru8));

	(*ppStru)->m	= 8;
	wprintf(L"Struct_ParameterOut \n");
}

C#程式碼:定義成ref IntPtr即可,需要解析

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct testStru8
{
    public int		m;
};
[DllImport("ExportDll.dll", CharSet = CharSet.Unicode)]
public static extern void Struct_ParameterOut(ref IntPtr ppStru);

測試:

<strong>IntPtr outPtr = IntPtr.Zero;
CExportDll.Struct_ParameterOut(ref outPtr);
CExportDll.testStru8 stru8 = (CExportDll.testStru8)(Marshal.PtrToStructure(outPtr, typeof(CExportDll.testStru8)));
Marshal.FreeCoTaskMem(outPtr);
</strong>