0

我想将一个 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 文件的一部分。

4

1 回答 1

0

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

不管你这样做是为了什么,听起来都很糟糕。但是,您可能会重新考虑您的方法以获得实际答案:

为了帮助您入门,这里有一些 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。Ps 如果您将 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 应该始终对任何人隐藏,这将非常有用。仅供参考-很难^_^

于 2013-11-14T20:33:10.323 回答