سؤال

هذا السؤال هو ذات الصلة "كيفية جعل متسقة dll الثنائيات عبر VS الإصدارات؟"

  • لدينا تطبيقات و ملفات Dll بنيت مع VC6 و تطبيق جديد بنيت مع VC9.على VC9-التطبيق لاستخدام DLLs جمعت مع VC6 معظم التي هي مكتوبة في ج و واحد في C++.
  • C++ lib إشكالية بسبب اسم الديكور/تغيير اسم القضايا.
  • تجميع كل شيء مع VC9 هو حاليا ليس خيارا هناك تظهر بعض الآثار الجانبية.حل هذه ستكون المرة طويلا.
  • لا يمكن تعديل C++ مكتبة, ومع ذلك يجب تجميعها مع VC6.
  • C++ ليب هو أساسا OO-المجمع آخر ج المكتبة.على VC9-التطبيق يستخدم بعض وظائف ثابتة فضلا عن بعض غير ثابت.

في حين أن وظائف ثابتة يمكن التعامل مع شيء من هذا القبيل

// Header file
class DLL_API Foo
{
    int init();
}

extern "C"
{
    int DLL_API Foo_init();
}

// Implementation file
int Foo_init()
{
    return Foo::init();
}

فإنه ليس من السهل مع عدم أساليب ثابتة.

كما أفهم ، كريس Becke هو اقتراح باستخدام COM-مثل واجهة لن يساعدني لأن واجهة أسماء الأعضاء سوف لا يزال تكون مزينة وبالتالي لا يمكن الوصول إليها من الثنائية التي تم إنشاؤها مع مختلف مترجم. هل أنا هناك ؟

أن الحل الوحيد أن يكتب ج-أسلوب DLL واجهة استخدام معالجات الكائنات أو أنا في عداد المفقودين شيئا ؟ في هذه الحالة أعتقد أنني ربما يكون أقل من الجهد مع مباشرة باستخدام ملفوفة ج-المكتبة.

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

المحلول

واجهة أسماء الأعضاء سوف لا تكون مزينة -- انهم مجرد إزاحة في vtable.يمكنك تحديد واجهة (باستخدام C, بدلا من COM "واجهة") في رأس الملف هكذا:

struct IFoo {
    int Init() = 0;
};

ثم يمكنك تصدير وظيفة من DLL, مع عدم تغيير اسم:

class CFoo : public IFoo { /* ... */ };
extern "C" IFoo * __stdcall GetFoo() { return new CFoo(); }

هذا سوف تعمل بشكل جيد ، شريطة أن كنت تستخدم مترجم يولد متوافق vtables.Microsoft C++ وقد ولدت نفس الشكل vtable منذ (على الأقل أعتقد) MSVC6.1 DOS, حيث vtable هو مجرد قائمة من المؤشرات على وظائف (مع thunking في عدة الميراث الحالة).GNU C++ (إذا لم تخني الذاكرة) يولد vtables مع مؤشرات الدالة النسبية إزاحة.هذه ليست متوافقة مع بعضها البعض.

نصائح أخرى

أكبر مشكلة في الاعتبار عند استخدام DLL المجمعة مع مختلف C++ compiler من الدعوة EXE يتم تخصيص الذاكرة وجوه الحياة.

أنا أفترض أنه يمكنك الحصول على الماضي اسم تغيير اسم (الدعوة الاتفاقية) ، والتي ليس من الصعب إذا كنت تستخدم مترجم متوافق مع تغيير اسم (أعتقد VC6 متوافق على نطاق واسع مع VS2008) ، أو إذا كنت تستخدم extern "C".

حيث يمكنك تشغيل في مشاكل عند تخصيص شيء باستخدام new (أو malloc) من DLL, ثم يعود هذا إلى المتصل.المتصل delete (أو free) محاولة تحرير كائن من كومة.هذا سيكون خاطئ.

يمكنك إما القيام COM الطراز IFoo::Release شيء أو MyDllFree() شيء.كل من هذه, لأنها دعوة العودة إلى DLL ، واستخدام التنفيذ الصحيح delete (أو free()) ، لذلك سوف حذف الكائن الصحيح.

أو يمكنك التأكد من أن كنت تستخدم LocalAlloc (على سبيل المثال) ، بحيث EXE و DLL تستخدم نفس الكومة.

