views:

108

answers:

4
#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                                              \
    __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

A: 

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.

Jerry Coffin
Just tested with VS2010 and I was able to create labels without any issues and seem to recall that its been possible for quite some time.
torak
I see. Will try this out.EDIT: Hmm, no good. The jz call still raises the error, among the other new errors. Just to clarify, I'm using VS 2008.
shadeMe
A: 

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
torak
The token-paste operator in the 3rd line isn't recognized as one - The compiler thinks it's a directive. Edited question with modified code.
shadeMe
@shadeMe: You could try taking the token paste out of the assembly and using function pointer instead.
torak
A: 

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.

Roland Illig
A: 

Fixed it by enclosing the function body in another scope.

shadeMe