سؤال

ماذا ؟

لدي DLGTEMPLATE تحميله من مورد DLL, كيف يمكنني تغيير سلاسل تعيين عناصر التحكم في وقت التشغيل برمجيا ؟

كنت تريد أن تكون قادرة على القيام بذلك قبل الحوار إنشاء مثل هذا أستطيع أن أقول أن السلاسل على العرض جاء من مورد DLL, وليس من يدعو إلى SetWindowText عند مربع الحوار تهيئة.

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

كيف ؟

أنا أفعل هذا من خلال ربط الحوار/الملكية ورقة إنشاء المعهد.الذي يعطيني الوصول إلى DLGTEMPLATE قبل الفعلية الحوار تم قبل HWND.

لماذا ؟

أريد أن أكون قادرة على القيام وقت الترجمة و التعريب الاختبار.أنا بالفعل هذا تنفيذها لتحميل السلسلة (بما في ذلك MFC 7.0 المجمع) ، والقوائم مسرع الجداول ، ولكن أنا تكافح من أجل التعامل مع الحوار/الملكية ورقة الخلق.

أمثلة التعليمات البرمجية سيكون الحل المثالي ، من الناحية المثالية فئة إلى التفاف حول DLGTEMPLATE ، إذا أنا أعمل خارج بلدي الحل سأقوم بعد ذلك.

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

المحلول

لا يمكنك تحرير السلاسل في الذاكرة.على DLGTEMPLATE هيكل مباشر ملف الخرائط ذات الصلة بايت dll المورد.أن يكون للقراءة فقط.

أنت ذاهب إلى الحاجة إلى عملية كاملة DLGTEMPLATE هيكل يكتب من جديد مع تغيير طول السلاسل.

سوف بصراحة يكون من الأسهل مجرد ربط WM_INITDIALOG وتغيير سلاسل من خلال التفاعل مع عناصر التحكم من بناء DLGTEMPLATE الكاتب.لأن هناك arn الكثير من المحيطين.إلا إذا كان لديك إضافية شرط أن ينقذ فعلا غيرت الحوار موارد القرص الخام .ملفات res (أو محاولة تعديل .dll inplace) معرف حقا ننصح تجنب هذا النهج.

أنت تقول أنك تفعل هذا من أجل accellerator الجداول قائمة السلاسل - إذا كنت يمكن أن تضمن أن مصححة في سلاسل ستكون أقصر ، ثم جعل مجرد الثنائية نسخة من DLGTEMPLATE البنية و كتابة غير تافهة مسح رمز من الضروري أن تجد كل سلسلة حتى تتمكن من تصحيح النسخة في المكان.

نصائح أخرى

هناك ملف هناك في مكان ما (والتي أعتقد نشأت في Microsoft ولكن أنا لست متأكدا تماما) دعا RESFMT.ZIP وهو ما يفسر هذا مع بعض أمثلة التعليمات البرمجية.ريمون تشن أيضا ممتازة تعليل هذا على بلوق.لاحظ أن شكل DIALOGEX الحوار ضوابط مختلفة.

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

في الأساس, تخصيص كبير قليلا من كتلة من الذاكرة في كلمة *lpIn.ثم يضاف هيكل على أعلى من ذلك.مضيفا المعلومات الأساسية عن الحوار (انظر DLGTEMPLATE) والضوابط واضح جدا حسب المعلومات هناك في MSDN.

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

الأولى (اقترضت من مكان ما اعتقد RESFMT.ZIP):