أعتقد كريس Becke اقتراح هو على ما يرام.وأود أن لا تستخدم روجر الحل الأول, الذي يستخدم واجهة في الاسم فقط ، كما ذكر ، يمكن تشغيل في مشاكل تتعارض مترجم-التعامل مع فئات مجردة و طرق افتراضية.روجر يشير إلى جاذبية COM-حالة متناسقة في له متابعة.

  1. نقطة الألم:كنت بحاجة إلى تعلم كيفية جعل واجهة COM الطلبات والتعامل بشكل صحيح مع IUnknown ، والاعتماد على الأقل IUnknown:AddRef و IUnknown:الإفراج.إذا تطبيقات واجهات يمكن أن تدعم أكثر من واجهة واحدة أو إذا طرق يمكن أيضا العودة واجهات, قد تحتاج أيضا أن تصبح مريحة مع IUnknown:QueryInterface.

  2. هنا الفكرة الرئيسية.جميع البرامج التي تستخدم في تنفيذ واجهة (ولكن لا تنفيذ ذلك) استخدام مشترك #include "*.ح" ملف تعريف واجهة باعتبارها البنية (ج) أو C/C++ فئة (VC++) أو البنية (غير VC++ ولكن C++).على *.ساعة الملف تتكيف تلقائيا بشكل مناسب اعتمادا على ما إذا كنت تقوم بتجميع برنامج لغة C أو C++ لغة البرنامج.لا يجب عليك أن تعرف عن ذلك الجزء ببساطة استخدام *.ساعة الملف.ما *.ساعة الملف هل هو تعريف واجهة البنية أو نوع, دعنا نقول, IFoo مع افتراضية وظائف الأعضاء (فقط وظائف لا الرؤية المباشرة إلى بيانات أعضاء في هذا النهج).

  3. ملف الرأس هي التي شيدت لتكريم COM الثنائية القياسية في الطريقة التي يعمل ل ج و الذي يعمل على C++ بغض النظر عن برنامج التحويل البرمجي C++ التي يتم استخدامها.(جافا JNI الشعبية أكتشف هذه.) وهذا يعني أنه يعمل بشكل منفصل بين-تجميع وحدات من أي منشأ طالما البنية التي تتكون بالكامل من وظيفة إدخال مؤشرات (أ vtable) يتم تعيينها إلى الذاكرة نفس قبل كل منهم (حتى أنها يجب أن تكون جميع x86 32 بت أو كل x64, على سبيل المثال).

  4. في DLL يطبق COM واجهة طريق المجمع الدرجة من نوع ما, ما عليك سوى مصنع نقطة الدخول.شيء مثل

    extern "C" HRESULT MkIFooImplementation(الفراغ **ppv);

والتي ترجع HRESULT (سوف تحتاج إلى معرفة تلك أيضا) و أيضا عودة *pv في الموقع الذي ينص على تلقي IFoo مؤشر واجهة.(أنا القشط و هناك أكثر حذرا التفاصيل التي سوف تحتاج هنا.لا تثق في بناء الجملة) وظيفة فعلية الصورة النمطية التي يمكنك استخدامها من أجل هذا أعلن أيضا في *.ساعة الملف.

  1. وهذه النقطة هي أن مصنع الدخول الذي هو دائما غير مزخرف extern "C" يفعل كل ما يلزم المجمع الدرجة الخلق ثم يسلم Ifoo مؤشر واجهة إلى الموقع الذي تحدده.وهذا يعني أن كل إدارة الذاكرة انشاء فئة و كل إدارة الذاكرة من أجل وضع اللمسات الأخيرة عليه ، وما إلى ذلك ، سوف يحدث في DLL حيث كنت بناء المجمع.هذا هو المكان الوحيد حيث لديك للتعامل مع تلك التفاصيل.

  2. عندما تحصل على موافق النتيجة من المصنع وظيفة ، وقد صدر مؤشر واجهة وبالفعل تم حجز لك (هناك ضمني IFoo:Addref العملية بالفعل يؤديها نيابة عن مؤشر واجهة تم تسليمها لك).

  3. عندما كنت فعلت مع واجهة الإفراج عنها مع دعوة على IFoo:الإفراج عن طريقة واجهة.هذا هو الإصدار النهائي تنفيذ (في حال كنت أكثر AddRef أن النسخ) التي من شأنها تمزيق الصف و واجهة الدعم في مصنع DLL.هذا هو ما يحصل لك من الصحيح الاعتماد على ثابت ديناميكية stoorage تخصيص وإطلاق وراء واجهة, أم لا DLL التي تحتوي على وظيفة مصنع يستخدم نفس المكتبات رمز الدعوة.

  4. ربما يجب عليك تنفيذ IUnknown:QueryInterface (مثل طريقة IFoo:QueryInterface) أيضا ، حتى لو كان دائما يفشل.إذا كنت تريد أن تكون أكثر تطورا باستخدام COM الثنائية نموذج واجهة لديك المزيد من الخبرة ، يمكنك تعلم كيفية توفير كامل QueryInterface تطبيقات.

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

لم رسمت الموارد قد تحتاج إلى استشارة للحصول على أمثلة و ما عليك أن تتعلم من أجل جعل *.ساعة الملفات فعلا تنفيذ مصنع وظيفة wrappers المكتبات التي ترغب في مشاركتها.إذا كنت ترغب في حفر أعمق ، هولر.

هناك أشياء أخرى تحتاج إلى النظر أيضا ، مثل التشغيل مرة يتم استخدامها من قبل مختلف المكتبات.إذا لم الأجسام ويجري تقاسم هذا جيد, ولكن هذا يبدو من غير المرجح تماما للوهلة الأولى.
كريس بيكر اقتراحات هي دقيقة جدا - استخدام الفعلية واجهة COM قد تساعدك على الحصول على توافق ثنائي عليك.الأميال الخاص بك قد تختلف :)

لا متعة الرجل.كنت في الكثير من الإحباط ، ربما عليك أن تعطي هذا:

أن الحل الوحيد أن يكتب ج-أسلوب DLL واجهة استخدام معالجات إلى الأشياء أو أنا في عداد المفقودين شيء ما ؟ في هذه الحالة أعتقد أنني ربما يكون أقل من الجهد مع مباشرة باستخدام ملفوفة ج-المكتبة.

حقا تبدو قريبة.حظا سعيدا.

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