2017-08-30 56 views
2

我想在安裝期間在Inno安裝腳本中使用自定義DLL。我寫了一個非常簡單的函數,它基本上使用MySQL .NET連接器檢查MySQL數據庫的連接字符串(目標服務器上沒有MySQL客戶端)。這個導出函數的代碼是:Inno安裝程序 - 依賴關係的外部.NET DLL

public class DbChecker 
{ 
    [DllExport("CheckConnexion", CallingConvention.StdCall)] 
    public static int CheckConnexion([MarshalAs(UnmanagedType.LPStr)] string connexionString) 
    { 
     int success; 
     try 
     { 
      MySqlConnection connection = new MySqlConnection(connexionString); 
      connection.Open(); 
      connection.Close(); 
      success = 0; 
     } 
     catch (Exception) 
     { 
      success = 1; 
     } 
     return success; 
    } 
} 

功能導入這樣的Inno Setup的:

[Files] 
Source: "..\..\MyDll\bin\x86\Release\*"; Flags: dontcopy; 

[Code] 
function CheckConnexion(connexionString: AnsiString): Integer; 
external '[email protected]:MyDll.dll,MySql.Data.dll stdcall setuponly loadwithalteredsearchpath';` 

的問題是,設置拋出異常的運行時間:

運行時錯誤(at 53:207):

外部異常E0434352。

我想我必須使用files前綴,因爲函數被調用在NextButtonClick事件處理程序,之前的文件複製到{app}目錄。

在運行時將MyDll.dllMySql.Data.dll都正確提取到{tmp}目錄。

我試着用和不用loadwithalteredsearchpath標誌都有相同的結果。

我發現這個錯誤代碼是一個通用的.NET運行時錯誤代碼。

如果我刪除使用MySql.Data它工作完全正常(除了它什麼也不做......)

誠如其他線程上我一直在試圖將錯誤使用EventLog我的.NET代碼的一部分和UnhandledException,但是無論什麼(也沒有創建日誌源),我都有相同的異常,即使沒有MySQL部分也是如此。我在我的電腦上檢查了EventLog權限。

看來,只要我使用其他任何「基本」C#代碼(每當我嘗試加載另一個DLL)時,都會拋出異常。

+0

CheckConnexion在NextButtonClick事件處理程序中調用。 如果我沒有使用'MySql.Data'的第二個函數,它正在工作。純粹的參考似乎不是問題。 – tvarnier

+0

使用'File.WriteAllLines',調用沒有引用'MySql.Data'的函數,記錄並正確返回。使用'MySql.Data'的人在沒有記錄任何東西的情況下仍然以相同的方式失敗。 – tvarnier

+0

由於引用,'MySql.Data' dll被複制到'MyDll'的bin目錄中。整個目錄導入到我的原始文章中描述的'[files]'部分。 我可以在運行時看到在Inno-Setup臨時目錄中提取的'MySql.Data.dll'和'MyDll.dll'。 – tvarnier

回答

2

有可能是一種更好的方式,但是這樣做。

實現一個初始化函數(Init這裏),設置了AppDomain.AssemblyResolve處理程序查找一個裝配在主(執行)程序集的路徑:

[DllExport("Init", CallingConvention.StdCall)] 
public static void Init() 
{ 
    AppDomain currentDomain = AppDomain.CurrentDomain; 
    currentDomain.AssemblyResolve += new ResolveEventHandler(MyResolveEventHandler); 
} 

private static Assembly MyResolveEventHandler(object sender, ResolveEventArgs args) 
{ 
    string location = Assembly.GetExecutingAssembly().Location; 
    AssemblyName name = new AssemblyName(args.Name); 
    string path = Path.Combine(Path.GetDirectoryName(location), name.Name + ".dll"); 
    if (File.Exists(path)) 
    { 
     return Assembly.LoadFrom(path); 
    } 
    return null; 
} 

其導入到Inno Setup的:

procedure Init(); external '[email protected]:MyDll.dll stdcall setuponly'; 

在調用需要依賴項的函數之前調用它(CheckConnexion)。


另一種解決方案可能是這樣的:
Embedding DLLs in a compiled executable


順便說一句,沒有必要爲loadwithalteredsearchpath標誌。它對.NET組件imo沒有影響。

+0

這個伎倆!我確實看到了這裏的邏輯,但是我們必須這樣做,這是一種恥辱,尤其是在Windows ^^上。似乎IDD,'loadwithalteredsearchpath'標誌不適用於.NET程序集。非常感謝 ! – tvarnier

+0

完成:)順便說一句,我試圖嵌入當時的dll。它在我的開發計算機上工作,但不在CI服務器上,因爲Costura是爲.NET 4.5.x編譯的,而且似乎.NET 4和4.5編譯器具有接口差異。這就是爲什麼我不得不直接引用'MySql.Data'。但是這個解決方法是簡單架構上的一個很好的解決方案。 – tvarnier