سؤال

هل من الممكن بناء الموارد في مكتبة ثابتة وإعادة استخدامها بمجرد الارتباط بالمكتبة؟

أنا أفكر في المقام الأول في الحالة التي تقوم فيها باستدعاء وظيفة في المكتبة والتي بدورها تصل إلى الموارد.

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

المحلول

يمكن القيام بذلك، لكنه مؤلم للغاية:لا يمكنك القيام بذلك بمجرد الارتباط بالمكتبة الثابتة.

النظر في هذا:يتم تضمين الموارد في EXE أو DLL.عندما تستدعي بعض التعليمات البرمجية الموجودة في المكتبة الثابتة (على سبيل المثال) LoadIcon، فإنها ستحصل على الموارد من EXE أو DLL المرتبط بها.

لذلك، إذا كانت مكتبتك الثابتة تتطلب توفير الموارد، فلديك خياران:

  1. يمكنك جعل المكتبة تبنيها بسرعة، ثم تستخدم (على سبيل المثال) CreateDialogIndirect.انظر ريموند تشين "إنشاء قالب حوار في وقت التشغيل".
  2. يمكنك تضمينها في المكتبة كمصفوفات بسيطة (أي) char my_dialog_resource[] = { .... };, ، ثم استخدم (على سبيل المثال) CreateDialogIndirect.ربما ستحتاج إلى العثور على (أو كتابة) أداة مساعدة تقوم بالتحويل من .RES الملفات الى .CPP ملفات.
  3. يمكنك شحن ملف LIB باستخدام برنامج نصي للمورد (.RC file) وملف الرأس المقابل.أنت إذن #include لهم حسب الاقتضاء.ستحتاج إلى حجز نطاق من معرفات الموارد ليستخدمها LIB، بحيث لا تتعارض مع معرفات EXE أو DLL الرئيسية.هذا ما يفعله MFC عند استخدامه كمكتبة ثابتة.أو يمكنك استخدام معرفات موارد السلسلة (هذا لا يعمل مع STRINGTABLE موارد).
  4. يمكن شحن مكتبتك الثابتة مع ملف DLL لمورد منفصل.

نصائح أخرى

الشيء الوحيد الذي عليك القيام به لاستخدام الموارد (الصور، ومربعات الحوار، الخ...) في مكتبة ثابتة في Visual C++ (2008)، هو تضمين ملف .res المرتبط بالمكتبة الثابتة في مشروعك.يمكن القيام بذلك في "إعدادات المشروع/الرابط/الإدخال/التبعيات الإضافية".

باستخدام هذا الحل، يتم تعبئة موارد المكتبة الثابتة في ملف exe.، لذلك لا تحتاج إلى ملف DLL إضافي.لسوء الحظ، لا يقوم Visual Studio بتضمين ملف .res تلقائيًا كما هو الحال مع ملف .lib (عند استخدام ميزة "تبعيات المشروع")، ولكن أعتقد أن هذه الخطوة الإضافية الصغيرة مقبولة.

لقد بحثت لفترة طويلة جدًا عن هذا الحل، والآن يفاجئني أنه بهذه البساطة.المشكلة الوحيدة هي أنها غير موثقة على الإطلاق.

لقد مررت بهذا للتو مع برنامج التحويل البرمجي MS Visual Studio.لقد قمنا بتحويل بعض المشاريع القديمة من مكتبات DLL إلى مكتبات ثابتة.تحتوي العديد من مكتبات الارتباط الحيوي (DLL) هذه على موارد حوار أو سلسلة مضمنة فيها.لقد تمكنت من تجميع البرامج النصية .RC لمكتبات الارتباط الحيوي (DLL) هذه في تطبيقنا الرئيسي من خلال تضمينها في ملف البرنامج النصي RC الخاص بالتطبيق الرئيسي عبر آلية "TEXTINCLUDE".لقد وجدت أنه من الأسهل القيام بذلك عن طريق تحرير ملف RC مباشرة، لكن Visual Studio يوفر آلية أكثر "معالجة" أيضًا.من المرجح أن يختلف التنفيذ في المترجمين الآخرين.


لمعالجة البرنامج النصي RC الرئيسي مباشرة:

.1.في قسم "2 TEXTINCLUDE"، قم بتضمين ملف الرأس الذي يحدد معرفات الموارد لمكتبتك.بناء الجملة هو

2 TEXTINCLUDE 
BEGIN
    "#include ""my_first_lib_header.h""\r\n"
    "#include ""my_second_lib_header.h""\0" 
END

.2.في قسم "3 TEXTINCLUDE"، قم بتضمين البرنامج النصي RC من مكتبتك.

3 TEXTINCLUDE
BEGIN
    "#include ""my_first_library.rc""\r\n"
    "#include ""my_second_library.rc""\0"
END

يجب أن تتم الخطوتين 3 و4 تلقائيًا، لكنني وجدت أنه من الأكثر موثوقية إدخالهما بنفسي، بدلاً من الاعتماد على مترجم البرنامج النصي لموارد Microsoft للعناية بالأشياء.

.3.أضف ملف الرأس مع تعريفات موارد مكتباتك إلى قائمة رموز القراءة فقط.عادة ما تكون هذه القائمة بالقرب من أعلى الملف.

#define APSTUDIO_READONLY_SYMBOLS
#include "my_first_lib_header.h"
#include "my_second_lib_header.h"
#undef APSTUDIO_READONLY_SYMBOLS

