Mam aplikację zbudowaną jako "Dowolny procesor" i dwie biblioteki DLL innych firm z tej samej biblioteki kierowane na x86 i x64. Chciałbym dołączyć jedną z tych bibliotek w czasie wykonywania, w zależności od platformy, którą uruchomiłaby na komputerze klienta. Jaki byłby najlepszy sposób, aby to osiągnąć?Załaduj bibliotekę x64 lub x86 w zależności od platformy?
Odpowiedz
Jeśli mówimy o niezarządzanych DLL, deklaruje p/wywołuje tak:
[DllImport("DllName.dll")]
static extern foo();
pamiętać, że nie są podając ścieżkę do biblioteki DLL, tylko jego nazwa, która przypuszczam jest taka sama dla zarówno wersje 32-, jak i 64-bitowe.
Następnie, zanim zadzwonisz do któregokolwiek z twoich p/invokes, załaduj bibliotekę do swojego procesu. Zrób to przez p/wywołanie funkcji API LoadLibrary
. W tym momencie ustalisz, czy Twój proces jest 32- czy 64-bitowy i odpowiednio zbudujesz pełną ścieżkę do biblioteki DLL. Ta pełna ścieżka jest przekazywana do LoadLibrary
.
Teraz, gdy wywołasz swoje p/invokes dla biblioteki, zostaną one rozwiązane przez moduł, który właśnie załadowałeś.
Dla zarządzanych złożeń można użyć Assembly.LoadFile
, aby określić ścieżkę zespołu. Może to być trochę trudne do orkiestracji, ale ten znakomity artykuł pokazuje, jak: Automatically Choose 32 or 64 Bit Mixed Mode DLLs. Jest wiele szczegółów dotyczących trybu mieszanego i rodzimych zależności DLL, które prawdopodobnie nie są dla ciebie istotne. Kluczem jest obsługa zdarzeń AppDomain.CurrentDomain.AssemblyResolve
.
Bardzo fajnie. Nie wiedziałem tego. – Ani
Dzięki David, Czy muszę utworzyć wrapper wokół istniejących bibliotek dll, ponieważ metody, które muszę uzyskać dostęp nie są statyczne?. – Ammark
Czy używasz 'DllImport' teraz, gdy wywołujesz swój kod podczas kompilacji tak jak x86 lub tylko x64? –
Jestem właściwie doświadczony w tym temacie, więc pomyślałem, że opublikuję odpowiedź zgodnie ze sposobem, w jaki używałem Pencil.Gaming. Po pierwsze musisz "DllImport
" "dwie funkcje, jedna z 32-bitowej biblioteki dll i jedna z 64-bitowej biblioteki DLL (lub tak, lub dylib, niezależnie od używanej platformy).
static class Foo32 {
[DllImport("32bitdll.dll")]
internal static extern void Foo();
}
static class Foo64 {
[DllImport("64bitdll.dll")]
internal static extern void Foo();
}
Następnie trzeba klasę pośrednią zawierającą delegatów i importowanie ich z 32 lub 64-bitowej współdziałanie w zależności od rozmiaru IntPtr
(nie używam Environment.Is64BitProcess
, ponieważ jest to funkcja .NET 4) :
internal delegate void FooDelegate();
static class FooDelegates {
internal static FooDelegate Foo;
static FooDelegates() {
Type interop = (IntPtr.Size == 8) ? typeof(Foo64) : typeof(Foo32);
FieldInfo[] fields = typeof(FooDelegates).GetFields(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
foreach (FieldInfo fi in fields) {
MethodInfo mi = glfwInterop.GetMethod(fi.Name, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
Delegate function = Delegate.CreateDelegate(fi.FieldType, mi);
fi.SetValue(null, function);
}
}
}
I wtedy zazwyczaj używają "prawdziwe" klasy, zawierający funkcję importowane (choć nie jest to technicznie wymagane):
public static class FooApi {
public static void Foo() {
FooDelegates.Foo();
}
}
To jest prawdziwy problem, jeśli potrzebujesz tylko jednej lub dwóch funkcji, ale sposób importowania delegatów jest naprawdę skuteczny w przypadku większych bibliotek/aplikacji. Możesz sprawdzić Pencil.Gaming na github, ponieważ używa tej metody dość szeroko (here jest przykładem tego, że jest często używany).
Inną zaletą tej metody jest to, że jest w 100% wieloplatformowy i nie polega na żadnych funkcjach WinAPI.
Nie potrzebujesz żadnych delegatów. Możesz zrobić to wszystko za pomocą zwykłego "DllImport" dla wszystkich importowanych funkcji. –
@DavidHeffernan Ale wtedy nie możesz użyć "Any CPU". Będziesz wówczas potrzebował redystrybuować oddzielne wersje aplikacji dla systemów 32- i 64-bitowych. – antonijn
Pewnie możesz użyć AnyCPU. Moja odpowiedź wyjaśnia, w jaki sposób. Potrzebujesz bibliotek DLL, które mają taką samą nazwę, ale pamiętaj o różnych folderach. Ale jest to normalne w przypadku bibliotek DLL z 32/64 bitowością. –
Moim kompletnym rozwiązaniem mojego problemu było użycie drugiego linku dostarczonego przez Davida Heffernana. To, co zrobiłem, to 1. Przywoływano podręczną bibliotekę DLL w projekcie. 2. Określone dwa zdarzenia pre-build
xcopy /y "$(SolutionDir)\Assemblies\Lib\x86\(Assembly name)*" "$(TargetDir)"
xcopy /y "$(SolutionDir)\Assemblies\Lib\x64\(Assemble name)*" "$(TargetDir)"
3. i uruchamiania aplikacji w przypadku resolve zespół zmienił odpowiedni montaż w zależności od platformy.
var currentDomain = AppDomain.CurrentDomain;
var location = Assembly.GetExecutingAssembly().Location;
var assemblyDir = Path.GetDirectoryName(location);
if (assemblyDir != null && (File.Exists(Path.Combine(assemblyDir, "(Assembly name).proxy.dll"))
|| !File.Exists(Path.Combine(assemblyDir, "(Assembly name).x86.dll"))
|| !File.Exists(Path.Combine(assemblyDir, "(Assembly name).x64.dll"))))
{
throw new InvalidOperationException("Found (Assembly name).proxy.dll which cannot exist. "
+ "Must instead have (Assembly name).x86.dll and (Assembly name).x64.dll. Check your build settings.");
}
currentDomain.AssemblyResolve += (sender, arg) =>
{
if (arg.Name.StartsWith("(Assembly name),", StringComparison.OrdinalIgnoreCase))
{
string fileName = Path.Combine(assemblyDir,
string.Format("(Assembly).{0}.dll", (IntPtr.Size == 4) ? "x86" : "x64"));
return Assembly.LoadFile(fileName);
}
return null;
};
To jednak działa tylko dla bibliotek .net, nie dla żadnego dll – Tyron
- 1. Zmień kod C# DllImport cel w zależności od x64/x86
- 2. Setuptools specyficzne zależności od platformy
- 3. Używanie biblioteki dll x64 w aplikacji x86
- 4. Rozwiązywanie zależności Maven inaczej, jeśli JVM w użyciu jest x86 lub x64?
- 5. x86/x64 Dodaj Przesunięcie adresowania
- 6. x64 względy wydajności x86 .Net
- 7. Obsługa nierozwiązanych zależnych od platformy zależności w biodiodzie
- 8. Uruchom MSI x86 lub x64 z MSBuild bootstrapper
- 9. Załaduj bibliotekę do modelu w CodeIgniter
- 10. Najbardziej standardowy sposób wyboru nazwy funkcji w zależności od platformy?
- 11. przełączanie masowe między x64 x86 w projektach konfiguracji
- 12. Kompilowanie pliku binarnego C# .NET x64 w systemie x86
- 13. C++ Załaduj bibliotekę DLL z podkatalogu?
- 14. TVarData Różnice między x86 i x64 Delphi
- 15. x86 Usługa zdalnego debugowania na x64
- 16. Linux x86/x64: Wyłącz błędne ustawienia danych
- 17. Czy chipy x86/x64 nadal używają mikroprogramowania?
- 18. SWT x64 z xulrunner 3.6.28 x86
- 19. Entity Framework spinup znacznie wolniej na x64 vs x86
- 20. Dodawanie bibliotek x86 i x64 do pakietu NuGet
- 21. Włącz zależne od platformy zależności Java (bez podpalania włosów).
- 22. Uruchomienie programu WinForm 10x wolniej pod x64 względem x86
- 23. Załaduj bibliotekę DLL częściej niż raz?
- 24. Jak uzyskać różne zależności w zależności od rodziny OS
- 25. Próbuję nie potrzebować dwóch oddzielnych rozwiązań dla programu x86 i x64
- 26. Skonfiguruj środowisko ASP.NET do używania x86 w systemie x64 Windows
- 27. Jak radzić sobie z pakietów x86 vs x64
- 28. Console.WriteLine działa na x86 x64, ale nie mam
- 29. Załaduj bibliotekę, przekazując parametr do konstruktora w codeigniter
- 30. jaki jest związek nazwy "projektu win32" w visual studio z platformą x86 lub x64
Czy to zarządzane zespoły lub kod natywny? –
Dlaczego nie chcesz po prostu tworzyć wersji x86 i x64 swojej aplikacji? – outcoldman
Chciałbym powiedzieć, że są one mieszane. Odkompilowanie ich dało mi dużo kodu napisanego w C, ale wciąż nie jestem pewien. – Ammark