Question

Quoi?

Un DLGTEMPLATE est chargé à partir d'une DLL de ressource. Comment puis-je modifier les chaînes affectées aux contrôles au moment de l'exécution par programmation?

Je souhaite pouvoir effectuer cette opération avant la création de la boîte de dialogue, de sorte que je puisse dire que les chaînes affichées proviennent de la DLL de ressources et non d'appels à SetWindowText lors de l'initialisation de la boîte de dialogue.

Google a trouvé des exemples de création de DLGTEMPLATE dans le code ou de bidouillage de bits de style simples, mais rien pour modifier les chaînes en mémoire.

Comment?

Je le fais en accrochant les API de création de dialogues / propriétés. Ce qui me donne accès au DLGTEMPLATE avant la création du dialogue et avant qu’il ait un HWND.

Pourquoi?

Je veux pouvoir effectuer la localisation à l'exécution et les tests de localisation. J'ai déjà implémenté cette fonctionnalité pour le chargement de chaînes (y compris le wrapper MFC 7.0), de menus et de tables d'accélération, mais j'ai du mal à gérer la création de feuilles de dialogue / propriétés.

Des exemples de code constitueraient la réponse idéale, idéalement une classe à lire autour de DLGTEMPLATE. Si je travaille sur ma propre solution, je la posterai.

Était-ce utile?

La solution

Vous ne pouvez pas éditer les chaînes en mémoire. La structure DLGTEMPLATE est un mappage direct de fichier des octets pertinents de la dll de ressources. C’est en lecture seule.

Vous allez devoir traiter toute la structure DLGTEMPLATE et en écrire une nouvelle avec les chaînes de longueur modifiée.

Il sera franchement plus facile de simplement accrocher le WM_INITDIALOG et de modifier les chaînes en interagissant avec les contrôles plutôt que de créer un graveur DLGTEMPLATE. Parce qu'il n'y en a pas beaucoup autour. Sauf obligation supplémentaire de sauvegarder les ressources de boîte de dialogue modifiées sur le disque sous forme de fichiers .res bruts (ou de tenter de modifier le fichier .dll in situ), nous vous recommandons vivement d'éviter cette approche.

Vous dites que vous le faites déjà pour les tables d'accélérateur et les chaînes de menus. Si vous pouvez garantir que les chaînes affectées au correctif vont être plus courtes, créez une copie binaire de la structure DLGTEMPLATE et écrivez le code d'analyse non trivial. nécessaire de trouver chaque chaîne pour pouvoir patcher la copie en place.

Autres conseils

Il y a un fichier quelque part (appelé Microsoft, mais je ne suis pas tout à fait sûr) originaire de RESFMT.ZIP qui explique cela avec quelques exemples de code. Raymond Chen fait également d'excellentes explications à ce sujet sur son blog. Notez que le format des contrôles DIALOGEX et DIALOG est différent.

Comme indiqué dans d'autres réponses, il vous faudrait recréer la structure dès le début. Ce n'est pas si grave que vous avez déjà les informations de base. L'ajout des contrôles est difficile.

En gros, allouez un bloc de mémoire volumineux à un WORD * lpIn. Ajoutez ensuite la structure par-dessus. L'ajout des informations de base pour le DIALOG (voir DLGTEMPLATE) et les contrôles est assez évident car les informations sont disponibles dans MSDN.

Les deux problèmes les plus importants que vous rencontrerez sont les suivants: s’assurer que les différentes parties commencent sur une limite d’alignement et interpréter les valeurs des contrôles DIALOG, en particulier lorsqu’il ne faut ajouter qu’une chaîne, une chaîne ou un ordinal. Chaque contrôle doit commencer sur une limite régulière.

Pour le premier (emprunté quelque part je pense à RESFMT.ZIP):

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

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

What I did was build a series of functions like this one following that allowed me to assemble DIALOGS in memory. (My need was so I could have some common code that didn't need an associated RC file for some very basic messages).

Here is an example...

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 );
    }

Le fichier d'en-tête du module complet comprenait les fonctions suivantes:

WORD * AddControlToDialogTemplateEx (MTDialogTemplateType * dlgtmp,                                    char * Titre,                                    WORD Id,                                    char * WinClass,                                    Style DWORD,                                    x court                                    bref y,                                    court cx,                                    cy courte,                                    DWORD ExStyle,                                    int HelpID); int DestroyDlgTemplateEx (MTDialogTemplateType * dlgtmp); MTDialogTemplateType * CreateDlgTemplateEx (char * Name, // Nous utilisons name uniquement pour référence, afin qu'il puisse être NULL                                             x court                                             bref y,                                             court cx,                                             cy courte,                                             DWORD ExtendedStyle,                                             Style DWORD,                                             char * Menu,                                             char * WinClass,                                             char * Légende,                                             char * FontTypeFace,                                             int FontSize,                                             int FontWeigth,                                             int FontItalic,                                             int Charset,                                             int HelpID,                                             int NumberOfControls);

Ce qui m'a permis d'assembler facilement des dialogues entiers à partir de code.

Voir la fonction API :: EnumChildWindows (HWND, WNDENUMPROC, LPARAM)

Vous pouvez appeler ceci dans CFormView :: Create ou CDialog :: OnInitDialog pour vous donner une chance de remplacer les légendes de contrôle. Ne vous inquiétez pas, les anciennes chaînes ne clignotent pas avant de les remplacer.

Dans votre ressource de boîte de dialogue, définissez les légendes de contrôle sur une clé dans une sorte de dictionnaire. Si vous compilez / clr, vous pouvez utiliser une ressource de table de chaînes gérée. Dans votre rappel, recherchez la chaîne traduite dans votre dictionnaire et définissez la légende du contrôle sur la traduction. Un autre avantage de / clr et de la table des chaînes gérées réside dans le fait que vous pouvez automatiquement rechercher le bon langage dans Windows (ou vous-même) après avoir déjà défini System :: Threading :: Thread :: CurrentThread- > CurrentUICulture.

Quelque chose comme ça

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 );
        }
    }
}

Vous devrez localiser la chaîne que vous souhaitez modifier dans le tampon de mémoire qui représente le modèle. La seule façon de le faire est de parcourir tout le modèle. Ce qui n'est pas facile Une fois que vous avez terminé, insérez des octets dans le tampon si votre nouvelle chaîne est plus longue que celle d'origine. Ou réduisez la mémoire tampon si la nouvelle chaîne est plus courte.

Comme l'a écrit Chris, il serait beaucoup plus facile de modifier le texte dans WM_INITDIALOG et d'essayer de reformuler votre requête en précisant que vous ne pouvez pas appeler SetWindowText ().

Merci à tous, j’ai eu 24 heures de repos sur le problème, puis un filtre global pour les fenêtres, le filtrage WM_INITDIALOG, qui était une méthode beaucoup plus simple, a très bien fonctionné, aucune connexion API n’est requise, 2 pages de code réduites à une simple quelques lignes.

Merci pour toutes les réponses.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top