2014-01-16 45 views
0

有方法:如何防止分配一個出現「訪問衝突異常」的參數?

function Test.get_Param(out a : BOOL): HRESULT; stdcall; 
begin 
    a := b; 
    Result := T_Result; 
end; 

現在的例外發生在a := b;,發生訪問衝突異常。 當然,我可以嘗試並抓住它。但我不想這樣做...... 那麼有什麼方法可以確定使用某種方式,並跳過作業。像:

if (! now I know it will happening that Exception){ 
    a := b; // so I can skip 
} 
Result := T_Result; 

也許這很容易,但因爲我不知道使用德爾福,所以希望你們的人可以幫助我。謝謝。

UPDATE1:

b: Boolean;//Some friend need to know what is the b param type. 

UPDATE2:

我嘗試使用:

if b<> nil then Enabled := b; 

,但我不能建造它,它會顯示:E2008不相容的類型

UPDATE3:

我試圖調試它,當我調試,局部變量面板顯示屏上:

一個不可訪問值

我使用.NET稱之爲。有元數據:

bool get_Param{ [param: In, MarshalAs(UnmanagedType.Bool)] [PreserveSig] set; } 

實際上我沒有使用.NET訪問它。我使用.NET訪問一個DirectShow濾波器,而DirectShow過濾器是當前的方法(用Delphi寫)

UPDATE4:

這部分C#代碼

[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), SuppressUnmanagedCodeSecurity, Guid("hidden")] 
public interface IDCDSPFilterInterface{ 
    bool get_Param{ [param: In, MarshalAs(UnmanagedType.Bool)] [PreserveSig] set; } 
    ..   hidden other  .. 
}} 
+1

請注意SSCCE。 http://sscce.org/ – Roddy

+0

嗨@Roddy什麼地方你不明白? – qakmak

+0

你爲什麼要寫'如果b <> nil'? 'b'是你的'b'類型的變量。它不能是'nil',因爲它不是一個指針。 –

回答

1

有一個你的互操作邊界兩端嚴重不匹配。你的Delphi函數與C#聲明不匹配。

解決方案不是測試參數的有效性。給定函數的聲明,你的Delphi代碼是正確的。解決方法是使互操作邊界的兩邊匹配。除非你展示互操作邊界的兩邊,否則我不能告訴你更多。

+0

如果你展示了更多的C#端和更完整的Delphi列表,那麼我認爲我可以很快地清除錯配。 '[PreserveSig]'看起來與你的'HRESULT'返回類型不兼容。 –

+0

Hi @David Heffernan,我沒有發現任何C#代碼的問題。我看其他樣本,看起來像所有的界面寫的那樣,所以我仍然需要一些方法來知道異常會來...... – qakmak

+0

這將是很好的看到C#代碼。目前我們有一些元數據。你可以顯示C# –

2

我嘗試使用:

if b<> nil then Enabled := b; 

,但我不能建造它,它會顯示:E2008不兼容的類型

指針變量的ABC帕斯卡爾。http://en.wikipedia.org/wiki/Pascal_(programming_language)#Pointer_types

所以寫一個檢查的正確方法是

function Test.get_Param(out a : BOOL): HRESULT; stdcall; 
var ptr: ^BOOL; 
begin 
    ptr := @a; 
    if nil = ptr then .... 

    a := b; 
    Result := T_Result; 
end; 

那就是你明確的問題的基本問題。

現在,在現實中,檢查並沒有幫助。它只會保護你的nil/NULL指針,但這不可能發生。發生什麼可能是隨機垃圾指針而不是零。由於調用代碼錯誤。

再次,您可以通過var ptr: Pointer {untyped}; ptr := @Self; if ptr = nil then ...if nil <> Selfif Assigned(Self)來檢查 - 但這隻會保護您免受NIL指針,而不是從RANDOM GARBAGE指針保護您。

更多的話,我認爲實際的垃圾是不是在指針變量a,但指針Selfb正在試classm的一員,因此真正的聲明是a := Self.b;

由於您使用stdcall我認爲您正在嘗試使用非Delphi語言中的EXE進行使用的DLL。很可能你在該客戶端應用程序代碼中爲功能定義了錯誤的定義。其實,你只要做出正確的聲明就是你Test是一類。如果get_Param是RECORD Test的一種方法,或者如果它是Test類的STATIC CLASS方法,那麼您只能做出正確的選擇。所以編寫你的函數的正確方法將如下

function Test.get_Param(out a : BOOL): HRESULT; 
begin 
    a := b; 
    Result := T_Result; 
end; 

function DLL_get_Param(const TestObject: pointer; out a : BOOL): HRESULT; stdcall; 
var MyTest: Test; 
begin 
    pointer(MyTest) := TestObject; 

    Result := MyTest.DLL_get_Param(a); 
end; 

export DLL_get_Param; 

閱讀德爾福的文檔你可以得到/放入/從DLL函數。 IntegersfloatspointersIInterface。你不能傳入DLL複雜和行爲的對象,如蜇,動態數組,對象實例。由於您無法傳遞對象實例,因此無法傳遞Self變量,並且您無法調用方法。

一個非常昂貴的方式抓住它會像

{global} var TestInstances: TList; 
type 
    TEST = class... 

    procedure AfterConstructon; override; 
    procedure BeforeConstructon; override; 

.... 


procedure Test.AfterConstructon; 
begin 
    inherited; 
    TestInstances.Add(Self); // single-thread assumption here 
end; 

procedure Test.BeforeConstructon; 
begin 
    TestInstances.Remove(Self); // single-thread assumption here 
    inherited; 
end; 

function Test.get_Param(out a : BOOL): HRESULT; stdcall; 
begin 
    if not (TestInstances.IndexOf(Self) >= 0 {found!}) // single-thread assumption here 
    then ... WTF ??? 
    ... 

.... 

initialization  
    TestInstances := TList.Create; 
finalization 
    TestInstances.Free; 
end; 

如果你的DLL可以使用多線程應用程序,你也應該換標記的通話將http://docwiki.embarcadero.com/Libraries/XE2/en/System.SyncObjs.TCriticalSection

+0

'HRESULT'返回類型是一個巨大的線索。這是COM。 –

+0

@DavidHeffernan HResult類型被用在許多DLL中,而不僅僅是COM。另外,如果我們看到AV這樣的重大錯誤,那麼這意味着假設不成立。特別是像COM服務器和對象這樣的相當強大的假設被正確地聲明,正確初始化並正確傳遞。 –

+0

@ Arioch'The拒絕它,如果你喜歡。證據非常清楚。你認爲'[PreserveSig]'是什麼意思? –

1

既然不能看看你在哪裏decalred b,我會假設它是Test的成員。

所以一個很大的可能性是,你有一個無效的實例Test,並且你得到一個訪問衝突試圖讀取b爲了將它分配給a。作爲一個例子,get_Param的下列用法會引發異常。

var 
    LTest: Test; 
    LA: Boolean; 
begin 
    LTest := nil; 
    LTest.get_Param(LA); 
end; 

問題是你需要一個有效的Test實例才能使用它。例如。

var 
    LTest: Test; 
    LA: Boolean; 
begin 
    LTest := Test.Create; 
    try 
    LTest.get_Param(LA); 
    finally 
    LTest.Free; 
    end; 
end; 
+0

抱歉沒有告訴你b型。不管怎樣,謝謝你。 – qakmak

+0

這是一個COM對象。該對象不會以這種方式創建。 –