开发者

Preprocessor macro based code yields a C2400 error

#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]      \
    }  \
}

Using the above macro causes the compiler to throw this error:

error C2400: inline assembler syntax error in 'second operand'; found 'RESTORE'

What have I done incorrectly ?

EDIT:

void __declspec(naked) #name##CancelCommonDialogHook(void)               \ 
{                                                                        \
    __asm   add     esp, [k##name##CancelCommonDialogStackOffset]        \
    __asm   jz      RESTORE                                 开发者_如何学C             \
    __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]          \
}

The above code doesn't work either:

error C2447: '{' : missing function header (old-style formal list?) error C2014: preprocessor command must start as first nonwhite space


At least the last time I tried it, you couldn't create labels inside an inline assembly block in VC++. Using C-style labels works though:

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]      \
    }  \
}

I haven't written any inline assembly in VC++ for quite a while, so I can't guarantee that will work, but I'd guess there's a pretty fair chance.


I've been without computer access, so hopefully you've resolved this already. I think that the problem is that using "\" to end the line actually tells the C preprocessor to merge the next line with this line. See comment 3 on this page, and line splicing here. That works OK for most C statements, but is more problematic for assembly, since new lines are how it deliniates statements.

I can think of two approaches to a solution. The first is to find something like C's ";" which can be used as a statment separator in assembly, I don't know if such a thing exists. The second approach is to wrap everything in separate __asm statements. Taking the second approach you get, the following:

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]}        \
}

NOTE: I've left the labels outside of asm statements because:

  1. I think you can
  2. I'm not sure of the scoping rules for labels defined in __asm blocks


Just a wild guess: The macro will expand all the text to a single line, ending up with add esp, [k...] jz RESTORE jmp k.... Maybe it helps to put a semicolon at the end of each assembler instruction.

An indication for that hypothesis is that the error occurs on your second "line". The first is ok, but the second will be merged to the first, so this is the first chance for the compiler to get confused. Had the error been somewhere later, this wouldn't be it probably.


Fixed it by enclosing the function body in another scope.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