Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

MCodeGen - Easily transform C/C++ code into mcode


  • Please log in to reply
48 replies to this topic
TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007
This script will automate the conversion of C/C++ code into machine code useable by Laszlo's renowned MCode function. I do not consider it my script, because much of the information needed for it was provided by Laszlo himself as well as jamie. Thanks for the great work!

You need at least Visual C++ 2005 or greater to use this. It was tested with Visual Studio 2008, as well as Visual C++ 2010 Express, available for free here.

How to use (GUI):

Posted Image

Using the GUI is rather straight-forward. Type your function(s) in the textbox, and press "Create machine code!" to have the machine code pasted onto the clipboard. For example, the C code:

MyFunction() {
	return 42;
}

MyFunction2() {
   return 43;
}
will generate this on the clipboard:

MCode(MyFunction, "6A2A58C3")
MCode(MyFunction2, "6A2B58C3")

How to use (command-line):

For better integration with text editors, MCodeGen also supports a command-line interface. The syntax is:

MCodeGen [options...] filepath
Available options are:

-minsize    Optimizes for minimum size (not compatible with -maxspeed)
-maxspeed   Optimizes for maximum speed (not compatible with -minsize)
-c          Compile as C code (not compatible with -cpp)
-cpp        Compile as C++ code (not compatible with -c)
-notify     Alert by notifications instead of message boxes
-x86        Compile for x86 target architecture
-x64        Compile for x64 target architecture
-warn[n]    Set warning level ([n] is between 0 and 4, e.g. -warn0)

If neither -minsize nor -maxspeed is specified, MCodeGen defaults to -minsize.
If neither -c nor -cpp is specfied, MCodeGen will choose by the file extension.
If neither -x86 or -x64 is specified, MCodeGen defaults to -x86.

Download
Last updated: August 17th, 2010

Changelog

August 17th, 2010

- More precise parsing
- Added support for x64

June 27th, 2010

- Now reloads the last code compiled on startup.

June 26th, 2010

- Fixed GUI exiting after compile error.


Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
Beautiful!

TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007
Cheers!

fincs
  • Moderators
  • 1662 posts
  • Last active:
  • Joined: 05 May 2007
Good!

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
A couple of little improvements could be made
- at a C syntax error the script should not terminate: now it gives no opportunity to fix the C code, we have to start all over
- the last C function edited could be made the default text the next time script starts, because we often try variants and extensions to the last function.

Saving the last 10 or so C source codes could be even better, so we can continue working on them, where we left off.

TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007

A couple of little improvements could be made
- at a C syntax error the script should not terminate: now it gives no opportunity to fix the C code, we have to start all over

Whoops! That wasn't part of the design. I forgot to test the GUI after implementing the command-line. I fixed it now.

- the last C function edited could be made the default text the next time script starts, because we often try variants and extensions to the last function.

Good idea! It could easily be implemented!

Saving the last 10 or so C source codes could be even better, so we can continue working on them, where we left off.

I'll see what I can come up with.

TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007
I added support for x64 machine code generation, for use with AHK_L x64.
Don't forget to also add a call to VirtualProtect in your MCode function!

stevel
  • Members
  • 133 posts
  • Last active: Nov 15 2013 12:32 AM
  • Joined: 12 Oct 2010
This script is a tremendous aid to simplifying using MCode!!!!

I noticed one thing that might save some confusion with those using it. Even if you select c++ as the desired language, the generated MCode seems to always be exactly the same (except for a mangled function name!) as if you selected c output. Check this out for yourself. What this means is that when you use the generated MCode in your script, you must use "CDecl" (since the MCode output is really in 'c' format even though you used c++ format for the original source code in the function). An easy and safe way to always check this (and save many headaches) is simply to test ErrorLevel immediately after trying your generated code in the 'DllCall()' statement in your script.
Example:
result := DllCall(&MyMCodeFunction, "UInt", aParam, "CDecl", "int")
If Errorlevel
   Msgbox, %Errorlevel%
See the 'DllCall()' help entry for using 'CDecll' with DllCall() for more, including the meaning of different error codes.

EDIT: Correction. See the next two comments. Whether or not 'CDecl' is needed in DllCall() depends on if '__stdcall' was used when compiling the C or C++ code. If it was used, then CDecl is not needed, otherwise it is needed.

Jamie
  • Members
  • 129 posts
  • Last active: Dec 02 2012 04:59 AM
  • Joined: 26 Mar 2010
CDecl has nothing to do with C vs C++. It's about whether the caller or callee does stack cleanup.

