The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: austinm on June 01, 2010, 10:07:08 PM

Title: Call MessageBoxW assembly code from C++
Post by: austinm on June 01, 2010, 10:07:08 PM
Hi,

First of all, a short introduction since this is my first post on the forum. I'm Mike, a 3rd-year university student studying computer science. I've just recently been taking my first stabs at the Win32 API and its accompanying disassembly, etc.

Currently, I'm trying to put a few lines of assembly into my C++ Windows program. Here is what I have so far:


wchar_t MsgBoxCaption[] = L"Caption";
wchar_t MsgBoxText[] = L"Hello World!";
__asm
{
    push hWnd
    push MsgBoxCaption
    push MsgBoxText
    push 0 ; MB_OK
    call MessageBoxW
}


I am aware of the 'invoke' directive, but I'd like to code it the old-fashioned way to really learn more about what's going on.

Unfortunately, when I build and start debugging, I get this:

Unhandled exception at 0x0129b3f0 in HelloWorld.exe: 0xC0000005: Access violation.

I've done some Googling around, but I'm not quite sure what the problem is. I've tried various syntaxes and also found something about stack memory alignment.

Does anyone see what I'm doing wrong? Thanks for your help.

-Mike
Title: Re: Call MessageBoxW assembly code from C++
Post by: Richard van Petrov on June 01, 2010, 11:16:06 PM
Welcome to the forum Mike!

    push hWnd
    push offset MsgBoxCaption
    push offset MsgBoxText
    push 0 ; MB_OK
    call MessageBoxW


Literally, you are trying to put "Caption" and "Hello World!" onto the stack. What you want to do is: is pass a pointer that points to the data locations.

int WINAPI MessageBox(
  __in_opt  HWND hWnd,
  __in_opt  LPCTSTR lpText,
  __in_opt  LPCTSTR lpCaption,
  __in      UINT uType
);
Title: Re: Call MessageBoxW assembly code from C++
Post by: Richard van Petrov on June 01, 2010, 11:21:01 PM
And I also see that you are mixed up on how to call a procedure with parameters.

When calling a procedure in assembly, the last parameter is pushed onto the stack first, and the first parameter is pushed onto the stack last.


Here is the correct form of your code:
    push 0 ; MB_OK
    push offset MsgBoxCaption
    push offset MsgBoxText
    push hWnd
    call MessageBoxW


Note: When you include the 'windows.inc' file (from your \masm32\include folder) into your code, you can write constants into your code like this:
push MB_YESNOCANCEL or MB_INFORMATION
push NULL ; Puts 'Error' as the title === refer to MessageBox Function documentation
push offset MsgBoxText
push NULL
call MessageBoxW
Title: Re: Call MessageBoxW assembly code from C++
Post by: hutch-- on June 02, 2010, 01:53:10 AM
Mike,

Richard is correct here, almost exclusively Windows API calls are STDCALL, push arguments in reverse order and the procedure balances the stack on exit. When working with C/C++ you can also call other functions/procedures written in MASM with the C calling convention, push a variable number of arguments in reverse order to the procedure and the caller balances the stack. The action is in using matching calling conventions between C and MASM and usually using the EXTERN notation with the C compiler to prototype the MASM functions that you call.

Inline assembler still works in Win32 with Microsoft C compilers but with the coming 64 bit code you will need to write seperate modules in MASM for assembler code.
Title: Re: Call MessageBoxW assembly code from C++
Post by: austinm on June 02, 2010, 03:15:41 AM
Hi, thanks for the replies. I remember learning about "left-pushing" and "right-pushing" arguments onto the stack, apparently I had it backwards.

Here is the build output from changing to "push offset MsgBoxCaption" instead of "push MsgBoxCaption":

error C2415: improper operand type

I tried casting the wchar_t pointers to LPCTSTR, but apparently that's not the cause. Am I missing something simple?
Title: Re: Call MessageBoxW assembly code from C++
Post by: hutch-- on June 02, 2010, 05:50:07 AM
 :bg

Probably, set the arguments as DWORD as they are all the same size. Just make sure you have a Unicode string for each if you call the unicode version of MessageBox.
Title: Re: Call MessageBoxW assembly code from C++
Post by: GregL on June 02, 2010, 08:04:15 PM
austinm,

You didn't mention the version of the compiler you are using.  Using VC++ 2010 Express this works for me.


    __asm
    {
        push 0    ; MB_OK
lea eax, MsgBoxCaption[0]
push eax
lea eax, MsgBoxText[0]
push eax
push 0    ; hWnd = NULL
        call DWORD PTR MessageBoxW
    }


Don't ask me why you need the DWORD PTR in the call.  ( I copied the compiler output  :wink  ).

Title: Re: Call MessageBoxW assembly code from C++
Post by: Vortex on June 02, 2010, 08:17:37 PM
Pelles C 6 :


__asm{
push 0
push OFFSET title
push OFFSET msg
push 0
call DWORD PTR MessageBoxW
}
Title: Re: Call MessageBoxW assembly code from C++
Post by: GregL on June 02, 2010, 08:31:00 PM
Vortex,

Yes, in VC 2010 it gives "error C2415: improper operand type" for "push OFFSET MsgBoxCaption" or "push OFFSET MsgBoxCaption[0]".  I got errors using ADDR too, had to do it the long way.

I have never really cared for inline assembly, it has a different set of rules from MASM, and it's too limited.  It does have it's uses though.
Title: Re: Call MessageBoxW assembly code from C++
Post by: Richard van Petrov on June 02, 2010, 10:26:55 PM
Mike,

If your code is in a procedure or function then you will need to use 'addr' and not 'offset'

What push addr MessageText does is:
lea eax, MessageText
push eax


You use addr for local variables because their address locations are made at runtime and not compile time.


void ExampleProc()
    wchar_t MsgBoxCaption[] = L"Caption";
    wchar_t MsgBoxText[] = L"Hello World!";
    __asm
    {
        push 0 ; MB_OK
        push addr MsgBoxCaption
        push addr MsgBoxText
        push hWnd
        call MessageBoxW
    }
}
Title: Re: Call MessageBoxW assembly code from C++
Post by: austinm on June 02, 2010, 10:58:34 PM
I got it working!

Thank you all for your replies. I was using Visual Studio 2010 Ultimate.

I was vaguely aware that there were different methods of loading addresses, whether they are defined at run-time or compile-time. Lesson learned to watch more closely for that in the future.

Overall it's been a pretty good first thread, I'm sure I'll be back later with more questions.
Title: Re: Call MessageBoxW assembly code from C++
Post by: Vortex on June 10, 2010, 08:33:19 PM
Hi Greg,

Me too, I don't prefer the inline assembly system. Moving assembly code to .asm files and creating separate object modules is better.