如何在运行时指定[DllImport]路径(嵌入.msi文件中)

时间:2013-11-14 06:27:55

标签: c# wix windows-installer dllimport custom-action

我想将一个dll导入到我的C#项目中,使用DllImport调用它的函数。 我的dll需要作为我的.msi文件的一部分导入。

当我指定DLL的完整路径时,它确实有效,但这是在.msi文件之外。


我正面临dllNotFoundException问题。

<Binary Id="CustomAction2.CA.dll"
src="../artifacts/CustomAction2.CA.dll" />

<CustomAction Id="Install"                
        Execute="deferred"
        BinaryKey="CustomAction2.CA.dll" 
        DllEntry="CustomAction1" />

<CustomAction Id="InstallWithProperty"
        Property="Install"
        Value="location=[DEFAULT_INSTALLDIR]$FULL_NAME;name=myDll.dll" 
        Execute="immediate"/>

<InstallExecuteSequence>      
  <Custom Action="InstallWithProperty" After="InstallFiles"/>
  <Custom Action="Install" After="InstallWithProperty" />
</InstallExecuteSequence>

调用自定义操作时,它说 我得到以下异常

Exception thrown by custom action: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.DllNotFoundException: Unable to load DLL 'myDll.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E) at CustomAction2.CustomActions.ConfigDriver(IntPtr hwndParent, UInt16 fRequest, String lpszDriver, String lpszArgs, String lpszMsg, UInt16 cbMsgMax, Int64& pcbMsgOut) at CustomAction2.CustomActions.CustomAction1(Session session) --- End of inner exception stack trace --- at System.RuntimeMethodHandle._InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeType typeOwner) at System.RuntimeMethodHandle.InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object arguments, Signature sig, MethodAttributes methodAttributes, RuntimeType typeOwner) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object parameters, CultureInfo culture, Boolean skipVisibilityChecks) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object parameters, CultureInfo culture) at Microsoft.Deployment.WindowsInstaller.CustomActionProxy.InvokeCustomAction(Int32 sessionHandle, String entryPoint, IntPtr remotingDelegatePtr) CustomAction Install returned actual error code 1603 (note this may not be 100% accurate if translation happened inside sandbox)

有人可以提供帮助吗?我想使用myDll.dll进行进一步安装,这是.msi文件的一部分。

1 个答案:

答案 0 :(得分:0)

如果我理解正确,你有MSI文件里面有.DLL,你想要发送它吗?

无论你做什么,听起来都不错。你可能会重新思考你的方法, 但是,对于一个实际的答案:

为了帮助您入门,这里有一些C#代码:

String inputFile = @"C:\\Install1.msi";
            // Get the type of the Windows Installer object 
            Type installerType = Type.GetTypeFromProgID("WindowsInstaller.Installer");

            // Create the Windows Installer object 
            WindowsInstaller.Installer installer = (WindowsInstaller.Installer)Activator.CreateInstance(installerType);

            // Open the MSI database in the input file 
            Database database = installer.OpenDatabase(inputFile, MsiOpenDatabaseMode.msiOpenDatabaseModeReadOnly);

            // Open a view on the Property table for the version property 
            View view = database.OpenView("SELECT * FROM Property WHERE Property = 'ProductVersion'");

            // Execute the view query 
            view.Execute(null);

            // Get the record from the view 
            Record record = view.Fetch();

            // Get the version from the data 
            string version = record.get_StringData(2);

现在请注意,它不会从MSI中提取文件,但这是一个好的开始。为了从MSI中实际提取,您需要稍微更改一下代码。

这是执行此操作的VB代码,请注意SQL语法,如查询。

 Function ExtractIcon(IconName, OutputFile) 

                Const msiReadStreamAnsi = 2 



                Dim oDatabase 

                Set oDatabase = Session.Database 



                Dim View 

                Set View = oDatabase.OpenView("SELECT * FROM Icon WHERE 
Name = '" &amp; IconName &amp; "'") 

                View.Execute 



                Dim Record 

                Set Record = View.Fetch 

                Dim BinaryData 



                BinaryData = Record.ReadStream(2, Record.DataSize(2), 
msiReadStreamAnsi) 



                Dim FSO 

                Set FSO = CreateObject("Scripting.FileSystemObject") 

                Dim Stream 

                Set Stream = FSO.CreateTextFile(OutputFile, True) 

                Stream.Write BinaryData 

                Stream.Close 

                Set FSO = Nothing 

            End Function 

你需要将它转换为C#,这将是一件容易的事。 之后,您需要实际使用动态pInvoke。如果将DLL解压缩到项目文件夹中,并使用相对路径,也可以使用普通的pInvoke。

使用动态pInvoke:

按照这篇文章; http://blogs.msdn.com/b/jmstall/archive/2007/01/06/typesafe-getprocaddress.aspx

这是一个很简洁的代码:

 using(UnmanagedLibrary lib = new UnmanagedLibrary("kernel32")  // becomes call to LoadLibrary
   { 
      Action<String> function = lib.GetUnmanagedFunction<Action<String>>("DeleteFile"); // GetProcAddress
      function(@"c:\tmp.txt");
   } // implict call to lib.Dispose, which calls FreeLibrary.

如果您觉得自己像上帝,可以将DLL加载到内存中,而不是在任何地方提取它。如果您拥有应始终对任何人隐藏的令人惊叹的DLL,这将非常有用。这只是为了获取信息 - 这很难^ _ ^