.4.قم بتضمين البرنامج النصي RC الخاص بمكتبتك في قسم APSTUDIO_INVOKED.عادة ما يكون هذا في أسفل الملف.

#ifndef APSTUDIO_INVOKED
#include "my_first_library.rc"
#include "my_second_library.rc"
#endif 

يمكنك أيضًا القيام بكل هذا تلقائيًا من خلال Visual Studio IDE، لكنني وجدت أنه لا ينطبق دائمًا عندما كنت أتوقع ذلك.

  1. افتح نافذة "عرض الموارد" في Visual Studio.
  2. انقر بزر الماوس الأيمن على ملف الموارد الخاص بتطبيقك الرئيسي واختر "يتضمن المورد..." من قائمة السياق.
  3. في المربع المسمى "توجيهات الرموز للقراءة فقط"، قم بإضافة عبارات التضمين لملفات .h التي تحدد معرف المورد لمكتباتك.
  4. في المربع المسمى "توجيهات وقت الترجمة"، قم بإضافة عبارات التضمين للبرنامج النصي .rc الخاص بمكتبتك.
  5. انقر فوق موافق.قد ترغب أيضًا في تشغيل تجميع البرنامج النصي لـ RC يدويًا، للتأكد من حدوث ذلك.

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

لإضافة مسار تضمين إضافي:

  1. افتح مربع حوار الخصائص لتطبيقك الرئيسي.
  2. حدد "خصائص التكوين/الموارد/عام" من جزء التنقل الأيمن.
  3. في قائمة الخصائص، أدخل أي مسارات ذات صلة بجوار "دلائل تضمين إضافية".

وأنا لا أعتقد ذلك. لم يكن لديك مكتبة ثابتة انها HINSTANCE الخاصة. انها يتم تنفيذ التعليمات البرمجية في سياق DLL أو EXE الذي يربط به. هذا هو السبب في كل الموارد سوف محاولة لتحميل من التعليمات البرمجية مكتبة ثابتة سوف يكون ذلك أرفق DLL / EXE.

وفعلت هذا النوع من الموارد إعادة استخدامها مع DLL رغم ذلك، بقدر ما لها انها مساحة العنوان الخاص، ويمكنك الاتصال LoadResource مع HINSTANCE DLL ل.

وفقًا لـ Visual Studio 2010، يبدو أن أدوات التطوير من Microsoft لا يمكنها التعامل بشكل صحيح مع بيانات الموارد المجمعة داخل المكتبات الثابتة على الإطلاق.

لتوزيع ملف الموارد المترجمة (أ .res الملف)، لديك خياران:

  1. توزيع .res الملفات بشكل منفصل، وتوجيه رمز العميل للارتباط بها؛
  2. يستخدم cvtres لدمج عدة .res الملفات في كائن واحد (.obj) الملف، وقم بتوفيره بشكل منفصل.

لاحظ أنه لا يمكنك الكتابة في ملفات الكائنات التي تم إنشاؤها باستخدام cvtres.إذا تم توفير ملفات كائن متعددة، lib يشكو كما لو كانت متعددة .res أعطيت الملفات؛إذا تم توفير ملف كائن واحد، lib لا يشكو، لكن الرابط يتجاهل ببساطة بيانات الموارد المضمنة في ملف lib.

قد يكون الأمر أن هناك طريقة لإجبار الرابط على قراءة وربط libbb في بيانات المورد (مع بعض خيارات سطر الأوامر، ومعالجة القسم وما إلى ذلك)، نظرًا لأن بيانات المورد متاحة بالفعل في المكتبة (كما هو الحال مع dumpbin يكشف).حتى الآن، لم أجد حلاً، وما لم يكن هناك من يرغب في اختراق أدوات التطوير، فإن أي شيء أفضل من هذا الحل البسيط ربما لا يستحق كل هذا الجهد.

الطريقة الوحيدة لإرسال بيانات الموارد إلى مكتبة ثابتة (في هذه الحالة، مع مكتبة ثابتة) هو توزيع الموارد بشكل منفصل وربطها بشكل صريح في رمز العميل.استخدام cvtres يمكنك تقليل عدد ملفات الموارد الموزعة إلى ملف واحد، إذا كان لديك العديد منها.

والطريقة الموصى بها هي لتوفير دلل بالموارد جنبا إلى جنب مع المكتبة.

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

  1. يتم تحويل الرمز إلى مجموعة ثابتة من BYTE. bin2c يمكن استخدامها لذلك.
  2. يتم تحويل البيانات إلى مقبض HICON.وإليك كيف فعلت ذلك:

    HICON GetIcon()
    { 
       DWORD dwTmp;
       int offset;
       HANDLE hFile;
       HICON hIcon = NULL;
       offset = LookupIconIdFromDirectoryEx(s_byIconData, TRUE, 0, 0, LR_DEFAULTCOLOR);
       if (offset != 0)
       {
          hIcon = CreateIconFromResourceEx(s_byIconData + offset, 0, TRUE, 0x00030000, 0, 0, LR_DEFAULTCOLOR | LR_DEFAULTSIZE);
       }
       return hIcon;  
    }
    
  3. يتم استخدام GetIcon بدلاً من LoadIcon.بدلاً من الاتصال:

m_hIcon = ::LoadIcon(hInstanceIcon, MAKEINTRESOURCE(pXMB->nIcon));

ثم اتصل

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