[英]How to marshalling a function with (char* param[]) in C#
我在本机dll中有一个函数,其函数如下所示
int GetActiveNames(char* names[]);
如何在C#中为上述函数创建PInvoke包装器方法,该函数将返回一个字符串/字符数组?
为了更具描述性。
我尝试了P / Invoke方式,并显示以下错误 。
我只是简化了实际的C函数签名以使其变得简单。 但是这里是完整的C函数签名和函数参数的描述
int OpalGetActiveProjects(unsigned short allocatedProjects,
unsigned short *numProjects,
unsigned short allocatedModels,
unsigned short *numModels,
unsigned short allocatedProjectsPathLen,
unsigned short *maxProjectPathLen,
unsigned short allocatedModelPathLen,
unsigned short *maxModelPathLen,
unsigned short allocatedMachineNameLen,
unsigned short *maxMachineNameLen,
unsigned short allocatedIpLen,
unsigned short *maxIpLen,
char *projectPaths[],
unsigned short instanceIDs[],
char *machineNames[],
char *controllerIPs[],
char *modelPaths[],
unsigned short numModelsPerProject[]
unsigned short modelIDs[],
unsigned short modelStates[]);
该函数返回活动项目的列表。 对于每个项目,此函数返回配置文件的完整路径,打开该项目的计算机的名称和IP地址,当前项目会话的实例ID以及属于该项目的模型的列表。 对于每个模型,将返回路径,ID和状态。如果分配的存储空间对于任何参数而言都太小,则不会返回任何列表,但会设置numProjects,numModels,maxProjectPathLen,maxModelPathLen,maxMachineNameLen和maxIpLen值,并且返回值为E2BIG。 应用程序可以使用此事实在第一次调用时将长度指定为0,分配所需的存储空间,然后发出第二次调用以获取信息。
输入参数
locatedProjects :调用者为其路径,机器名称,IP地址和实例ID分配存储空间的项目数。 locatedModels :调用者为其名称,路径和实例ID分配存储空间的模型数量。 allocateProjectPathLen :分配用于接收项目路径的存储空间allocateModelPathLen :分配用于接收模型路径的存储空间allocatedMachineNameLen :分配用于接收机器名的存储空间分配IpLen:分配用于接收IP地址的存储长度
输出参数
numProjects :指向API将存储活动项目的实际数量的位置的指针。 numModels:指向API将存储所有活动项目的实际模型总数的位置的指针。 maxProjectPathLen:指向API将存储最长项目路径长度的位置的指针。 maxModelPathLen:指向API将存储最长模型路径长度的位置的指针。 maxMachineNameLen:指向API将存储最长计算机名称长度的位置的指针。 maxIpLen:指向API将存储最长IP地址长度的位置的指针。 projectPaths:字符串数组,API将在其中存储活动项目的配置文件的路径。 instanceIDs: API将在其中存储活动项目的实例ID的数组。 machineNames: API将在其中存储计算机名称的数组。 controllerIPs: API将在其中存储IP地址的数组。 modelPaths: API将在其中存储所有活动项目的模型路径的数组。 numModelsPerProject: API将在其中存储每个项目的模型数的数组。 使用这些值来确定哪个模型属于哪个项目。 modelIDs: API将在其中存储所有活动项目的模型ID的数组。 modelStates: API将在其中存储所有活动项目的模型状态的数组。
还有一个C程序,它使用OpalGetActiveProjects()函数来获取projectPaths,machineNames等。
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
// Header for getcwd() is platform-dependent
#if defined(WIN32)
#include <direct.h>
#include <windows.h>
#elif defined(__linux__)
#include <unistd.h>
#define _MAX_PATH 256
#endif
#include "OpalApi.h"
void PrintError(int rc, char *funcName);
#define FALSE 0
#define TRUE 1
int main (int argc, char* argv[])
{
char **projectPath, **modelPath;
char *projectPaths, *modelPaths;
char **loaderMachineName, **controllerIp;
char *loaderMachineNames, *controllerIps;
int i, rc, projectIdx;
unsigned short *instId;
int *instId2;
int * modelIds;
unsigned short *numModelsPerProject;
unsigned short *modelId;
unsigned short *modelState;
unsigned short allocProjects, numProjects;
unsigned short allocModels, numModels;
unsigned short allocProjectPathLen, maxProjectPathLen;
unsigned short allocModelPathLen, maxModelPathLen;
unsigned short allocMachineLen, maxMachineLen;
unsigned short allocIpLen, maxIpLen;
// Obtenir la taille des données.
allocProjects =allocModels = 0;
allocProjectPathLen = allocModelPathLen = 0;
allocMachineLen = allocIpLen = 0;
rc = OpalGetActiveProjects( 0, &allocProjects,
0, &allocModels,
0, &allocProjectPathLen,
0, &allocModelPathLen,
0, &allocMachineLen,
0, &allocIpLen,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL );
if ((rc != 0) && (rc != E2BIG))
{
PrintError(rc, "OpalGetActiveProject");
printf(" - alGetActiveProjects error output !!!\n");
printf("\t numProjects - %i \n", allocProjects);
printf("\t numModels - %i \n", allocModels);
printf("\t maxProjectPathLen - %i \n", allocProjectPathLen);
printf("\t maxModelPathLen - %i \n", allocModelPathLen);
//printf("\t maxMachineNameLen - %i \n", maxMachineNameLen);
printf("\t maxIpLen - %i \n", allocIpLen);
return (rc);
// Erreur
//return returnInstance;
}
projectPath = (char **)_alloca(allocProjects * sizeof(*projectPath));
projectPaths = (char *)_alloca(allocProjects * (allocProjectPathLen + 1) * sizeof(*projectPaths));
loaderMachineName = (char **)_alloca(allocProjects * sizeof(*loaderMachineName));
loaderMachineNames = (char *)_alloca(allocProjects * (allocMachineLen + 1) * sizeof(*loaderMachineNames));
controllerIp = (char **)_alloca(allocProjects * sizeof(*controllerIp));
controllerIps = (char *)_alloca(allocProjects * (allocIpLen + 1) * sizeof(*controllerIps));
numModelsPerProject = (unsigned short*)_alloca(allocProjects * sizeof(*numModelsPerProject));
modelPath = (char **)_alloca(allocModels * sizeof(*modelPath));
modelPaths = (char *)_alloca(allocModels * (allocModelPathLen + 1) * sizeof(*modelPaths));
for (i = 0; i < allocProjects; ++i)
{
projectPath[i] = &projectPaths[i * (allocProjectPathLen + 1)];
loaderMachineName[i] = &loaderMachineNames[i * (allocMachineLen + 1)];
controllerIp[i] = &controllerIps[i * (allocIpLen + 1)];
}
for (i = 0; i < allocModels; ++i)
{
modelPath[i] = &modelPaths[i * (allocModelPathLen + 1)];
}
instId = (unsigned short *)_alloca(allocProjects * sizeof(*instId));
instId2 = (int *)_alloca(allocProjects * sizeof(*instId2));
modelId = (unsigned short*)_alloca(allocModels * sizeof(*modelId));
modelState = (unsigned short *)_alloca(allocModels * sizeof(*modelState));
rc = OpalGetActiveProjects( allocProjects, &numProjects,
allocModels, &numModels,
allocProjectPathLen, &maxProjectPathLen,
allocModelPathLen, &maxModelPathLen,
allocMachineLen, &maxMachineLen,
allocIpLen, &maxIpLen,
projectPath, instId,
loaderMachineName, controllerIp, modelPath,
numModelsPerProject, modelId, modelState);
printf(" - OpalGetActiveProjects output !!!\n");
printf("\t numProjects - %i \n", allocProjects);
printf("\t numModels - %i \n", allocModels);
printf("\t maxProjectPathLen - %i \n", allocProjectPathLen);
printf("\t maxModelPathLen - %i \n", allocModelPathLen);
//printf("\t maxMachineNameLen - %i \n", maxMachineNameLen);
printf("\t maxIpLen - %i \n", allocIpLen);
for(i=0; i<numProjects; i++)
{
printf("\t \t projectPath[%d] = %s \n", i, *(projectPath +i));
printf("\t \t instId[%d] = %d \n", i, *(instId + i));
printf("\t \t loaderMachineName[%d] = %s \n", i, *(loaderMachineName + i));
printf("\t \t controllerIp[%d] = %s \n", i, *(controllerIp + i));
printf("\t \t numModelsPerProject[%d] = %d \n", i, * (numModelsPerProject +i));
}
for(i=0; i<numModels; i++)
{
printf("\t \t modelPath[%d] = %s \n", i, *(modelPath+i));
printf("\t \t modelId[%d] = %d \n", i, *(modelId +i));
printf("\t \t modelState[%d] = %d \n", i, *(modelState+i));
}
OpalDisconnect();
getchar();
}
void PrintError(int rc, char *funcName)
{
char buf[512];
unsigned short len;
OpalGetLastErrMsg(buf, sizeof(buf), &len);
printf("Error !!! \n %s (code %d) from %s\n", buf, rc, funcName);
}
签名太奇怪了,无法翻译成C#。 我尝试查看TlbImp.exe将其转换为什么,并显示:
TlbImp:警告TI3015:运行时封送程序无法封送“ Marshal2.IMarshal3.GetActiveNames”的参数之一。 因此,此类参数将作为指针传递,并且可能需要使用不安全的代码进行操作。
如果可以,我建议更改函数以返回包含BSTR的SAFEARRAY。 在C#端,您会看到一个System.Array,其元素(类型为Object)可以转换为String。
我还建议使GetActiveNames成为COM类的方法。 P / Invoke太原始且不安全。
使用C#调用/调用函数:
using System.Runtime.InteropServices;
public class ActiveNames
{
public string[] ActiveNames { get; set; }
[DllImport("GetActiveNames.dll")] // replace with the actual name of the DLL
unsafe private static int GetActiveNames(sbyte** names):
public void GetActiveNames()
{
unsafe
{
// I use 100 here as an artificial number. This may not be a reasonable
// assumption, but I don't know how the actual GetActiveNames works
sbyte** names = (sbyte**)Marshal.AllocHGlobal(100).ToPointer();
try
{
GetActiveNames(names);
// fill the ActiveNames property
ActiveNames = new string[100];
for (int i = 0; i < 100; ++i)
ActiveNames[i] = new string(names[i]);
}
finally
{
// deallocate the unmanaged names memory
Marshal.FreeHGlobal(IntPtr((void*)names));
}
}
}
}
并使用C ++ / CLI(无需P / Invoke):
#include "GetActiveNames.h" // replace with the actual GetActiveNames's header
using namespace System;
using namespace System::Runtime::InteropServices;
public ref class ActiveNames
{
private:
array<String^>^ m_activeNames;
public:
property array<String^>^ ActiveNames
{
array<String^>^ get()
{
return m_activeNames;
}
void set(array<String^>^ names)
{
m_activeNames = names;
}
}
void GetActiveNames()
{
signed char** names = new signed char*[100];
try
{
::GetActiveNames(reinterpret_cast<char**>(names));
ActiveNames = gcnew array<String^>(100);
for (int i = 0; i < 100; ++i)
ActiveNames[i] = gcnew String(names[i]);
catch (...)
{
delete[] names;
throw;
}
delete[] names;
}
};
如您所见,我做了一些不安全的假设,因为我不知道GetActiveNames的工作原理(如何分配和释放名称的内存?如何知道返回了多少个名称?)。 如果您需要更多帮助,则必须更加具体。
哇,那真的是一个可怕的API。 甚至没有其他任何东西吗...哦,我不知道... DECENT,您可以使用吗? 但是如果你真的想要...
using System;
using System.Runtime.InteropServices;
public class ActiveProjects
{
public string[] ProjectPaths { get; set; }
public ushort[] InstanceIds { get; set; }
public string[] MachineNames { get; set; }
public string[] ControllerIps { get; set; }
public string[] ModelPaths { get; set; }
public ushort[] NumberOfModelsPerProject { get; set; }
public ushort[] ModelIds { get; set; }
public ushort[] ModelStates { get; set; }
[DllImport("<the DLL>")]
unsafe private static int OpalGetActiveProjects(
ushort allocatedProjects,
ushort* numProjects,
ushort allocatedModels,
ushort* numModels,
ushort allocatedProjectsPathLen,
ushort* maxProjectPathLen,
ushort allocatedModelPathLen,
ushort* maxModelPathLen,
ushort allocatedMachineNameLen,
ushort* maxMachineNameLen,
ushort allocatedIpLen,
ushort* maxIpLen,
sbyte** projectPaths,
ushort* instanceIDs,
sbyte** machineNames,
sbyte** controllerIPs,
sbyte** modelPaths,
ushort* numModelsPerProject,
ushort* modelIDs,
ushort* modelStates
);
public void GetActiveProjects()
{
unsafe
{
ushort numberOfProjects = 0;
ushort numberOfModels = 0;
ushort maxProjectPathLength = 0;
ushort maxModelPathLength = 0;
ushort maxMachineNameLength = 0;
ushort maxIpLength = 0;
int result = OpalGetActiveProjects(
0,
&numberOfProjects,
0,
&numberOfModels,
0,
&maxProjectPathLength,
0,
&maxModelPathLength,
0,
&maxMachineNameLength,
0,
&maxIpLength,
null,
null,
null,
null,
null,
null,
null,
null
);
if (result != 0 && result != 123)
throw new Exception("Error getting active projects");
sbyte** projectPaths = null;
ushort* instanceIds = null;
sbyte** machineNames = null;
sbyte** controllerIps = null;
sbyte** modelPaths = null;
ushort* numberOfModelsPerProject = null;
ushort* modelIds = null;
ushort* modelStates = null;
try
{
projectPaths = (sbyte**)Marshal.AllocHGlobal(numberOfProjects * IntPtr.Size).ToPointer();
for (int i = 0; i < numberOfProjects; ++i)
projectPaths[i] = null;
for (int i = 0; i < numberOfProjects; ++i)
projectPaths[i] = (sbyte*)Marshal.AllocHGlobal(maxProjectPathLength);
instanceIds = (ushort*)Marshal.AllocHGlobal(numberOfProjects * 2).ToPointer();
machineNames = (sbyte**)Marshal.AllocHGlobal(numberOfProjects * IntPtr.Size).ToPointer();
for (int i = 0; i < numberOfProjects; ++i)
machineNames[i] = null;
for (int i = 0; i < numberOfProjects; ++i)
machineNames[i] = (sbyte*)Marshal.AllocHGlobal(maxMachineNameLength).ToPointer();
controllerIps = (sbyte**)Marshal.AllocHGlobal(numberOfProjects * IntPtr.Size).ToPointer();
for (int i = 0; i < numberOfProjects; ++i)
controllerIps[i] = null;
for (int i = 0; i < numberOfProjects; ++i)
controllerIps[i] = (sbyte*)Marshal.AlloHGlobal(maxIpLength).ToPointer();
modelPaths = (sbyte**)Marshal.AlloHGlobal(numberOfModels * IntPtr.Size).ToPointer();
for (int i = 0; i < numberOfProjects; ++i)
modelPaths = null;
for (int i = 0; i < numberOfProjects; ++i)
modelPaths = (sbyte*)Marshal.AllocHGlobal(maxModelPathLength).ToPointer();
numberOfModelsPerProject = (ushort*)Marshal.AlloHGlobal(numberOfProjects * 2).ToPointer();
modelIds = (ushort*)Marshal.AllocHGlobal(numberOfModels * 2).ToPointer();
modelStates = (ushort*)Marshal.AllocHGlobal(numberOfModels * 2).ToPointer();
ushort numberOfProjects2 = 0;
ushort numberOfModels2 = 0;
ushort maxProjectPathLength2 = 0;
ushort maxModelPathLength2 = 0;
ushort maxMachineNameLength2 = 0;
ushort maxIpLength2 = 0;
OpalGetActiveProjects(
numberOfProjects,
&numberOfProjects2,
numberOfModels,
&numberOfModels2,
maxProjectPathLength,
&maxProjectPathLength2,
maxModelPathLength,
&maxModelPathLength2,
maxMachineNameLength,
&maxMachineNameLength2,
maxIpLength,
&maxIpLength2,
projectPaths,
instanceIds,
machineNames,
controllerIps,
modelPaths,
numberOfModelsPerProject,
modelIds,
modelStates
);
ProjectPaths = new string[numberOfProjects2];
for (int i = 0; i < numberOfProjects2; ++i)
ProjectPaths[i] = new string(projectPaths[i]);
InstanceIds = new ushort[numberOfProjects2];
for (int i = 0; i < numberOfProjects2; ++i)
InstanceIds[i] = instanceIds[i];
MachineNames = new string[numberOfProjects2];
for (int i = 0; i < numberOfProjects2; ++i)
MachineNames[i] = new string(machineNames[i]);
ControllerIps = new string[numberOfProjects2];
for (int i = 0; i < numberOfProjects2; ++i)
ControllerIps[i] = new string(controllerIps[i]);
ModelPaths = new string[numberOfModels2];
for (int i = 0; i < numberOfModels2; ++i)
ModelPaths[i] = new string(modelPaths[i]);
NumberOfModelsPerProject = new ushort[numberOfProjects2];
for (int i = 0; i < numberOfProjects2; ++i)
NumberOfModelsPerProject[i] = numberOfModelsPerProject[i];
ModelIds = new ushort[numberOfModels2];
for (int i = 0; i < numberOfModels2; ++i)
ModelIds[i] = modelIds[i];
ModelStates = new ushort[numberOfModels2];
for (int i = 0; i < numberOfModels2; ++i)
ModelStates[i] = modelStates[i];
}
finally
{
if (projectPaths != null)
{
for (int i = 0; i < numberOfProjects && projectPaths[i] != null; ++i)
Marshal.FreeHGlobal(IntPtr((void*)projectPaths[i]));
Marshal.FreeHGlobal(IntPtr((void*)projectPaths));
}
if (instanceIds != null)
Marshal.FreeHGlobal(IntPtr((void*)instanceIds));
if (machineNames != null)
{
for (int i = 0; i < numberOfProjects && machineNames[i] != null; ++i)
Marshal.FreeHGlobal(IntPtr((void*)machineNames[i]));
Marshal.FreeHGlobal(IntPtr((void*)machineIds));
}
if (controllerIps != null)
{
for (int i = 0; i < numberOfProjects && controllerIps[i] != null; ++i)
Marshal.FreeHGlobal(IntPtr((void*)controllerIps[i]));
Marshal.FreeHGlobal(IntPtr((void*)controllerIps));
}
if (modelPaths != null)
{
for (int i = 0; i < numberOfModels && modelPaths[i] != null; ++i)
Marshal.FreeHGlobal(IntPtr((void*)modelPaths[i]));
Marshal.FreeHGlobal(IntPtr((void*)modelPaths));
}
if (numberOfModelsPerProject != null)
Marshal.FreeHGlobal(IntPtr((void*)numberOfModelsPerProject));
if (modelIds != null)
Marshal.FreeHGlobal(IntPtr((void*)modelIds));
if (modelStates != null)
Marshal.FreeHGlobal(IntPtr((void*)modelStates));
}
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.