تستخدم جنبا إلى جنب الجمعيات لتحميل x64 أو x32 إصدار DLL

StackOverflow https://stackoverflow.com/questions/108971

  •  01-07-2019
  •  | 
  •  

سؤال

لدينا نسختين من مدارة C++ الجمعية ، واحدة x86 و واحد إلى x64.هذه الجمعية تسمى من قبل .صافي تطبيق الامتثال بالنسبة AnyCPU.نحن نشر مدونة طريق نسخ ملف تثبيت ، وأود أن تواصل القيام بذلك.

هل من الممكن أن تستخدم جنبا إلى جنب الجمعية يعبر إلى تحميل x86 أو x64 الجمعية على التوالي عند تطبيق حيوي اختيار المعالج العمارة ؟ أو أن هناك طريقة أخرى للحصول على هذا عمله في ملف نسخ النشر (مثلا ، لا تستخدم GAC)?

هل كانت مفيدة؟

المحلول

أنا خلقت حل بسيط التي هي قادرة على تحميل منصة محددة الجمعية من قابل للتنفيذ جمعت كما AnyCPU.التقنية المستخدمة يمكن تلخيصها على النحو التالي:

  1. تأكد الافتراضي .صافي الجمعية آلية التحميل ("الانصهار" المحرك) لا يمكن أن تجد إما إلى x86 أو x64 نسخة من منصة محددة الجمعية
  2. قبل التطبيق الرئيسية محاولات تحميل منصة محددة الجمعية تثبيت مخصص الجمعية محلل في التيار AppDomain
  3. الآن عندما الرئيسية التطبيق يحتاج منصة محددة الجمعية ، الانصهار المحرك سوف تتخلى (لأنه من الخطوة 1) و اتصل محلل مخصص (لأنه من الخطوة 2);في محلل مخصص نحدد الأساسي الحالي و استخدام الدليل القائم على البحث تحميل DLL المناسبة.

تثبت هذه التقنية ، أرفق قصير سطر الأوامر القائمة التعليمي.أنا اختبرت الناتجة الثنائيات على ويندوز XP x86 ثم Vista SP1 x64 (عن طريق نسخ الثنائيات على مثل النشر).

ملاحظة 1:"csc.exe" هو C-sharp مترجم.ويفترض هذا البرنامج التعليمي هو في المسار الخاص بك (بلدي التجارب تم استخدام "C:\WINDOWS\Microsoft.NET\Framework\v3.5\csc.exe")

ملاحظة 2:أنصحك إنشاء مجلد مؤقت على اختبارات تشغيل سطر الأوامر (أو powershell) والتي دليل العمل الحالي هو تعيين إلى هذا الموقع على سبيل المثال

(cmd.exe)
C:
mkdir \TEMP\CrossPlatformTest
cd \TEMP\CrossPlatformTest

الخطوة 1:منصة محددة ممثلة في الجمعية بسيطة C# مكتبة الفئة:

// file 'library.cs' in C:\TEMP\CrossPlatformTest
namespace Cross.Platform.Library
{
    public static class Worker
    {
        public static void Run()
        {
            System.Console.WriteLine("Worker is running");
            System.Console.WriteLine("(Enter to continue)");
            System.Console.ReadLine();
        }
    }
}

الخطوة 2:نحن تجميع منصة محددة الجمعيات بسيطة باستخدام سطر الأوامر:

(cmd.exe from Note 2)
mkdir platform\x86
csc /out:platform\x86\library.dll /target:library /platform:x86 library.cs
mkdir platform\amd64
csc /out:platform\amd64\library.dll /target:library /platform:x64 library.cs

الخطوة 3:البرنامج الرئيسي هو تنقسم إلى قسمين."الإطلاق" يحتوي على نقطة الدخول الرئيسية القابل للتنفيذ و يسجل مخصص الجمعية محلل الحالي في appdomain:

// file 'bootstrapper.cs' in C:\TEMP\CrossPlatformTest
namespace Cross.Platform.Program
{
    public static class Bootstrapper
    {
        public static void Main()
        {
            System.AppDomain.CurrentDomain.AssemblyResolve += CustomResolve;
            App.Run();
        }

        private static System.Reflection.Assembly CustomResolve(
            object sender,
            System.ResolveEventArgs args)
        {
            if (args.Name.StartsWith("library"))
            {
                string fileName = System.IO.Path.GetFullPath(
                    "platform\\"
                    + System.Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE")
                    + "\\library.dll");
                System.Console.WriteLine(fileName);
                if (System.IO.File.Exists(fileName))
                {
                    return System.Reflection.Assembly.LoadFile(fileName);
                }
            }
            return null;
        }
    }
}

"البرنامج" هو "الحقيقي" تنفيذ التطبيق (ملاحظة هذا التطبيق.تشغيل تم الاستناد في نهاية الإطلاق.الرئيسية):

// file 'program.cs' in C:\TEMP\CrossPlatformTest
namespace Cross.Platform.Program
{
    public static class App
    {
        public static void Run()
        {
            Cross.Platform.Library.Worker.Run();
        }
    }
}

