Код на основе макроса препроцессора выдает ошибку C2400 - PullRequest
0 голосов
/ 29 июня 2010
#define CANCEL_COMMON_DIALOG_HOOK(name)  \
void __declspec(naked) ##name##CancelCommonDialogHook(void)  \
{  \
    __asm  \
    {  \
        add     esp, [k##name##CancelCommonDialogStackOffset]  \
        jz      RESTORE  \
        jmp     [k##name##CancelCommonDialogNewFileRetnAddr]  \
    RESTORE:  \
        pushad  \
        call    DoSavePluginCommonDialogHook  \
        test    eax, eax  \
        jnz     REMOVE  \
        popad  \
        jmp     [k##name##CancelCommonDialogRestoreRetnAddr]  \
    REMOVE:  \
        popad  \
        jmp     [k##name##CancelCommonDialogRemoveRetnAddr]      \
    }  \
}

Использование приведенного выше макроса приводит к тому, что компилятор выдает эту ошибку:

ошибка C2400: синтаксическая ошибка встроенного ассемблера во «втором операнде»;найдено 'RESTORE'

Что я сделал неправильно?

РЕДАКТИРОВАТЬ:

void __declspec(naked) #name##CancelCommonDialogHook(void)               \ 
{                                                                        \
    __asm   add     esp, [k##name##CancelCommonDialogStackOffset]        \
    __asm   jz      RESTORE                                              \
    __asm   jmp     [k##name##CancelCommonDialogNewFileRetnAddr]         \
    RESTORE:                                                             \
    __asm   pushad                                                       \
    __asm   call    DoSavePluginCommonDialogHook                         \
    __asm   test    eax, eax                                             \
    __asm   jnz     REMOVE                                               \
    __asm   popad                                                        \
    __asm   jmp     [k##name##CancelCommonDialogRestoreRetnAddr]         \
    REMOVE:                                                              \
    __asm   popad                                                        \
    __asm   jmp     [k##name##CancelCommonDialogRemoveRetnAddr]          \
}

Приведенный выше код также не работает:

ошибка C2447: '{': отсутствует заголовок функции (формальный список старого стиля?) Ошибка C2014: команда препроцессора должна начинаться с первого не белого пространства

Ответы [ 4 ]

0 голосов
/ 14 октября 2010

Исправлено, заключая тело функции в другую область.

0 голосов
/ 29 июня 2010

Я был без доступа к компьютеру, так что, надеюсь, вы уже решили это. Я думаю, что проблема в том, что использование «\» для завершения строки на самом деле говорит препроцессору C слить следующую строку с этой строкой. См. Комментарий 3 на этой странице , а сращивание строк здесь . Это работает нормально для большинства операторов C, но более проблематично для сборки, так как новые строки - это то, как он разделяет операторы.

Я могу придумать два подхода к решению. Во-первых, найти что-то вроде C ";" который может использоваться как разделитель статов в сборке, я не знаю, существует ли такая вещь. Второй подход заключается в том, чтобы обернуть все в отдельные __asm операторы. При втором подходе вы получаете следующее:

void __declspec(naked) ##name##CancelCommonDialogHook(void)          
{                                                                    
    __asm{add     esp, [k##name##CancelCommonDialogStackOffset]}      \
    __asm{jz      RESTORE}                                            \
    __asm{jmp     [k##name##CancelCommonDialogNewFileRetnAddr]}       \
    RESTORE:                                                          \
    __asm{pushad}                                                     \
    __asm{call    DoSavePluginCommonDialogHook}                       \
    __asm{test    eax, eax}                                           \
    __asm{jnz     REMOVE}                                             \
    __asm{popad}                                                      \
    __asm{jmp     [k##name##CancelCommonDialogRestoreRetnAddr]}       \
    REMOVE:                                                           \
    __asm{popad}                                                      \
    __asm{jmp     [k##name##CancelCommonDialogRemoveRetnAddr]}        \
}

ПРИМЕЧАНИЕ. Я оставил метки вне операторов asm, потому что:

  1. Я думаю, что вы можете
  2. Я не уверен в правилах области видимости для меток, определенных в __asm блоков
0 голосов
/ 08 июля 2010

Просто дикая догадка: макрос развернет весь текст в одну строку, заканчиваясь add esp, [k...] jz RESTORE jmp k....Возможно, это помогает поставить точку с запятой в конце каждой инструкции на ассемблере.

Указанием для этой гипотезы является то, что ошибка возникает во второй «строке».Первое нормально, но второе будет объединено с первым, так что это первый шанс для запутанного компилятора.Если бы ошибка была где-то позже, это не было бы, вероятно.

0 голосов
/ 29 июня 2010

По крайней мере, в последний раз, когда я пытался это сделать, вы не могли создавать метки внутри встроенного блока сборки в VC ++.Хотя использование меток в стиле C работает:

void __declspec(naked) ##name##CancelCommonDialogHook(void)  \
{  \
    __asm  \
    {  \
        add     esp, [k##name##CancelCommonDialogStackOffset]  \
        jz      RESTORE  \
        jmp     [k##name##CancelCommonDialogNewFileRetnAddr]  \
    }           \
    RESTORE:    \
    _asm {      \
        pushad  \
        call    DoSavePluginCommonDialogHook  \
        test    eax, eax  \
        jnz     REMOVE  \
        popad  \
        jmp     [k##name##CancelCommonDialogRestoreRetnAddr]  \
    }          \
    REMOVE:    \
    __asm {    \
        popad  \
        jmp     [k##name##CancelCommonDialogRemoveRetnAddr]      \
    }  \
}

Я давно не писал встроенных сборок в VC ++, поэтому не могу гарантировать, что это сработает, но я предполагаю, чточестный шанс.

...