Add __stdcall to your C (or C++) code if you want to invoke without having to specify "CDecl".

uint __stdcall ptrtest(uint *p, uint *q) {
	uint t = 123;
	*p = *q;
	*q = t;
	return t;
}


stevel
  • Members
  • 133 posts
  • Last active: Nov 15 2013 12:32 AM
  • Joined: 12 Oct 2010
Jamie,
Thanks for the correction. My 'C' programming experience was a quick look 20 years ago. I had used MCodeGen.ahk, an excellent front end to make an otherwise difficult concept very approachable, and ran into error problems. That was until I realized the issue was using 'CDecl' correctly. I tried your example out with and without __stdcall and it worked perfectly. Using __stdcall with MCodeGen permitted use of DllCall() without the need for 'CDecl' while without __stdcall, 'CDecl' was needed (obviously, once the reason CDecl is needed is explained). I did note one problem with your example if anyone tries to duplicate my experiment: the term uint produced a compile error. So I changed it to:
unsigned int __stdcall ptrtest(unsigned int *p, unsigned int *q) 
{
   unsigned int t = 123;
   *p = *q;
   *q = t;
   return t;
}
and that compiled perfectly.

Edit Jan 13, 2011: A side effect to using __stdcall in your c/c++ code is that it mangles the function names. This effect doesn't matter for either MCode or RegisterCallback because the name of the exported dll function is not used. However, if for some reason to want to move the source code into a dll, if you use __stdcall, the mangled name will be needed in DllCall (note: WINAPI and CALLBACK are both defined as __stdcall in vc++). So, for exported dll functions, you are better off just not using __stdcall and adding "cdecl" to your DLLCall()'s so that you can transparently use your normal exported function names without having to keep track of their mangled names. If you are not aware of this, it can be a very elusive error that is difficult to track down (I know from personal experience). Note: you could solve the name mangling problem by using DEF files if you decide to use __stdcall in an exported function but it is much easier to not use __stdcall and add "Cdecl returnType", where 'returnType' is the type of the exported function's return value, to the end of DllCall.

JoeSchmoe
  • Members
  • 304 posts
  • Last active: Feb 28 2013 05:39 PM
  • Joined: 17 Feb 2008

This script will automate the conversion of C/C++ code into machine code useable by Laszlo's renowned MCode function. I do not consider it my script, because much of the information needed for it was provided by Laszlo himself as well as jamie. Thanks for the great work!

Bravo, all!

IsNull
  • Moderators
  • 990 posts
  • Last active: May 15 2014 11:56 AM
  • Joined: 10 May 2007
Simple to use and very powerful. Thank you! :D

Frankie
  • Members
  • 2930 posts
  • Last active: Feb 05 2015 02:49 PM
  • Joined: 02 Nov 2008
I use this any time I use MCode with AHK. Great tool!
aboutscriptappsscripts
Request Video Tutorials Here or View Current Tutorials on YouTube
Any code ⇈ above ⇈ requires AutoHotkey_L to run

stevel
  • Members
  • 133 posts
  • Last active: Nov 15 2013 12:32 AM
  • Joined: 12 Oct 2010
On a related matter: has anyone compiled a dll that worked in ahk using Visual C++ Express 2010? I used VC++ 2010 to produce the simplest of dll's but no matter what I try it keeps giving an 'A_Lasterror' message of 6 (invalid handle) even though the calculation does return a correct answer. I posted this problem at http://www.autohotke...pic.php?t=66941.

Frankie
  • Members
  • 2930 posts
  • Last active: Feb 05 2015 02:49 PM
  • Joined: 02 Nov 2008

has anyone compiled a dll that worked in ahk...

Yes. I use one dll to test all my functions before turning them to MCode.
Heres how to make a dll. Open VC++ Express and click new project. A window will pop up, on the left side click Win32. Then select "Win32 Console Application" and click OK.
A window pops up so click next. On the following screen there is an option for DLL in the header Application Type. Choose that and click finish.
I like to put the following line near the top of the main file (nameofdll.cpp).
#define DLL extern "C" __declspec(dllexport)
Then you can create functions to export like this:
DLL int sum(int a, int b) {
It's just a shortcut, if you don't put it like that, you still have to include that code before each function.

Edit: And in-case you don't know to call these functions you have to specify the name of the dll in the dllcall.
DllCall("nameofdll.dll\sum", "int" ...
aboutscriptappsscripts
Request Video Tutorials Here or View Current Tutorials on YouTube
Any code ⇈ above ⇈ requires AutoHotkey_L to run