تحذير مع بناء 64bit dll
-
01-10-2019 - |
سؤال
رأس التصدير DLL
extern "C"
void _declspec(dllexport) __stdcall foo();
ملف .def
EXPORTS
foo @1
عندما أقوم بإنشاء DLL بواسطة تكوين 64 بت بني ، أقابل هذا التحذير.
تحذير LNK4197: تصدير "فو" المحدد عدة مرات ؛ باستخدام المواصفات الأولى
ولكن إذا قمت ببناء DLL بواسطة تكوين بناء 32 بت ، فإن التحذير لا يحدث أبدًا.
ما المشكلة؟ ماهو الفرق.
في رأس DLL للواجهة ، عادة ما نستخدم هذه التقنية ،
#ifdef EXPORT_DLL
#define BASICAPI _declspec(dllexport)
#else
#define BASICAPI _declspec(dllimport)
#endif //_EXPORT_DLL
ولكن إذا كان ملف DEF موجودًا أيضًا ، فسوف نلتقي دائمًا بالتحذير عندما نقوم ببناء 64 بت DLL.
لذلك ، هل يجب أن نكتب الرموز مثل هذا؟
#ifdef EXPORT_DLL
#define BASICAPI
#else
#define BASICAPI _declspec(dllimport)
#endif //_EXPORT_DLL
أنه يعمل بشكل جيد. لكنها ليست مألوفة بالنسبة لي.
أعطني أي آرائك.
المحلول
عمومًا ليس من الممارسات الجيدة تحديد الصادرات مرتين لنفس الوظيفة. إذا كان لديك بالفعل __declspec(dllexport)
ثم لا تحتاج إلى تحديد التصدير في ملف .DEF أيضًا. على العكس ، إذا كان لديك التصدير المدرج في ملف .def ، فلا داعي ل __declspec(dllexport)
.
أعتقد أن سبب التحذير هو أن البناء في x86 ، __declspec(dllexport)
يقوم بتصدير الاسم المزين بأحد السطح السطحي الرائد ، لكن برنامج التحويل البرمجي 64 بت لا يزين أسماء مع السطح السفلي الرائد ، مما يؤدي إلى مكرر. للتحقق من ذلك ، يمكنك أن تنظر إلى DLL 32 بت في Walker التبعية ، ويجب أن ترى وظيفتين تم تصديرهما ، "Foo" و "_foo".
نصائح أخرى
__declspec(dllexport)
و .def ملفات اثنين مختلف طرق لتصدير الرموز من DLL. لا تحتاج إلى كليهما وينبغي أن تحذفهم. ال __declspec
تعد الطريقة أكثر تنوعًا بالنسبة لبرامج C ++ حيث تصدر أسماء مع c ++ millgling ، مما يتيح تصدير الوظائف المحملة الزائدة ، ولكن على العكس من ذلك يجعل الأسماء أكثر صعوبة في الاستيراد عبر getProcadDress.
أيضا ، باستخدام ماكرو عام مثل EXPORT_DLL
أمر خطير لأنه يعني أنه لا يمكنك بناء DLL ، الذي يستخدم DLL آخر ، دون أن يحاول DLL واحد تصدير جميع رموز كلا DLL.
يقوم DevStudio تلقائيًا بإنشاء رمز على مشاريع DLL: <PROJECT>_EXPORTS
مما يجعل الأمر سهلاً وآمنًا لإنشاء ماكرو تصدير:
#ifdef EXPORT
#undef EXPORT
#endif
#ifdef PROJECTNAMEHERE_EXPORTS
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif
EXTERN_C EXPORT void __stdcall Function1(void);
EXTERN_C EXPORT void __cdecl Function2(...);
EXPORT void Function3(void);
يمكن الحصول على وظائف 1 و 2 مع getProcaddress _Function1@0
و Function2
على التوالى. سيتم تصدير Function3 من خلال اسم مشوهة محددًا بمترجم سيبدو مثل: @Function3@@UAG_DB@Z
. هذا الاسم مختلف لكل تحميل زائد من الوظيفة ، وهو ما يسمح بالحمل الزائد للعمل.
من المهم معرفة اسم التشويش __declspec
كملفات .def لا تهتم وستصدر فقط Function1
, Function2
و Function3
.