TAPI lineGetCallInfo 返回空结果
TAPI lineGetCallInfo returning empty results
我正在尝试构建自定义解决方案以与我们的 IP Office phone 系统进行交互。我能够找到并更新我们的 phone 提供商 Avaya 提供的旧 VB6 TAPI 项目,该项目使用 TAPI32.dll 驱动程序。然而,从 VB6 到 .net 的变化给我带来了一些问题。其中最大的是旧代码将 Struct 传递给 dll 上的 pinvoke 函数。函数、结构和调用代码如下所示(抱歉长度):
Dim l_Call As Long
Dim struct_MyCallInfo As lineCallInfo
Dim l_lineGetCallInfo_Result As Long
' Init Parameters..
l_Call = RMSTAPIRoutines.glhCall
' Set Memory needed...
struct_MyCallInfo.l_dwTotalSize = LINECALLINFO_FIXEDSIZE + LINECALLINFO_MEMSIZE
' Run lineGetCallInfo..
l_lineGetCallInfo_Result = RMSTAPIDeclarations.lineGetCallInfo(l_Call, struct_MyCallInfo)
Global Const LINECALLINFO_MEMSIZE = DEFAULT_SIZE
Type lineCallInfo
l_dwTotalSize As Long
l_dwNeededSize As Long
l_dwUsedSize As Long
l_hLine As Long
l_dwLineDeviceID As Long
l_dwAddressID As Long
l_dwBearerMode As Long
l_dwRate As Long
l_dwMediaMode As Long
l_dwAppSpecific As Long
l_dwCallID As Long
l_dwRelatedCallID As Long
l_dwCallParamFlags As Long
l_dwCallStates As Long
l_dwMonitorDigitModes As Long
l_dwMonitorMediaModes As Long
struct_DialParams As lineDialParams
l_dwOrigin As Long
l_dwReason As Long
l_dwCompletionID As Long
l_dwNumOwners As Long
l_dwNumMonitors As Long
l_dwCountryCode As Long
l_dwTrunk As Long
l_dwCallerIDFlags As Long
l_dwCallerIDSize As Long
l_dwCallerIDOffset As Long
l_dwCallerIDNameSize As Long
l_dwCallerIDNameOffset As Long
l_dwCalledIDFlags As Long
l_dwCalledIDSize As Long
l_dwCalledIDOffset As Long
l_dwCalledIDNameSize As Long
l_dwCalledIDNameOffset As Long
l_dwConnectedIDFlags As Long
l_dwConnectedIDSize As Long
l_dwConnectedIDOffset As Long
l_dwConnectedIDNameSize As Long
l_dwConnectedIDNameOffset As Long
l_dwRedirectionIDFlags As Long
l_dwRedirectionIDSize As Long
l_dwRedirectionIDOffset As Long
l_dwRedirectionIDNameSize As Long
l_dwRedirectionIDNameOffset As Long
l_dwRedirectingIDFlags As Long
l_dwRedirectingIDSize As Long
l_dwRedirectingIDOffset As Long
l_dwRedirectingIDNameSize As Long
l_dwRedirectingIDNameOffset As Long
l_dwAppNameSize As Long
l_dwAppNameOffset As Long
l_dwDisplayableAddressSize As Long
l_dwDisplayableAddressOffset As Long
l_dwCalledPartySize As Long
l_dwCalledPartyOffset As Long
l_dwCommentSize As Long
l_dwCommentOffset As Long
l_dwDisplaySize As Long
l_dwDisplayOffset As Long
l_dwUserUserInfoSize As Long
l_dwUserUserInfoOffset As Long
l_dwHighLevelCompSize As Long
l_dwHighLevelCompOffset As Long
l_dwLowLevelCompSize As Long
l_dwLowLevelCompOffset As Long
l_dwChargingInfoSize As Long
l_dwChargingInfoOffset As Long
l_dwTerminalModesSize As Long
l_dwTerminalModesOffset As Long
l_dwDevSpecificSize As Long
l_dwDevSpecificOffset As Long
l_dwCallTreatment As Long
l_dwCallDataSize As Long
l_dwCallDataOffset As Long
l_dwSendingFlowspecSize As Long
l_dwSendingFlowspecOffset As Long
l_dwReceivingFlowspecSize As Long
l_dwReceivingFlowspecOffset As Long
' >= TAPI 3.0... BEGIN
l_dwCallerIDAddressType As Long
l_dwCalledIDAddressType As Long
l_dwConnectedIDAddressType As Long
l_dwRedirectionIDAddressType As Long
l_dwRedirectingIDAddressType As Long
' >= TAPI 3.0... END
mem As String * LINECALLINFO_MEMSIZE
End Type
Global Const LINECALLINFO_FIXEDSIZE = 344
Declare Function lineGetCallInfo Lib "TAPI32.DLL" _
(ByVal l_hCall As Long, ptr_lpCallInfo As Any) As Long
C# 不允许我这样做(关于访问受保护内存的各种声明)。经过一些研究,似乎每个人都同意您需要将 IntPtr 传递给非托管函数,而不是 Struct 本身。从我想出这个代码的例子
struct_MyCallInfo.l_dwTotalSize = RMSTAPIDeclarations.LINECALLINFO_FIXEDSIZE + RMSTAPIDeclarations.LINECALLINFO_MEMSIZE;
System.IntPtr sPTR = Marshal.AllocHGlobal(Marshal.SizeOf(struct_MyCallInfo));
Marshal.StructureToPtr(struct_MyCallInfo, sPTR, true);
int l_lineGetCallInfo_Result = RMSTAPIEvents.lineGetCallInfo(l_Call, sPTR);
调用这个函数
[DllImport("TAPI32.DLL", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
extern public static int lineGetCallInfo(int l_hCall, System.IntPtr ptr_lpCallInfo);
有了这个结构
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct lineCallInfo
{
public int l_dwTotalSize;
public int l_dwNeededSize;
public int l_dwUsedSize;
public int l_hLine;
public int l_dwLineDeviceID;
public int l_dwAddressID;
public int l_dwBearerMode;
public int l_dwRate;
public int l_dwMediaMode;
public int l_dwAppSpecific;
public int l_dwCallID;
public int l_dwRelatedCallID;
public int l_dwCallParamFlags;
public int l_dwCallStates;
public int l_dwMonitorDigitModes;
public int l_dwMonitorMediaModes;
public lineDialParams struct_DialParams;
public int l_dwOrigin;
public int l_dwReason;
public int l_dwCompletionID;
public int l_dwNumOwners;
public int l_dwNumMonitors;
public int l_dwCountryCode;
public int l_dwTrunk;
public int l_dwCallerIDFlags;
public int l_dwCallerIDSize;
public int l_dwCallerIDOffset;
public int l_dwCallerIDNameSize;
public int l_dwCallerIDNameOffset;
public int l_dwCalledIDFlags;
public int l_dwCalledIDSize;
public int l_dwCalledIDOffset;
public int l_dwCalledIDNameSize;
public int l_dwCalledIDNameOffset;
public int l_dwConnectedIDFlags;
public int l_dwConnectedIDSize;
public int l_dwConnectedIDOffset;
public int l_dwConnectedIDNameSize;
public int l_dwConnectedIDNameOffset;
public int l_dwRedirectionIDFlags;
public int l_dwRedirectionIDSize;
public int l_dwRedirectionIDOffset;
public int l_dwRedirectionIDNameSize;
public int l_dwRedirectionIDNameOffset;
public int l_dwRedirectingIDFlags;
public int l_dwRedirectingIDSize;
public int l_dwRedirectingIDOffset;
public int l_dwRedirectingIDNameSize;
public int l_dwRedirectingIDNameOffset;
public int l_dwAppNameSize;
public int l_dwAppNameOffset;
public int l_dwDisplayableAddressSize;
public int l_dwDisplayableAddressOffset;
public int l_dwCalledPartySize;
public int l_dwCalledPartyOffset;
public int l_dwCommentSize;
public int l_dwCommentOffset;
public int l_dwDisplaySize;
public int l_dwDisplayOffset;
public int l_dwUserUserInfoSize;
public int l_dwUserUserInfoOffset;
public int l_dwHighLevelCompSize;
public int l_dwHighLevelCompOffset;
public int l_dwLowLevelCompSize;
public int l_dwLowLevelCompOffset;
public int l_dwChargingInfoSize;
public int l_dwChargingInfoOffset;
public int l_dwTerminalModesSize;
public int l_dwTerminalModesOffset;
public int l_dwDevSpecificSize;
public int l_dwDevSpecificOffset;
public int l_dwCallTreatment;
public int l_dwCallDataSize;
public int l_dwCallDataOffset;
public int l_dwSendingFlowspecSize;
public int l_dwSendingFlowspecOffset;
public int l_dwReceivingFlowspecSize;
public int l_dwReceivingFlowspecOffset;
// >= TAPI 3.0... BEGIN
public int l_dwCallerIDAddressType;
public int l_dwCalledIDAddressType;
public int l_dwConnectedIDAddressType;
public int l_dwRedirectionIDAddressType;
public int l_dwRedirectingIDAddressType;
// >= TAPI 3.0... END
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 2048)]//LINEDEVSTATUS_MEMSIZE)]
public char[] _mem;
public string mem
{
get
{
return new string(_mem);
}
set
{
CopyValueToArray(_mem, value);
}
}
public static lineCallInfo CreateInstance()
{
lineCallInfo result = new lineCallInfo();
result._mem = new char[2048];
return result;
}
}
这行得通……有点。它 returns 结果没有抛出错误,但它 returns 填充的结构完全是空的。它应该返回指示线路类型、媒体模式、呼叫者信息等关于呼叫的值,但我只是得到全 0。
有人有过与 TAPI 进行托管交互的经验吗?我在结构或封送处理过程中做错了什么吗?几乎所有我的其他函数调用都有效,包括一些我在下面进行相同封送处理的地方。这让我相信它可能与结构有关。
编组 TAPI 结构 to/from 托管代码非常棘手。 TAPI在结构之后将可变长度数据放入内存中,您必须使用结构的xxxOffset和xxxSize成员才能找出数据所在的位置。
我强烈建议使用适用于 .NET 的 TAPI 库,它可以为您完成所有这些棘手的工作。您有两个选择:商业 AddTapi.NET or open-source Julmar TAPI.
我正在尝试构建自定义解决方案以与我们的 IP Office phone 系统进行交互。我能够找到并更新我们的 phone 提供商 Avaya 提供的旧 VB6 TAPI 项目,该项目使用 TAPI32.dll 驱动程序。然而,从 VB6 到 .net 的变化给我带来了一些问题。其中最大的是旧代码将 Struct 传递给 dll 上的 pinvoke 函数。函数、结构和调用代码如下所示(抱歉长度):
Dim l_Call As Long
Dim struct_MyCallInfo As lineCallInfo
Dim l_lineGetCallInfo_Result As Long
' Init Parameters..
l_Call = RMSTAPIRoutines.glhCall
' Set Memory needed...
struct_MyCallInfo.l_dwTotalSize = LINECALLINFO_FIXEDSIZE + LINECALLINFO_MEMSIZE
' Run lineGetCallInfo..
l_lineGetCallInfo_Result = RMSTAPIDeclarations.lineGetCallInfo(l_Call, struct_MyCallInfo)
Global Const LINECALLINFO_MEMSIZE = DEFAULT_SIZE
Type lineCallInfo
l_dwTotalSize As Long
l_dwNeededSize As Long
l_dwUsedSize As Long
l_hLine As Long
l_dwLineDeviceID As Long
l_dwAddressID As Long
l_dwBearerMode As Long
l_dwRate As Long
l_dwMediaMode As Long
l_dwAppSpecific As Long
l_dwCallID As Long
l_dwRelatedCallID As Long
l_dwCallParamFlags As Long
l_dwCallStates As Long
l_dwMonitorDigitModes As Long
l_dwMonitorMediaModes As Long
struct_DialParams As lineDialParams
l_dwOrigin As Long
l_dwReason As Long
l_dwCompletionID As Long
l_dwNumOwners As Long
l_dwNumMonitors As Long
l_dwCountryCode As Long
l_dwTrunk As Long
l_dwCallerIDFlags As Long
l_dwCallerIDSize As Long
l_dwCallerIDOffset As Long
l_dwCallerIDNameSize As Long
l_dwCallerIDNameOffset As Long
l_dwCalledIDFlags As Long
l_dwCalledIDSize As Long
l_dwCalledIDOffset As Long
l_dwCalledIDNameSize As Long
l_dwCalledIDNameOffset As Long
l_dwConnectedIDFlags As Long
l_dwConnectedIDSize As Long
l_dwConnectedIDOffset As Long
l_dwConnectedIDNameSize As Long
l_dwConnectedIDNameOffset As Long
l_dwRedirectionIDFlags As Long
l_dwRedirectionIDSize As Long
l_dwRedirectionIDOffset As Long
l_dwRedirectionIDNameSize As Long
l_dwRedirectionIDNameOffset As Long
l_dwRedirectingIDFlags As Long
l_dwRedirectingIDSize As Long
l_dwRedirectingIDOffset As Long
l_dwRedirectingIDNameSize As Long
l_dwRedirectingIDNameOffset As Long
l_dwAppNameSize As Long
l_dwAppNameOffset As Long
l_dwDisplayableAddressSize As Long
l_dwDisplayableAddressOffset As Long
l_dwCalledPartySize As Long
l_dwCalledPartyOffset As Long
l_dwCommentSize As Long
l_dwCommentOffset As Long
l_dwDisplaySize As Long
l_dwDisplayOffset As Long
l_dwUserUserInfoSize As Long
l_dwUserUserInfoOffset As Long
l_dwHighLevelCompSize As Long
l_dwHighLevelCompOffset As Long
l_dwLowLevelCompSize As Long
l_dwLowLevelCompOffset As Long
l_dwChargingInfoSize As Long
l_dwChargingInfoOffset As Long
l_dwTerminalModesSize As Long
l_dwTerminalModesOffset As Long
l_dwDevSpecificSize As Long
l_dwDevSpecificOffset As Long
l_dwCallTreatment As Long
l_dwCallDataSize As Long
l_dwCallDataOffset As Long
l_dwSendingFlowspecSize As Long
l_dwSendingFlowspecOffset As Long
l_dwReceivingFlowspecSize As Long
l_dwReceivingFlowspecOffset As Long
' >= TAPI 3.0... BEGIN
l_dwCallerIDAddressType As Long
l_dwCalledIDAddressType As Long
l_dwConnectedIDAddressType As Long
l_dwRedirectionIDAddressType As Long
l_dwRedirectingIDAddressType As Long
' >= TAPI 3.0... END
mem As String * LINECALLINFO_MEMSIZE
End Type
Global Const LINECALLINFO_FIXEDSIZE = 344
Declare Function lineGetCallInfo Lib "TAPI32.DLL" _
(ByVal l_hCall As Long, ptr_lpCallInfo As Any) As Long
C# 不允许我这样做(关于访问受保护内存的各种声明)。经过一些研究,似乎每个人都同意您需要将 IntPtr 传递给非托管函数,而不是 Struct 本身。从我想出这个代码的例子
struct_MyCallInfo.l_dwTotalSize = RMSTAPIDeclarations.LINECALLINFO_FIXEDSIZE + RMSTAPIDeclarations.LINECALLINFO_MEMSIZE;
System.IntPtr sPTR = Marshal.AllocHGlobal(Marshal.SizeOf(struct_MyCallInfo));
Marshal.StructureToPtr(struct_MyCallInfo, sPTR, true);
int l_lineGetCallInfo_Result = RMSTAPIEvents.lineGetCallInfo(l_Call, sPTR);
调用这个函数
[DllImport("TAPI32.DLL", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
extern public static int lineGetCallInfo(int l_hCall, System.IntPtr ptr_lpCallInfo);
有了这个结构
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct lineCallInfo
{
public int l_dwTotalSize;
public int l_dwNeededSize;
public int l_dwUsedSize;
public int l_hLine;
public int l_dwLineDeviceID;
public int l_dwAddressID;
public int l_dwBearerMode;
public int l_dwRate;
public int l_dwMediaMode;
public int l_dwAppSpecific;
public int l_dwCallID;
public int l_dwRelatedCallID;
public int l_dwCallParamFlags;
public int l_dwCallStates;
public int l_dwMonitorDigitModes;
public int l_dwMonitorMediaModes;
public lineDialParams struct_DialParams;
public int l_dwOrigin;
public int l_dwReason;
public int l_dwCompletionID;
public int l_dwNumOwners;
public int l_dwNumMonitors;
public int l_dwCountryCode;
public int l_dwTrunk;
public int l_dwCallerIDFlags;
public int l_dwCallerIDSize;
public int l_dwCallerIDOffset;
public int l_dwCallerIDNameSize;
public int l_dwCallerIDNameOffset;
public int l_dwCalledIDFlags;
public int l_dwCalledIDSize;
public int l_dwCalledIDOffset;
public int l_dwCalledIDNameSize;
public int l_dwCalledIDNameOffset;
public int l_dwConnectedIDFlags;
public int l_dwConnectedIDSize;
public int l_dwConnectedIDOffset;
public int l_dwConnectedIDNameSize;
public int l_dwConnectedIDNameOffset;
public int l_dwRedirectionIDFlags;
public int l_dwRedirectionIDSize;
public int l_dwRedirectionIDOffset;
public int l_dwRedirectionIDNameSize;
public int l_dwRedirectionIDNameOffset;
public int l_dwRedirectingIDFlags;
public int l_dwRedirectingIDSize;
public int l_dwRedirectingIDOffset;
public int l_dwRedirectingIDNameSize;
public int l_dwRedirectingIDNameOffset;
public int l_dwAppNameSize;
public int l_dwAppNameOffset;
public int l_dwDisplayableAddressSize;
public int l_dwDisplayableAddressOffset;
public int l_dwCalledPartySize;
public int l_dwCalledPartyOffset;
public int l_dwCommentSize;
public int l_dwCommentOffset;
public int l_dwDisplaySize;
public int l_dwDisplayOffset;
public int l_dwUserUserInfoSize;
public int l_dwUserUserInfoOffset;
public int l_dwHighLevelCompSize;
public int l_dwHighLevelCompOffset;
public int l_dwLowLevelCompSize;
public int l_dwLowLevelCompOffset;
public int l_dwChargingInfoSize;
public int l_dwChargingInfoOffset;
public int l_dwTerminalModesSize;
public int l_dwTerminalModesOffset;
public int l_dwDevSpecificSize;
public int l_dwDevSpecificOffset;
public int l_dwCallTreatment;
public int l_dwCallDataSize;
public int l_dwCallDataOffset;
public int l_dwSendingFlowspecSize;
public int l_dwSendingFlowspecOffset;
public int l_dwReceivingFlowspecSize;
public int l_dwReceivingFlowspecOffset;
// >= TAPI 3.0... BEGIN
public int l_dwCallerIDAddressType;
public int l_dwCalledIDAddressType;
public int l_dwConnectedIDAddressType;
public int l_dwRedirectionIDAddressType;
public int l_dwRedirectingIDAddressType;
// >= TAPI 3.0... END
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 2048)]//LINEDEVSTATUS_MEMSIZE)]
public char[] _mem;
public string mem
{
get
{
return new string(_mem);
}
set
{
CopyValueToArray(_mem, value);
}
}
public static lineCallInfo CreateInstance()
{
lineCallInfo result = new lineCallInfo();
result._mem = new char[2048];
return result;
}
}
这行得通……有点。它 returns 结果没有抛出错误,但它 returns 填充的结构完全是空的。它应该返回指示线路类型、媒体模式、呼叫者信息等关于呼叫的值,但我只是得到全 0。
有人有过与 TAPI 进行托管交互的经验吗?我在结构或封送处理过程中做错了什么吗?几乎所有我的其他函数调用都有效,包括一些我在下面进行相同封送处理的地方。这让我相信它可能与结构有关。
编组 TAPI 结构 to/from 托管代码非常棘手。 TAPI在结构之后将可变长度数据放入内存中,您必须使用结构的xxxOffset和xxxSize成员才能找出数据所在的位置。
我强烈建议使用适用于 .NET 的 TAPI 库,它可以为您完成所有这些棘手的工作。您有两个选择:商业 AddTapi.NET or open-source Julmar TAPI.