我試圖構建一個自定義解決方案來與我們的IP Office電話系統進行交互。我能夠找到並更新由我們的電話提供商Avaya提供的使用TAPI32.dll驅動程序的舊VB6 TAPI項目。然而,從VB6到.net的變化給我帶來了一些問題。其中最大的問題是舊代碼將一個Struct傳遞給DLL上的pinvoke函數。功能,結構和調用代碼如下所示(遺憾的長度):TAPI lineGetCallInfo返回空結果
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過程嗎?幾乎所有其他的函數調用都可以工作,其中包括我在下面做的同樣的編組。這導致我相信它可能與結構有關。