كيفية ربط libs 32 بت/64 بت في وقت متأخر في وقت التشغيل

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

  •  09-06-2019
  •  | 
  •  

سؤال

لدي مشكلة مشابهة للمشكلة الموصوفة ولكنها مختلفة عنها تمامًا هنا (تحميل التجميعات وتبعياتها).

لدي ملف C++ DLL للعرض ثلاثي الأبعاد وهو ما نبيعه للعملاء.بالنسبة لمستخدمي .NET، سيكون لدينا غلاف CLR حوله.يمكن إنشاء C++ DLL في كلا الإصدارين 32 و64 بت، ولكن أعتقد أن هذا يعني أننا بحاجة إلى غلافي CLR نظرًا لأن CLR يرتبط بملف DLL محدد؟

لنفترض الآن أن عميلنا لديه تطبيق .NET يمكن أن يكون إما 32 أو 64 بت، ولأنه تطبيق .NET خالص فإنه يترك CLR للعمل عليه من مجموعة واحدة من التجميعات.والسؤال هو كيف يمكن لرمز التطبيق الاختيار ديناميكيًا بين مجموعات CLR/DLL 32 و64 بت في وقت التشغيل؟

وبشكل أكثر تحديدًا، هل الإجابة المقترحة على السؤال المذكور أعلاه تنطبق هنا أيضًا (أي:إنشاء معالج ResolveEvent)؟

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

المحلول

أخيرًا لدي إجابة لهذا يبدو أنها تعمل.

قم بتجميع الإصدارين 32 و64 بت - المُدار وغير المُدار - في مجلدات منفصلة.ثم اطلب من تطبيق .NET أن يختار في وقت التشغيل الدليل الذي سيتم تحميل التجميعات منه.

المشكلة في استخدام ResolveEvent هي أنه يتم استدعاؤه فقط في حالة عدم العثور على التجميعات، لذلك من السهل أن ينتهي الأمر بطريق الخطأ بإصدارات 32 بت.بدلاً من ذلك، استخدم كائن AppDomain ثانيًا حيث يمكننا تغيير خاصية ApplicationBase للإشارة إلى المجلد الصحيح.لذلك ينتهي بك الأمر برمز مثل:

static void Main(String[] argv)
  {
     // Create a new AppDomain, but with the base directory set to either the 32-bit or 64-bit
     // sub-directories.

     AppDomainSetup objADS = new AppDomainSetup();

     System.String assemblyDir = System.IO.Path.GetDirectoryName(Application.ExecutablePath);
     switch (System.IntPtr.Size)
     {
        case (4): assemblyDir += "\\win32\\";
           break;
        case (8): assemblyDir += "\\x64\\";
           break;
     }

     objADS.ApplicationBase = assemblyDir;

     // We set the PrivateBinPath to the application directory, so that we can still
     // load the platform neutral assemblies from the app directory.
     objADS.PrivateBinPath = System.IO.Path.GetDirectoryName(Application.ExecutablePath);

     AppDomain objAD = AppDomain.CreateDomain("", null, objADS);
     if (argv.Length > 0)
        objAD.ExecuteAssembly(argv[0]);
     else
        objAD.ExecuteAssembly("MyApplication.exe");

     AppDomain.Unload(objAD);

  }

ينتهي بك الأمر مع ملفين exes - تطبيقك العادي وتطبيق تبديل ثانٍ يختار البتات التي سيتم تحميلها.ملاحظة - لا يمكنني الحصول على الفضل في تفاصيل هذا الأمر بنفسي.أحد زملائي استنتج ذلك بالنظر إلى مؤشري الأولي.إذا قام بالتسجيل في StackOverflow وعندما يقوم بذلك، فسوف أقوم بتعيين الإجابة له

نصائح أخرى

لقد تمكنت من القيام بذلك منذ عام تقريبًا، لكني لم أعد أتذكر كل التفاصيل.بشكل أساسي، يمكنك استخدام IntPtr.Size لتحديد ملف DLL المراد تحميله، ثم تنفيذ LoadLibrary الفعلي من خلال p/Invoc.عند هذه النقطة، تكون لديك الوحدة في الذاكرة ويجب أن تكون قادرًا فقط على استدعاء وظائف p/Invoc من داخلها - ولا ينبغي إعادة تحميل اسم الوحدة نفسه مرة أخرى.

على الرغم من ذلك، أعتقد أنه في تطبيقي قمت بالفعل بتسجيل C++ DLL كخادم COM ثم قمت بالوصول إلى وظائفه من خلال غلاف .NET الذي تم إنشاؤه - لذلك لا أعرف ما إذا كنت قد اختبرت p/Invocing مباشرة.

لقد واجهت سيناريو مماثل منذ فترة.مجموعة الأدوات التي كنت أستخدمها لم تكن تعمل بشكل جيد في بيئة 64 بت ولم أتمكن من إيجاد طريقة لإجبار التجميعات ديناميكيًا على الارتباط بـ 32 بت.

من الممكن إجبار التجميعات الخاصة بك على العمل في وضع 32 بت، ولكن هذا يتطلب تصحيح رأس CLR، (توجد أداة تفعل ذلك في إطار العمل) وإذا كانت التجميعات الخاصة بك ذات أسماء قوية، فلن ينجح هذا.

أخشى أنك ستحتاج إلى إنشاء ونشر مجموعتين من الثنائيات لمنصات 32 و64 بت.

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