2013-11-14 2 views
0

Я хочу импортировать dll в свой проект C# для вызова его функций с помощью DllImport. У меня есть dll, который нужно импортировать как часть моего .msi-файла.Как указать путь [DllImport] во время выполнения (встроенный внутри .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.

ответ

0

Если вы правильно поняли, у вас есть файл MSI, в котором есть .DLL, и вы хотите его вывести?

Что бы вы ни делали это, это звучит плохо. Вы можете rehink своего подхода, однако, фактический ответ:

Для начала, вот немного 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 вы также можете использовать обычный pInvoke, если вы извлекаете DLL в свою папку проектов и используете относительные пути.

Чтобы использовать динамический 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, которая всегда должна быть скрыта от кого-либо. Это только для информации - это довольно сложно^_^

+0

Смежные вопросы