TAPI lineGetCallInfo返回空结果

时间:2015-05-04 21:59:30

标签: c# struct vb6 marshalling tapi

我尝试构建自定义解决方案以与我们的IP Office电话系统进行交互。我能够找到并更新由我们的电话提供商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;
        }
    }

这有点......它返回结果而不抛出错误,但它返回的填充结构完全为空。它应该是返回值,表示有关呼叫的线路类型,媒体模式,呼叫者信息等,但我只是得到所有0。

有没有人有与TAPI进行托管互动的经验?我对Struct或Marshaling流程有什么问题吗?几乎所有我的其他函数调用都有效,包括我在下面执行相同编组操作的一些函数。这让我相信它可能与结构有关。

1 个答案:

答案 0 :(得分:0)

对托管代码进行封送TAPI结构非常棘手。 TAPI在结构之后将可变长度数据放入内存中,您必须使用结构的xxxOffset和xxxSize成员来查找数据的位置。

我强烈建议使用适用于.NET的TAPI库,为您完成所有这些棘手的操作。您有两种选择:商业AddTapi.NET或开源Julmar TAPI