提问人:Volodymyr Lytvyn 提问时间:7/19/2023 最后编辑:Volodymyr Lytvyn 更新时间:7/24/2023 访问量:45
PInvoke:很难使用缓冲区指针设置结构,该指针可以根据上下文采用各种类型
PInvoke: Struggle to set up struct with a buffer pointer which could take various types depending on context
问:
我正在尝试为由 tsmapi64.dll 表示的 IBM TSM Api(tivoli 存储管理器)构建 C# 客户端 作为参考,我有 api 文档和一个用 C 编写的示例应用程序(源代码 + 标头),它展示了如何使用 api 调用。示例应用程序在所有情况下都可以正常工作,而我的 C# 应用程序在某些函数上成功,但有些函数失败。
在 api 中声明了一个结构体 DataBlk,用于各种函数。它内部有缓冲区指针,可用于发送数据以及接收数据。
typedef struct
{
dsUint16_t stVersion ; /* structure version */
dsUint32_t bufferLen; /* Length of buffer passed below */
dsUint32_t numBytes; /* Actual number of bytes read from */
/* or written to the buffer */
char *bufferPtr; /* Data buffer */
dsUint32_t numBytesCompressed; /* on send actual bytes compressed */
dsUint16_t reserved; /* for future use */
}DataBlk;
它用于在函数 dsmSendData 中发送数据: dsInt16_t dsmSendData (dsUint32_t dsmHandle, DataBlk *dataBlkPtr);
数据Blk *dataBlkPtr (I/O) 此参数指向一个结构,该结构包括指向要从中发送数据的缓冲区的指针以及缓冲区的大小。返回时,此结构包含实际传输的字节数。 此调用的 C 代码:
dataBlkArea.bufferPtr = (char *)malloc(20);
dataBlkArea.stVersion = DataBlkVersion;
dataBlkArea.bufferLen = 20;
memcpy(dataBlkArea.bufferPtr,"T1T1T1T1T1T1T1T1T1T1", 20);
dsmSendData(handle,&dataBlkArea))
此调用的 C# 代码(成功):
[DllImport("tsmapi64.dll")]
private static extern Int16 dsmSendData(UInt32 dsmHandleP, ref DataBlk dataBlkPtr);
[StructLayout(LayoutKind.Sequential)]
public struct DataBlk
{
public UInt16 stVersion;
public UInt32 bufferLen;
public UInt32 numBytes;
public IntPtr bufferPtr;
public UInt32 numBytesCompressed;
public UInt16 reserved;
}
DataBlk dataBlkPtr = new DataBlk();
var buffStr = "12345";
var buffPtr = Marshal.StringToHGlobalAuto(buffStr);
dataBlkPtr.bufferPtr = buffPtr;
DsmSendData(handle, ref dataBlkPtr);
上面的东西成功了,但现在我需要使用函数 dsmGetNextQObj 从服务器查询数据: dsInt16_t dsmGetNextQObj (dsUint32_t dsmHandle, DataBlk *dataBlkPtr);
DataBlk dataBlkPtr (I/O) 指向一个结构,该结构包括指向要接收的数据的缓冲区的指针和缓冲区的大小。此缓冲区是qryResp 数据(qryRespArchiveData、qryRespBackupData 等)响应结构。返回时,此结构包含传输的字节数。下表描述了与每种类型的查询关联的结构 dataBlkPtr 参数必须指向使用 qryResp*Data 结构类型定义的缓冲区。调用 dsmGetNextQObj 的上下文决定了在查询响应中输入的结构类型。
此调用的 C 代码:
typedef struct S_archDetailCG
{
char cgName[DSM_MAX_CG_NAME_LENGTH + 1]; /* Copy group name */
dsUint16_t frequency; /* Copy (archive) frequency */
dsUint16_t retainVers; /* Retain version */
dsUint8_t copySer; /* for copy serialization values, see defines */
dsUint8_t copyMode; /* for copy mode values, see defines above */
char destName[DSM_MAX_CG_DEST_LENGTH + 1]; /* Copy dest name */
dsmBool_t bLanFreeDest; /* Destination has lan free path? */
dsmBool_t reserved; /* Not currently used */
dsUint8_t retainInit; /* possible values see above */
dsUint16_t retainMin; /* if retInit is EVENT num of days */
dsmBool_t bDeduplicate; /* destination has dedup enabled */
}archDetailCG;
typedef struct S_backupDetailCG
{
char cgName[DSM_MAX_CG_NAME_LENGTH + 1]; /* Copy group name */
dsUint16_t frequency; /* Backup frequency */
dsUint16_t verDataExst; /* Versions data exists */
dsUint16_t verDataDltd; /* Versions data deleted */
dsUint16_t retXtraVers; /* Retain extra versions */
dsUint16_t retOnlyVers; /* Retain only versions */
dsUint8_t copySer; /* for copy serialization values, see defines */
dsUint8_t copyMode; /* for copy mode values, see defines above */
char destName[DSM_MAX_CG_DEST_LENGTH + 1]; /* Copy dest name */
dsmBool_t bLanFreeDest; /* Destination has lan free path? */
dsmBool_t reserved; /* Not currently used */
dsmBool_t bDeduplicate; /* destination has dedup enabled */
}backupDetailCG;
typedef struct S_qryRespMCDetailData
{
dsUint16_t stVersion; /* structure version */
char mcName[DSM_MAX_MC_NAME_LENGTH + 1]; /* mc name */
char mcDesc[DSM_MAX_MC_DESCR_LENGTH + 1]; /*mc description */
archDetailCG archDet; /* Archive copy group detail */
backupDetailCG backupDet; /* Backup copy group detail */
}qryRespMCDetailData;
DataBlk qData;
qryRespMCDetailData qRespMCData, *mcResp;
qData.stVersion = DataBlkVersion;
qData.bufferLen = sizeof(qryRespMCDetailData);
qData.bufferPtr = (char *)&qRespMCData;
dsmGetNextQObj(handle,&qData)
我正在尝试的 C# 代码,但它失败了:
[StructLayout(LayoutKind.Sequential)]
public struct DataBlk
{
public UInt16 stVersion;
public UInt32 bufferLen;
public UInt32 numBytes;
public IntPtr bufferPtr;
public UInt32 numBytesCompressed;
public UInt16 reserved;
}
[StructLayout(LayoutKind.Sequential)]
public struct qryRespMCDetailData
{
public UInt16 stVersion { get; set; }
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 31)]
public string mcName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string mcDesc;
public archDetailCG archDet;
public backupDetailCG backupDet;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct archDetailCG
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 31)]
public string cgName;
public UInt16 frequency;
public UInt16 retainVers;
public byte copySer;
public byte copyMode;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 31)]
public string destName;
public byte bLanFreeDest;
public byte reserved;
public byte retainInit;
public UInt16 retainMin;
public byte bDeduplicate;
}
[StructLayout(LayoutKind.Sequential)]
public struct backupDetailCG
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 31)]
public string cgName;
public UInt16 frequency;
public UInt16 verDataExst;
public UInt16 verDataDltd;
public UInt16 retXtraVers;
public UInt16 retOnlyVers;
public byte copySer;
public byte copyMode;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 31)]
public string destName;
public byte bLanFreeDest;
public byte reserved;
public byte bDeduplicate;
}
qryRespMCDetailData qryRespMCDetailData = new qryRespMCDetailData();
backupDetailCG backupDetailCG = new backupDetailCG();
archDetailCG archDetailCG = new archDetailCG();
qryRespMCDetailData.backupDet = backupDetailCG;
qryRespMCDetailData.archDet = archDetailCG;
qryRespMCDetailData.stVersion = 4;
IntPtr buffer1 = Marshal.AllocCoTaskMem(Marshal.SizeOf<qryRespMCDetailData>());
Marshal.StructureToPtr(qryRespMCDetailData, buffer1, false);
DataBlk dataBlkPtr = new DataBlk();
dataBlkPtr.stVersion = 2;
dataBlkPtr.bufferPtr = buffer1;
dataBlkPtr.bufferLen = (uint)Marshal.SizeOf<qryRespMCDetailData>();
var rc = dsmGetNextQObj(handle, ref dataBlkPtr);
if (rc != 0)
{
string message = "";
var messagePtr = Marshal.StringToHGlobalAnsi(message);
dsmRCMsg(handle, rc, messagePtr);
Console.WriteLine("dsmGetNextQObj rc info = " + Marshal.PtrToStringAnsi(messagePtr));
}
else
{
var struc = Marshal.PtrToStructure<qryRespMCDetailData>(dataBlkPtr.bufferPtr);
Console.WriteLine("mcName = " + struc.mcName);
}
我收到错误“2065 E DSM_RC_WRONG_VERSION_PARM调用方的结构版本与 TSM 库版本不同。
我认为问题出在字段 DataBlk.bufferPtr 和/或 DataBlk.numBytes 的类型/值上,因为在找到其缓冲区指针和大小的正确组合之前,我对 dsmSendData 调用有相同的错误。
那么,您能否建议我应该如何为结构 qryRespMCDetailData 设置指针和大小? 这个用于管理类查询,但对于其他类型的查询,其他类型的返回结构是预期的,例如“qryRespArchiveData”,但我认为方法应该是类似的。
我在某处看到过 C (char *) 可能意味着一种通用指针,但是我如何将其应用于返回结构?
为这项任务尝试不安全的指针有意义吗?
谢谢!
答:
最终,这奏效了
[StructLayout(LayoutKind.Sequential)]
public struct DataBlk
{
public UInt16 stVersion;
public UInt32 bufferLen;
public UInt32 numBytes;
public IntPtr bufferPtr;
public UInt32 numBytesCompressed;
public UInt16 reserved;
}
[StructLayout(LayoutKind.Sequential)]
public struct qryRespMCDetailData
{
public UInt16 stVersion { get; set; }
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 31)]
public string mcName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string mcDesc;
public archDetailCG archDet;
public backupDetailCG backupDet;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct archDetailCG
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 31)]
public string cgName;
public UInt16 frequency;
public UInt16 retainVers;
public byte copySer;
public byte copyMode;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 31)]
public string destName;
public byte bLanFreeDest;
public byte reserved;
public byte retainInit;
public UInt16 retainMin;
public byte bDeduplicate;
}
[StructLayout(LayoutKind.Sequential)]
public struct backupDetailCG
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 31)]
public string cgName;
public UInt16 frequency;
public UInt16 verDataExst;
public UInt16 verDataDltd;
public UInt16 retXtraVers;
public UInt16 retOnlyVers;
public byte copySer;
public byte copyMode;
public string destName;
public byte bLanFreeDest;
public byte reserved;
public byte bDeduplicate;
}
qryRespMCDetailData qryRespMCDetailData = new qryRespMCDetailData();
backupDetailCG backupDetailCG = new backupDetailCG();
archDetailCG archDetailCG = new archDetailCG();
qryRespMCDetailData.backupDet = backupDetailCG;
qryRespMCDetailData.archDet = archDetailCG;
qryRespMCDetailData.stVersion = 4;
IntPtr buffer1 = Marshal.AllocCoTaskMem(Marshal.SizeOf<qryRespMCDetailData>());
Marshal.StructureToPtr(qryRespMCDetailData, buffer1, false);
DataBlk dataBlkPtr = new DataBlk();
dataBlkPtr.stVersion = 2;
dataBlkPtr.bufferPtr = buffer1;
dataBlkPtr.bufferLen = (uint)Marshal.SizeOf<qryRespMCDetailData>();
var rc = dsmGetNextQObj(handle, ref dataBlkPtr);
if (rc != 0)
{
string message = "";
var messagePtr = Marshal.StringToHGlobalAnsi(message);
dsmRCMsg(handle, rc, messagePtr);
Console.WriteLine("dsmGetNextQObj rc info = " + Marshal.PtrToStringAnsi(messagePtr));
}
else
{
var struc = Marshal.PtrToStructure<qryRespMCDetailData>(dataBlkPtr.bufferPtr);
Console.WriteLine("mcName = " + dataBlkPtr.bufferPtr);
}
评论