الخطوة 4:ترجمة التطبيق الرئيسي على سطر الأوامر:

(cmd.exe from Note 2)
csc /reference:platform\x86\library.dll /out:program.exe program.cs bootstrapper.cs

الخطوة 5:نحن الآن انتهى.بنية الدليل أنشأنا يجب أن تكون على النحو التالي:

(C:\TEMP\CrossPlatformTest, root dir)
    platform (dir)
        amd64 (dir)
            library.dll
        x86 (dir)
            library.dll
    program.exe
    *.cs (source files)

إذا كان يمكنك الآن تشغيل program.exe على 32bit منصة ، platform\x86\library.dll سيتم تحميلها ، إذا قمت بتشغيل program.exe على 64bit منصة ، platform\amd64\library.dll سيتم تحميل.علما أن أضفت وحدة التحكم.ReadLine() في نهاية العامل.طريقة تشغيل بحيث يمكنك استخدام "إدارة المهام" /عملية اكسبلورر للتحقيق تحميل Dll, أو يمكنك استخدام Visual Studio/المصحح ويندوز إرفاق إلى عملية لرؤية الاستدعاءات.... الخ

عندما program.exe تشغيل عادتنا الجمعية محلل تعلق الحالي appdomain.في أقرب وقت .صافي يبدأ تحميل برنامج الصف, فإنه يرى الاعتماد على 'مكتبة الجمعية ، لذلك يحاول تحميله.ومع ذلك ، لا يوجد مثل هذه الجمعية وجدت (لأننا خفية في منصة/* الدلائل).لحسن الحظ, لدينا محلل مخصص يعرف الخداع و بناء على النظام الأساسي الحالي يحاول التحميل الجمعية من المناسب منصة/* فرعي.

نصائح أخرى

نسختي ، على غرار @ميلان, ولكن مع العديد من التغييرات الهامة:

  • يعمل على جميع ملفات Dll التي لم يتم العثور عليها
  • يمكن تشغيل وإيقاف
  • AppDomain.CurrentDomain.SetupInformation.ApplicationBase يستخدم بدلا من Path.GetFullPath() لأن الدليل الحالي قد تكون مختلفة ، على سبيل المثالفي استضافة سيناريوهات Excel قد تحميل البرنامج المساعد الخاص بك ولكن الدليل الحالي لن يكون DLL الخاص بك.

  • Environment.Is64BitProcess يستخدم بدلا من PROCESSOR_ARCHITECTURE, كما يجب أن لا تعتمد على أي نظام التشغيل ، بل كيف بدأت عملية - كان يمكن أن يكون x86 العملية على إلى x64 من نظام التشغيل.قبل .صافي 4, استخدام IntPtr.Size == 8 بدلا من ذلك.

استدعاء هذا الرمز في منشئ ثابت من بعض الرئيسي الدرجة التي يتم تحميلها قبل كل شيء آخر.

public static class MultiplatformDllLoader
{
    private static bool _isEnabled;

    public static bool Enable
    {
        get { return _isEnabled; }
        set
        {
            lock (typeof (MultiplatformDllLoader))
            {
                if (_isEnabled != value)
                {
                    if (value)
                        AppDomain.CurrentDomain.AssemblyResolve += Resolver;
                    else
                        AppDomain.CurrentDomain.AssemblyResolve -= Resolver;
                    _isEnabled = value;
                }
            }
        }
    }

    /// Will attempt to load missing assembly from either x86 or x64 subdir
    private static Assembly Resolver(object sender, ResolveEventArgs args)
    {
        string assemblyName = args.Name.Split(new[] {','}, 2)[0] + ".dll";
        string archSpecificPath = Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
                                               Environment.Is64BitProcess ? "x64" : "x86",
                                               assemblyName);

        return File.Exists(archSpecificPath)
                   ? Assembly.LoadFile(archSpecificPath)
                   : null;
    }
}

إلقاء نظرة على SetDllDirectory.أنا استخدامها في جميع أنحاء حيوي التحميل من IBM spss الجمعية لكل x64 و x86.كما حل مسارات عدم دعم الجمعية dll تحميلها من قبل الجمعيات في حالتي كان الحال مع spss dll.

http://msdn.microsoft.com/en-us/library/ms686203%28VS.85%29.aspx

يمكنك استخدام corflags أداة لفرض AnyCPU exe لتحميل باعتبارها x86 أو x64 قابل للتنفيذ, ولكن هذا لا تلبي تماما ملف نسخ النشر شرط إلا إذا اخترت والتي exe إلى نسخ استنادا إلى الهدف.

هذا الحل يمكن أن تعمل على عدم تمكن الجمعيات أيضا.لقد خلق مثال بسيط على غرار ميلان Gardian هو مثال عظيم.على سبيل المثال أنا التي تم إنشاؤها بشكل حيوي تحميل مدارة C++ dll في C# dll جمعت أي منصة وحدة المعالجة المركزية.الحل يجعل من استخدام InjectModuleInitializer nuget حزمة الاشتراك AssemblyResolve الحدث قبل تبعيات الجمعية يتم تحميلها.

https://github.com/kevin-marshall/Managed.AnyCPU.git

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top