Pergunta

O que?

Eu tenho um DLGTEMPLATE carregado a partir de uma DLL de recursos, como posso mudar as cordas atribuídas aos controles em tempo de execução de programação?

Eu quero ser capaz de fazer isso antes que o diálogo é criado, de tal forma que eu posso dizer que as cordas em exposição veio da DLL de recursos, e não de chamadas para SetWindowText quando o diálogo é inicializado.

O Google encontrou exemplos de criação de DLGTEMPLATE em código, ou girando bits de estilo simples, mas nada sobre a edição das cordas na memória.

Como?

Estou fazendo isso ligando o diálogo / Bem Folha criação API. O que me dá acesso ao DLGTEMPLATE antes do diálogo real é criada e antes que ele tenha um HWND.

Por quê?

Eu quero ser capaz de fazer a localização de tempo de execução, e testes de localização. Eu já esta implementado para cordas de carga (incluindo o wrapper MFC 7.0), menus e tabelas acelerador, mas eu estou lutando para diálogo alça / criação folha de propriedades.

Exemplos de código seria a resposta perfeita, o ideal é uma classe para envolver a DLGTEMPLATE, se eu trabalhar a minha própria solução vou postar isso.

Foi útil?

Solução

Você não pode editar as cordas na memória. A estrutura DLGTEMPLATE é um mapeamento do relevent arquivos direto bytes da DLL do recurso. Isso é apenas para leitura.

Você vai precisar para processar toda a estrutura DLGTEMPLATE e escrever um novo com as cadeias de comprimento alterado.

Será francamente ser mais fácil simplesmente ligar o WM_INITDIALOG e alterar as cordas, interagindo com os controles do que a construção de um escritor DLGTEMPLATE. Porque há ar não um monte de pessoas à sua volta. A menos que você tem um requisito adicional para realmente economizar recursos de diálogo alterados no disco como arquivos res brutos (ou tentar modificar o inplace .dll) Id realmente recomendo que você evite essa abordagem.

Você diz que já estão fazendo isso para accellerator tabelas e cadeias de menu - se você pode garantir que o patch em cordas vão ser mais curto, em seguida, basta fazer uma cópia binária do struct DLGTEMPLATE, e escrever o código de digitalização não trivial necessário encontrar cada corda para que você possa corrigir a cópia no lugar.

Outras dicas

Há um arquivo lá fora em algum lugar (o que eu acho que se originou na Microsoft, mas não estou completamente certo) chamou RESFMT.ZIP que explica isso com alguns exemplos de código. Raymond Chen também faz algumas excelentes explicações sobre isso em seu blog. Note-se que o formato de controles DIALOGEX e diálogo são diferentes.

Como observado em algumas outras respostas que você precisa para criar a estrutura de novo desde o início. Isso não é de todo ruim como você já tem a informação básica. Adicionando os controles é onde está fica difícil.

Basicamente, alocar um bloco largish de memória em um WORD * lpIn. Em seguida, adicione a estrutura-se em cima disso. adicionando as informações básicas para o diálogo de (ver DLGTEMPLATE) e os controles é bastante óbvio que a informação está lá no MSDN.

Os dois maiores problemas que você vai encontrar são: Certificar-se que as várias partes começar em um limite de alinhamento, e interpretar os valores dos controles de diálogo, especialmente quando adicionar um apenas uma corda ou, uma corda ou ordinal. Cada necessidades de controle para começar em um mesmo limite.

Para a primeira (emprestado de algum lugar eu acho 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 );
    }

The header file to the complete module included these functions:

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

O que me permitiu montar diálogos inteiros facilmente a partir do código.

Veja a função API :: EnumChildWindows (HWND, WNDENUMPROC, LPARAM)

Você pode chamar isso de uma CFormView :: Criar ou CDialog :: OnInitDialog para dar-te a oportunidade de substituir as legendas controle. Não se preocupe, as velhas cordas não piscam-se antes de substituí-los.

Em seu recurso de diálogo, defina as legendas controle para uma chave em algum tipo de dicionário. Se você está compilando / clr você pode usar um recurso tabela de cadeia gerido. Em seu retorno, procure a string traduzida em seu dicionário e definir a legenda do controle para a tradução. Outro benefício do clr / e tabela de cadeia gerenciado é que você pode olhar automaticamente a linguagem certa pelo Windows (ou você) ter já definido System :: Enfiar :: Thread :: CurrentThread-> CurrentUICulture.

Algo como isto

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

Você vai ter que localizar a seqüência que você deseja modificar no buffer de mem que representa o modelo. A única maneira de fazer isso é percorrer todo o modelo. Que não é fácil. Uma vez feito isso, quer inserir bytes no buffer se a sua nova cadeia é maior do que o original. Ou encolher o buffer se a nova cadeia é mais curto.

Como Chris escreveu, seria muito mais fácil de modificar o texto no WM_INITDIALOG e tentar re-frase que você exigência de que diz que você não pode chamar SetWindowText ().

Obrigado a todos, eu realmente tive 24 horas descansar sobre o problema, então fui com janelas globais ligar filtragem WM_INITDIALOG que era um método muito mais simples, funcionou muito bem, enganchando necessária nenhuma API, 2 páginas de código para baixo a apenas um algumas linhas.

Obrigado por todas as respostas.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top