WORD *AlignDwordPtr (WORD *lpIn)
    {
    ULONG ul;

    ul = (ULONG) lpIn;
    ul +=3;
    ul >>=2;
    ul 

ما فعلته كان بناء سلسلة من المهام مثل هذا واحد بعد أن سمح لي لتجميع الحوارات في الذاكرة.(بلدي الحاجة لذلك أنا يمكن أن يكون بعض التعليمات البرمجية التي لم تكن في حاجة المرتبطة الملف RC لبعض رسائل أساسية).

هنا هو مثال...

WORD *AddStringOrOrdinalToWordMem( WORD *lpw, char    *sz_Or_Ord )
    {
    LPWSTR  lpwsz;
    int     BufferSize;

    if (sz_Or_Ord == NULL)
        {
        *lpw++ = 0;
        }
    else
        {
        if (HIWORD(sz_Or_Ord) == 0) //MAKEINTRESOURCE macro 
            {
            *lpw++ = 0xFFFF;
            *lpw++ = LOWORD(sz_Or_Ord);
            }
        else
            {
            if (strlen(sz_Or_Ord))
                {
                lpwsz = ( LPWSTR ) lpw;
                BufferSize = MultiByteToWideChar( CP_ACP, 0, sz_Or_Ord, -1, lpwsz, 0 );
                MultiByteToWideChar( CP_ACP, 0, sz_Or_Ord, -1, lpwsz, BufferSize );
                lpw = lpw +  BufferSize;
                }
            else
                {
                *lpw++ = 0;
                }
            }
        }
    return( lpw );
    }

ملف الرأس إلى وحدة كاملة وشملت هذه الوظائف:

WORD *AddControlToDialogTemplateEx(MTDialogTemplateType *dlgtmp, char *Title, WORD Id, char *WinClass, DWORD Style, short x, short y, short cx, short cy, DWORD ExStyle, int HelpID); int DestroyDlgTemplateEx(MTDialogTemplateType *dlgtmp); MTDialogTemplateType *CreateDlgTemplateEx( char *Name, // We use name just for reference, so it can be NULL short x, short y, short cx, short cy, DWORD ExtendedStyle, DWORD Style, char *Menu, char *WinClass, char *Caption, char *FontTypeFace, int FontSize, int FontWeigth, int FontItalic, int Charset, int HelpID, int NumberOfControls);

الذي سمح لي أن تجميع كل الحوارات بسهولة من التعليمات البرمجية.

انظر دالة API ::EnumChildWindows( HWND, WNDENUMPROC, LPARAM )

يمكنك استدعاء هذا في CFormView::إنشاء أو CDialog::OnInitDialog أن تعطي لنفسك فرصة استبدال السيطرة على تعليق.لا تقلق, السلاسل القديمة لا وميض قبل أن تحل محلها.

في مربع الحوار الموارد تعيين التحكم في تعليق على مفتاح في نوع من القاموس.إذا كنت تجميع /clr يمكنك استخدام تمكنت سلسلة الجدول الموارد.في رد ، انظر ترجمة السلسلة في القاموس الخاص بك وتعيين السيطرة شرح الترجمة.فائدة أخرى /clr وإدارة سلسلة الجدول هو أنه يمكنك تلقائيا البحث عن اللغة المناسبة من خلال ويندوز (أو أنت) بعد أن تم بالفعل تعيين النظام::خيوط::الموضوع::CurrentThread->CurrentUICulture.

شيء مثل هذا

CMyDialog::OnInitDialog()
{
    ::EnumChildWindows(
        this->GetSafeHwnd(),
        CMyDialog::UpdateControlText,
        (LPARAM)this )
}

BOOL CALLBACK CMyDialog::UpdateControlText( HWND hWnd, LPARAM lParam )
{
    CMyDialog* pDialog = (CMyDialog*)lParam;
    CWnd* pChildWnd = CWnd::FromHandle( hWnd );

    int ctrlId = pChildWnd->GetDlgCtrlID();
    if (ctrlId)
    {
        CString curWindowText;
        pChildWnd->GetWindowText( curWindowText );
        if (!curWindowText.IsEmpty())
        {
            CString newWindowText = // some look up
            pChildWnd->SetWindowText( newWindowText );
        }
    }
}

سيكون لديك لتحديد السلسلة التي تريد تعديلها في ذاكرة المخزن المؤقت الذي يمثل القالب.الطريقة الوحيدة للقيام بذلك هو أن تجتاز كل قالب.التي ليس من السهل.مرة واحدة كنت قد فعلت ذلك, إما إدراج بايت في المخزن المؤقت إذا الجديدة سلسلة أطول من نسخة أصلية واحدة.أو تقليص المنطقة العازلة إذا السلسلة الجديدة أقصر.

كما كتب كريس سيكون أسهل بكثير من تعديل النص في WM_INITDIALOG ومحاولة إعادة العبارة اشتراط أن يقول لك قد لا ندعو SetWindowText().

شكرا جميعا, في الحقيقة لدي 24 ساعة من الراحة على المشكلة ، ثم ذهب مع العالمي ربط windows تصفية WM_INITDIALOG التي كانت طريقة أبسط من ذلك بكثير ، وعملت على ما يرام, لا API hooking المطلوبة ، 2 صفحات التعليمات البرمجية وصولا إلى مجرد بضعة أسطر.

شكرا على كل الإجابات.

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