Linear Gradient Fill example for MASM

This is an old example I've created for MASM, which was posted in MASM32 forum 2 years ago:
http://www.masm32.com/board/index.php?topic=5944.0

It has a simple approach of double buffering and working with MSIMG32 for the gradient fills.

If you're into drawing in windows (Win32), and you like to program in assembly language; this is example is for you.
Download the source from attachment, or copy the source codes below.


Cheers,

-chris

LinearGradient.asm


.386
.model flat, stdcall
option casemap:none
option proc:private

include windows.inc

include user32.inc
include kernel32.inc
include gdi32.inc
include msimg32.inc

includelib user32.lib
includelib kernel32.lib
includelib gdi32.lib
includelib msimg32.lib

include MsgCrack.inc

; ==========================================================
; Protos
; ==========================================================
WinMain proto :HINSTANCE, :HINSTANCE, :LPSTR, :dword
WndProc proto :HWND, :UINT, :WPARAM, :LPARAM
DrawFancyDivider proto :HDC, :ptr RECT

; ==========================================================
; MessageHandlers Protos
; ==========================================================
WmDestroy proto :HWND
WmCommand proto :HWND, :word, :HWND, :word
WmPaint proto :HWND

option dotname

; ==========================================================
; Local Macros
; ==========================================================
m2m    macro mem32A, mem32B
    push    mem32B
    pop        mem32A
endm

func macro functionName:req, functionParams:vararg
    invoke    functionName, functionParams
    exitm    <eax>
endm

; ==========================================================
; Data
; ==========================================================
.data?
    hInstance    dd ?
    hFont        HFONT ?
   
.data
    szClassName db "ChrisVega.WinLion", 0
    szWndText    db "Win32 Assembly ROCK!", 0
    lgFont        LOGFONT <-19, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, "Arial">
   
    szText        db "Linear GradientFill sample program by Chris Vega", 0
    szTextLen    dd $-szText-1

.const
    WND_WIDTH    = 540
    WND_HEIGHT    = 180
   
    mnuFileExit = 2001
    mnuHelpAbout= 3001

; ==========================================================
; Entry Point
; ==========================================================
.code
start:
    invoke    WinMain, func(GetModuleHandle, 0), NULL, NULL, SW_SHOW
    invoke    ExitProcess, 0
   
; ==========================================================
; WinMain
; ==========================================================
WinMain proc uses edi esi hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, CmdShow:dword

    local    hwnd:HWND   
    local    msg:MSG
    local    hMenu:HANDLE
    local    wc:WNDCLASSEX
   
    ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    ; Register the class
    ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    m2m        wc.hInstance, hInst
    mov        wc.lpszClassName, offset szClassName
    mov        wc.lpfnWndProc, offset WndProc
    mov        wc.style, CS_PARENTDC or CS_HREDRAW or CS_VREDRAW
    mov        wc.cbSize, sizeof WNDCLASSEX
    mov        wc.hIcon, func(LoadIcon, hInst, 100)
    mov        wc.hIconSm, eax
    mov        wc.hCursor, func(LoadCursor, NULL, IDC_ARROW)
    mov        wc.lpszMenuName, NULL
    mov        wc.cbClsExtra, 0
    mov        wc.cbWndExtra, 0
    mov        wc.hbrBackground, NULL
    .if        !func(RegisterClassEx, addr wc)
            ret
    .endif

    ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    ; Create the window
    ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    mov        edi, func(GetSystemMetrics, SM_CXSCREEN)
    shr        edi, 1
    mov        eax, WND_WIDTH
    shr        eax, 1
    sub        edi, eax
   
    mov        esi, func(GetSystemMetrics, SM_CYSCREEN)
    shr        esi, 1
    mov        eax, WND_HEIGHT
    shr        eax, 1
    sub        esi, eax

    invoke    CreateWindowEx,\
                WS_EX_APPWINDOW or WS_EX_WINDOWEDGE, \
                addr szClassName,\
                addr szWndText,\
                   WS_OVERLAPPEDWINDOW,\
                   edi,\
                   esi,\
                   WND_WIDTH,\
                   WND_HEIGHT,\
                   NULL,\
                   func(LoadMenu, hInst, 1000),\
                   hInst,\
                   NULL
    mov        hwnd, eax
   
    ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    ; Set the window font
    ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    mov        hFont, func(CreateFontIndirect, addr lgFont)

    ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    ; Make the window visible
    ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    invoke    SendMessage, hwnd, WM_SETICON, ICON_BIG or ICON_SMALL, func(LoadIcon, hInst, 1000)
    invoke    ShowWindow, hwnd, CmdShow
    invoke    UpdateWindow, hwnd
   
    ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    ; Messageloop (with IsDialogMessage)
    ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    .while TRUE
        invoke GetMessage, addr msg, hwnd, 0, 0
        .break .if eax!=TRUE
        .if !func(IsDialogMessage,hwnd,addr msg)
            invoke    TranslateMessage, addr msg
            invoke    DispatchMessage, addr msg
        .endif
    .endw
   
    ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    ; Exit WinMain
    ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    mov eax, msg.wParam
    ret
   
WinMain endp

; ==========================================================
; Window Procedure
; ==========================================================
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
   
    .handle_msg_begin
        .handle_msg WM_DESTROY, WmDestroy
        .handle_msg WM_COMMAND, WmCommand
        .handle_msg WM_PAINT, WmPaint
    .handle_msg_end
   
    invoke    DefWindowProc, hWnd, uMsg, wParam, lParam
    ret

WndProc endp

; ==========================================================
; DrawFancyDivider
; ==========================================================
DrawFancyDivider proc uses ebx edi hdc:HDC, lpRect:ptr RECT
    local    pen:HPEN
    local    pen2:HPEN
   
    mov        ebx, lpRect
    assume    ebx: ptr RECT
   
    invoke    CreatePen, PS_SOLID, 1, 00404040h
    mov        pen, eax
   
    invoke    CreatePen, PS_SOLID, 1, 00707070h
    mov        pen2, eax
   
    invoke    SelectObject, hdc, pen
    push    eax
   
    mov        edi, [ebx].top
    add        edi, 3
    invoke    MoveToEx, hdc, [ebx].left, edi, NULL
    invoke    LineTo, hdc, [ebx].right, edi
    dec        edi
    invoke    SelectObject, hdc, pen2
    invoke    MoveToEx, hdc, [ebx].left, edi, NULL
    invoke    LineTo, hdc, [ebx].right, edi
    sub        edi, 2
    invoke    SelectObject, hdc, pen2
    invoke    MoveToEx, hdc, [ebx].left, edi, NULL
    invoke    LineTo, hdc, [ebx].right, edi
    inc        edi
    invoke    SelectObject, hdc, func(GetStockObject, WHITE_PEN)
    invoke    MoveToEx, hdc, [ebx].left, edi, NULL
    invoke    LineTo, hdc, [ebx].right, edi
   
    invoke    DeleteObject, pen
    invoke    DeleteObject, pen2
   
    pop        eax
    invoke    SelectObject, hdc, eax

    ret
DrawFancyDivider endp

; ==========================================================
; WmDestroy : Handles WM_DESTROY message
; ==========================================================
WmDestroy proc hWnd:HWND
    invoke    PostQuitMessage, 0
    ret
WmDestroy endp

; ==========================================================
; WmCommand : Handles WM_COMMAND message
; ==========================================================
WmCommand proc hWnd:HWND, id:word, hwndCtl:HWND, codeNotify:word

    ; ----------------------------------------------
    .if id==mnuFileExit
   
    push    hWnd
    call    WmDestroy

    ; ----------------------------------------------
    .elseif id==mnuHelpAbout

    invoke    MessageBox, hWnd, addr szText, addr szWndText, MB_ICONINFORMATION

    ; ----------------------------------------------
    .endif
   
    ret
WmCommand endp

; ==========================================================
; WmPaint : Handles WM_PAINT message
; ==========================================================
WmPaint proc uses ebx hWnd:HWND

    local hdc:HDC
    local rect:RECT
    local sz:SIZEL
   
    local memDC:HDC
    local memBM:HBITMAP
   
    local mesh:GRADIENT_RECT
    local vertex[3]:TRIVERTEX
   
    ; ---------------------------------------------------------------------
    ; Get the handle to the device context
    ; ---------------------------------------------------------------------
    mov        hdc, func(GetDC, hWnd)
   
    ; ---------------------------------------------------------------------
    ; Get the client rectangle
    ; ---------------------------------------------------------------------
    invoke    GetClientRect, hWnd, addr rect
   
    ; ---------------------------------------------------------------------
    ; Create an off-screen device context (double buffering) [1]
    ; ---------------------------------------------------------------------
    mov        memDC, func(CreateCompatibleDC, hdc)
    mov        memBM, func(CreateCompatibleBitmap, hdc, rect.right, rect.bottom)
    invoke    SelectObject, memDC, memBM
   
    ; ---------------------------------------------------------------------
    ; Populate vertex 1 structure
    ; ---------------------------------------------------------------------
    lea        ebx, vertex
    assume    ebx: ptr TRIVERTEX
    m2m        [ebx].x, rect.left
    m2m        [ebx].y, rect.top
    mov        [ebx].Alpha, 0
    mov        [ebx].Red, 07d00h
    mov        [ebx].Green, 0aa00h
    mov        [ebx].Blue, 0c300h
   
    ; ---------------------------------------------------------------------
    ; Populate vertex 2 structure
    ; ---------------------------------------------------------------------
    add        ebx, sizeof TRIVERTEX
    m2m        [ebx].x, rect.right
    m2m        [ebx].y, rect.bottom
    mov        [ebx].Alpha, 0
    mov        [ebx].Red, 00100h
    mov        [ebx].Green, 02a00h
    mov        [ebx].Blue, 04400h
   
    ; ---------------------------------------------------------------------
    ; Set the mesh (gradient rectangle) point
    ; ---------------------------------------------------------------------
    mov        mesh.UpperLeft, 0
    mov        mesh.LowerRight, 1
   
    ; ---------------------------------------------------------------------
    ; Call GradientFill function
    ; ---------------------------------------------------------------------
    invoke    GradientFill, memDC, addr vertex, 2, addr mesh, 1, GRADIENT_FILL_RECT_V
   
    ; ---------------------------------------------------------------------
    ; Draw the text, centered to the window
    ; ---------------------------------------------------------------------
    invoke    SetBkMode, memDC, TRANSPARENT
    invoke    SelectObject, memDC, hFont
    invoke    GetTextExtentPoint32, memDC, addr szText, szTextLen, addr sz
    invoke    SetTextColor, memDC, 0
    mov        eax, sz.x
    shr        eax, 1
    mov        sz.x, eax
    mov        eax, sz.y
    shr        eax, 1
    mov        sz.y, eax
    mov        eax, rect.right
    sub        eax, rect.left
    shr        eax, 1
    sub        eax, sz.x
    mov        edx, rect.bottom
    sub        edx, rect.top
    shr        edx, 1
    sub        edx, sz.y
    push    eax
    push    edx
    invoke    TextOut, memDC, eax, edx, addr szText, szTextLen
    invoke    SetTextColor, memDC, 00f0f0f0h
    pop        edx
    pop        eax
    sub        edx, 2
    sub        eax, 2
    invoke    TextOut, memDC, eax, edx, addr szText, szTextLen
   
    ; ---------------------------------------------------------------------
    ; Draw some fancy divider
    ; ---------------------------------------------------------------------
    invoke    DrawFancyDivider, memDC, addr rect
   
    ; ---------------------------------------------------------------------
    ; Flush the result to the window
    ; ---------------------------------------------------------------------
    invoke    BitBlt, hdc, 0, 0, rect.right, rect.bottom, memDC, 0, 0, SRCCOPY
   
    ; ---------------------------------------------------------------------
    ; Release all the resources we've used
    ; ---------------------------------------------------------------------
    invoke    DeleteDC, memDC
    invoke    DeleteObject, memBM

    ; ---------------------------------------------------------------------
    ; Release the device context
    ; ---------------------------------------------------------------------
    invoke    ReleaseDC, hWnd, hdc
   
    ; Notes:
    ;    [1] We need to create an off-screen device context for this demo,
    ;        this is because filling a rectangle with GradientFill function
    ;        will take some time to complete, and shows a lot of flickering
    ;        if we let the function use the window's DC.
    ret
WmPaint endp


end start

Posted by cvega with 1 comment(s)
Filed under: ,

Using CIL to set/get values from fields and properties

Background:

I'm currently working on a freelance project to optimize (yay, optimization again!) a .NET Entity Persister library of a Software Development firm here in Makati City -- much like a custom built NHibernate, but heavily dependent on reflection to get/set field values (their library has no support for Properties). They hired me because they kind of complaining that their system is so slow, it is taking about several seconds (to minutes) just to retrieve some thousand records -- considering the internals of their library is built on top of DataReader (Imagine, looping DataReader to fill a collection of Entities). According to their big boss, using thrid party O/R solution is not an option, they have to put a fix to their current library.

Looking at the problem:

Assuming we have an entity class SampleEntity:

  public class SampleEntity {
    public string stringField = "Sample Value";
    public string StringProperty { get; set; }
   }

and here's how they are setting the field:

  /// <summary>

  /// Dynamic field setter

  /// </summary>

  public class FieldSetter {

    /// <summary>

    /// Set field dynamically

    /// </summary>

    public static void SetField(object instance,
                               string fieldName, object value) {

      var t = instance.GetType();

      var fieldInfo = t.GetField(fieldName,
                                 BindingFlags.Instance | BindingFlags.Public);

      if (fieldInfo == null)

        throw new ArgumentException("There is no publicly accessible " +

                                    fieldName +
                                    " field found in " + t.FullName + ".");

      fieldInfo.SetValue(instance, value);

    }

  }

the library is actually doing this in loop to setup an entire entity instance, and they repeatedly doing it until the DataReader says stop:

  /// <summary>

  /// Get all entities from underlying data store.

  /// </summary>

  public List<T> SelectAll() {

    Open();

    var selectAll = new SqlCommand(BuildSelectStatement<T>(), Connection);

    var reader = selectAll.ExecuteReader();

    var list = new List<T>();

    if (reader != null)

      while (reader.Read()) {

        var entity = default(T);

        for (var i = 0; i < reader.FieldCount; i++) {

          var fieldName = reader.GetName(i);

          var data = reader.GetData(i);

          FieldSetter.SetField(entity, fieldName, data);

        }

      }

    Close();

    return list;

  }

the only problem I've notice that may be the cause of slow execution is the use of reflection.

Doing it the hard way, and maybe the faster way:

If you play long enough with reflection, you will get the experience that it is a slow because of internal loop overheads (search for matching name and binding attributes).

The approach I thought to workaround the problem is to emit CIL codes directly and call them as dynamic method, something that look like:

   public void SetField(SampleEntity instance, string value) {
     instance.stringField = value;
   }

In CIL, this is how it is coded:

  .method public hidebysig instance void SetField(
          class SampleEntity instance, string 'value') cil managed

  {

    .maxstack 8

    SEG_0001: 0x0003  ldarg.0

    SEG_0002: 0x0004  ldarg.1

    SEG_0003: 0x007   stfld string SampleEntity::stringField

    SEG_0008: 0x002   ret

  }

The lines I highlighted in red are the lines I'm interrested in making dynamic, so let's work on a DynamicMethod for doing just that:

  // We still need to get the field information from reflection

  var fieldInfo = t.GetField(fieldName,
                             BindingFlags.Instance | BindingFlags.Public);

  if (fieldInfo == null)

    throw new ArgumentException("There is no publicly accessible " +
                                fieldName +
                                " field found in " + t.FullName + ".");

 

We only need to get the field information once, during the setup of our DynamicMethod:

  var setter = new DynamicMethod("__set_field_" + fieldName,
                                 null,
                                 new[] { t, fieldInfo.FieldType },
                                 typeof(FieldSetter));

  var setterIL = setter.GetILGenerator();


This is because we need the FieldInfo as a parameter to stfld:

  // ldarg.0 - load argument 1 to eval.stack.0
  setterIL.Emit(OpCodes.Ldarg_0);

   
// ldarg.1 - load argument 2 to eval.stack.1

  setterIL.Emit(OpCodes.Ldarg_1);      

  // stfld f - set the field f of instance stack.0 
  //           with the value from stack.1  

  setterIL.Emit(OpCodes.Stfld, fieldInfo); 
         
  // ret     - exit the method                                
  setterIL.Emit(OpCodes.Ret);               


If you take a closer look at the emitted OpCodes, you'll see that it is simply a replica of CIL above, but with a little twist --  the fieldInfo we've taken from given fieldName.

 

That means we are almost done, we just have to call the DynamicMethod we've created for assigning value to field like this:

 

  setter.Invoke(null,
         new object[] { t,
                        "Kamusta mundo, ok ka lang ba?" });

Saving it for succeeding calls:

There's not much improvement at all if we are going to create DynamicMethod repeatedly, in fact that's even slower than using reflection. We have to save the created DynamicMethods for succeeding calls.


Saving it to Dictionary and then retrieving it every time we have a need for it, will boost the performance real fast (because we only have to create DynamicMethod once for every field we want to set value).

 

Summing it all together, with addition of controlling the creation of setter DynamicMethods, we will be able to write a new FieldSetter class:

  public class FieldSetter {

    public static DynamicMethod GetFieldSetterMethod(object instance, string fieldName) {

      var t = instance.GetType();

      var key = (t.FullName + "_" + fieldName).Replace(".", "_");

      if (!fieldSetter.ContainsKey(key)) {

        lock (fsync) {

          // We still need to get the field information from reflection

          var fieldInfo = t.GetField(fieldName,
                          BindingFlags.Instance | BindingFlags.Public);

          if (fieldInfo == null)

            throw new ArgumentException("There is no publicly accessible " +
                                        fieldName +
                                        " field found in " + t.FullName + ".");

          var setter = new DynamicMethod("__set_field_" + key, null,
                                         new[] { t, fieldInfo.FieldType },
                                         typeof(FieldSetter));

          var setterIL = setter.GetILGenerator();

 

          // ldarg.0 - load argument 1 to eval.stack.0

          setterIL.Emit(OpCodes.Ldarg_0);          

         

          // ldarg.1 - load argument 2 to eval.stack.1
          setterIL.Emit(OpCodes.Ldarg_1);          

         
          // stfld f - set the field f of instance stack.0
          //           with the value from stack.1

          setterIL.Emit(OpCodes.Stfld, fieldInfo); 

                      
          // ret     - exit the method                             

          setterIL.Emit(OpCodes.Ret);              

 

          fieldSetter.Add(key, setter);

        }

      }

      return fieldSetter[key];

    }

 

    /// <summary>

    /// Set the field value of given instance, using the name of the field.

    /// </summary>

    /// <param name="instance">The instance.</param>

    /// <param name="fieldName">The name of the field.</param>

    /// <param name="value">The value to set.</param>

    public static object SetFieldValue(object instance,
                                       string fieldName,
                                       object value) {

      return GetFieldSetterMethod(instance, fieldName)
             .Invoke(null, new[] { instance });

    }

 

    private static readonly Dictionary<string, DynamicMethod> fieldSetter =
                        new Dictionary<string, DynamicMethod>();

    private static readonly object fsync = new object();

  }

That's about it; I hope you guys find it useful for your own purpose.

Did it worked?

After I've delivered the code to them, they immediately tested it.., and tested it.., and tested it more. Long story short, I guess I made them happy because I've got an extra from the paycheck, and the another deal to support property on their custom EntityPerstister.

I'll be working more with their library, specifically the adding of support to Property and Method with one parameter. That's not much of a work left, and I think I almost got everything (except for the method with one parameter, but it’s practically the same as Property since properties are methods too!).


More codes:

Here, take a look at the classes I've put-up for setting/getting field and property (if you don't know how I’ve implemented it, you can re-read this post, or read more about CIL and DynamicMethod):

// FieldSetter.cs

 

  public class FieldSetter {

    private static DynamicMethod GetFieldSetterMethod(
                                 object instance, string fieldName) {

      var t = instance.GetType();

      var key = (t.FullName + "_" + fieldName).Replace(".", "_");

      if (!fieldSetter.ContainsKey(key)) {

        lock (fsync) {

          // We still need to get the field information from reflection

          var fieldInfo = t.GetField(fieldName,
                                     BindingFlags.Instance |
                                     BindingFlags.Public);

          if (fieldInfo == null)

            throw new ArgumentException("There is no publicly " +                  
                                       
"accessible " +
                                        fieldName +
                                        " field found in " +
                                        t.FullName + ".");

          var setter = new DynamicMethod("__set_field_" + key,
                       null, new[] { t, fieldInfo.FieldType },
                       typeof(FieldSetter));

          var setterIL = setter.GetILGenerator();

 

          // ldarg.0 - load argument 1 to eval.stack.0

          setterIL.Emit(OpCodes.Ldarg_0);          

 

          // ldarg.1 - load argument 2 to eval.stack.1
          setterIL.Emit(OpCodes.Ldarg_1);          

         

          // stfld f - set the field f of instance stack.0
          //           with the value from stack.1

          setterIL.Emit(OpCodes.Stfld, fieldInfo); 

 

          // ret     - exit the method                               

          setterIL.Emit(OpCodes.Ret);              

 

          fieldSetter.Add(key, setter);

        }

      }

      return fieldSetter[key];

    }

 

    public static void SetFieldValue(
                 object instance, string fieldName, object value) {

      GetFieldSetterMethod(instance, fieldName)
                .Invoke(null, new[] { instance, value });

    }

 

    private static readonly Dictionary<string, DynamicMethod>
            fieldSetter = new Dictionary<string, DynamicMethod>();

    private static readonly object fsync = new object();

  }

 

// FieldGetter.cs

 

  public class FieldGetter {

    private static DynamicMethod GetFieldGetterMethod(
                            object instance, string fieldName) {

      var t = instance.GetType();

      var key = (t.FullName + "_" + fieldName).Replace(".", "_");

      if (!fieldGetters.ContainsKey(key)) {

        lock (fsync) {

          var fieldInfo = t.GetField(fieldName,
                            BindingFlags.Instance |
                            BindingFlags.Public);

          if (fieldInfo == null)

            throw new ArgumentException("There is no publicly " + 
                                        "accessible "
+ fieldName +
                                        " field found in " +
                                        t.FullName + ".");

          var getter = new DynamicMethod("__get_field_" + key,
                             fieldInfo.FieldType, new[] { t },
                             typeof(FieldGetter));

          var getterIL = getter.GetILGenerator();

 

          // ldarg.0  - load argument 0 to eval.stack.0

          getterIL.Emit(OpCodes.Ldarg_0);   

 

          // ldfld f  - get the value of field from
          // instance in eval.stack
 and store it
          // on top of eval.stack
                      

          getterIL.Emit(OpCodes.Ldfld, fieldInfo); 

          // ret - return what's on top of eval.stack           
          getterIL.Emit(OpCodes.Ret);              

 

          fieldGetters.Add(key, getter);

        }

      }

      return fieldGetters[key];

    }

 

    public static object GetFieldValue(
                object instance, string fieldName) {

      return GetFieldGetterMethod(instance, fieldName)
                .Invoke(null, new[] { instance });

    }

 

    private static readonly Dictionary<string, DynamicMethod>
             fieldGetters = new Dictionary<string, DynamicMethod>();

    private static readonly object fsync = new object();

  }

 

// PropertySetter.cs

 

  public class PropertySetter {

    private static DynamicMethod GetPropertySetterMethod(
                            object instance, string propertyName) {

      var t = instance.GetType();

      var key = (t.FullName + "_" + propertyName).Replace(".", "_");

      if (!propertySetter.ContainsKey(key)) {

        lock (fsync) {

          var propertyInfo = t.GetProperty(propertyName,
                                           BindingFlags.Instance |
                                           BindingFlags.Public);

          if (propertyInfo == null)

            throw new ArgumentException("There is no publicly " +
                                        "accessible " + propertyName +
                                        " property found in " +
                                        t.FullName + ".");

          if (!propertyInfo.CanWrite)

            throw new ArgumentException("The property " +
                                        propertyName +
                               " has no publicly accessible setter.");

          var setter = new DynamicMethod("__set_property_" + key, null,
                           new[] { t, propertyInfo.PropertyType },
                           typeof(PropertySetter));

          var setterIL = setter.GetILGenerator();

 

          // ldarg.0    - load argument 1 to eval.stack.0

          setterIL.Emit(OpCodes.Ldarg_0); 

 

          // ldarg.1    - load argument 2 to eval.stack.1
         
setterIL.Emit(OpCodes.Ldarg_1); 

          // callvirt p - call set_* method to set the
          // value from eval.stack.1
                             

          setterIL.Emit(OpCodes.Callvirt, propertyInfo.GetSetMethod());

          // ret        - exit the method

          setterIL.Emit(OpCodes.Ret);                                  

 

          propertySetter.Add(key, setter);

        }

      }

      return propertySetter[key];

    }

 

    public static void SetPropertyValue(
                 object instance, string propertyName, object value) {

      GetPropertySetterMethod(instance, propertyName)
                .Invoke(null, new[] { instance, value });

    }

 

    private static readonly Dictionary<string, DynamicMethod>
             propertySetter = new Dictionary<string, DynamicMethod>();

    private static readonly object fsync = new object();

  }

 

 

// PropertyGetter.cs

 

  public class PropertyGetter {

    private static DynamicMethod GetPropertyGetterMethod(
                               object instance, string propertyName) {

      var t = instance.GetType();

      var key = (t.FullName + "_" + propertyName).Replace(".", "_");

      if (!propertyGetters.ContainsKey(key)) {

        lock (fsync) {

          var propertyInfo = t.GetProperty(propertyName,
                                           BindingFlags.Instance |
                                           BindingFlags.Public);

          if (propertyInfo == null)

            throw new ArgumentException("There is no publicly " +
                                        "accessible "
+ propertyName +
                                        " property found in " +
                                        t.FullName + ".");

          if (!propertyInfo.CanRead)

            throw new ArgumentException("The property " + propertyName
                            + " has no publicly accessible getter.");

 

          var getter = new DynamicMethod("__get_property_" + key,
                            propertyInfo.PropertyType, new[] { t },
                            typeof(PropertyGetter));

          var getterIL = getter.GetILGenerator();

 

          // ldarg.0 - load argument 0 to eval.stack.0

          getterIL.Emit(OpCodes.Ldarg_0);    

 

          // callvirt m - a call to get_* method to get
          // the property value
                          

          getterIL.Emit(OpCodes.Callvirt, propertyInfo.GetGetMethod());

 

          // ret - return the result of get_* call

          getterIL.Emit(OpCodes.Ret);                                  

 

          propertyGetters.Add(key, getter);

        }

      }

      return propertyGetters[key];

    }

 

    public static object SetPropertyValue(
                 object instance, string propertyName) {

      return GetPropertyGetterMethod(instance, propertyName)
                .Invoke(null, new[] { instance });

    }

 

    private static readonly Dictionary<string, DynamicMethod>
           propertyGetters = new Dictionary<string, DynamicMethod>();

    private static readonly object fsync = new object();

  }

 


I hope this still fall under the category of assembly language Big Smile
(even though CIL is not exactly assembly language)

See you again next time.

 

 

 

Posted by cvega with 5 comment(s)
Filed under:

Optimization Manuals Updated

Agner Fog have updated his amazing set of optimization manuals, do check them out!

1. Optimizing software in C++: An optimization guide for Windows, Linux and Mac platforms
This is an optimization manual for advanced C++ programmers. Topics include: The choice of platform and operating system. Choice of compiler and framework. Finding performance bottlenecks. The efficiency of different C++ constructs. Multi-core systems. Parallelization with vector operations. CPU dispatching. Efficient container class templates. Etc.
 
File name: optimizing_cpp.pdf, size: 703576, last modified: 2009-Jan-23.
Download.
 
2. Optimizing subroutines in assembly language: An optimization guide for x86 platforms
This is an optimization manual for advanced assembly language programmers and compiler makers. Topics include: C++ instrinsic functions, inline assembly and stand-alone assembly. Linking optimized assembly subroutines into high level language programs. Making subroutine libraries compatible with multiple compilers and operating systems. Optimizing for speed or size. Memory access. Loops. Vector programming (XMM, SIMD). CPU-specific optimization and CPU dispatching.
 
File name: optimizing_assembly.pdf, size: 757202, last modified: 2009-Jan-23.
Download.
 
3. The microarchitecture of Intel and AMD CPU’s: An optimization guide for assembly programmers and compiler makers
This manual contains details about the internal working of various microprocessors from Intel and AMD. Topics include: Out-of-order execution, register renaming, pipeline structure, execution unit organization and branch prediction algorithms for each type of microprocessor. Describes many details that cannot be found in manuals from microprocessor vendors or anywhere else. The information is based on my own research and measurements rather than on official sources. This information will be useful to programmers who want to make CPU-specific optimizations as well as to compiler makers and students of microarchitecture.
 
File name: microarchitecture.pdf, size: 1093888, last modified: 2009-Jan-23.
Download.
 
4. Instruction tables: Lists of instruction latencies, throughputs and micro-operation breakdowns for Intel and AMD CPU's
Contains detailed lists of instruction latencies, execution unit throughputs, micro-operation breakdown and other details for all application instructions of most microprocessors from Intel and AMD. Intended as an appendix to the preceding manuals.
 
File name: instruction_tables.pdf, size: 982795, last modified: 2008-Aug-24.
Download.
 
5. Calling conventions for different C++ compilers and operating systems
This document contains details about data representation, function calling conventions, register usage conventions, name mangling schemes, etc. for many different C++ compilers and operating systems. Discusses compatibilities and incompatibilities between different C++ compilers. Includes information that is not covered by the official Application Binary Interface standards (ABI's). The information provided here is based on my own research and therefore descriptive rather than normative. Intended as a source of reference for programmers who want to make function libraries compatible with multiple compilers or operating systems and for makers of compilers and other development tools who want their tools to be compatible with existing tools.
 
File name: calling_conventions.pdf, size: 328903, last modified: 2009-Jan-23.
Download.

Cheers,

Cool

Posted by cvega with no comments
Filed under: ,

Setting-up your MASM32 development environment

To start programming assembly language in windows, you need to first setup your development environment. Hopefully, this post may help you get started.

Getting an Assembler/Linker:

I previously posted the list of assemblers/linker and where you can get them, here.

For this post, since I use MASM most of the time, I will be walking you through getting the MASM32 SDK package, as it contain lots of useful procedures, include files, libraries, help files, examples, tools and more.. At the time of writing, the SDK version is 10, get it here. Work around your way to the download area, and get the latest installer package (SDK version 10 is around 4MB).

Be sure to read and understand the license: http://www.masm32.com/mlicence.htm
Then regularly check the devpinoy assembler forum, as we regularly post updates, so you'll get only the latest.

Once you're done downloading the Masm32 SDK10 installer, run install.exe and follow the direction. Make sure you're installing it in a directory with no space in directory name, like "c:\masm32", not "c:\Program Files\mask32" -- this is because the assembler/linker that is included in the package is an old one who will throw an error if found spaces in paths. I suggest don't change the default installation folder, which is in %root%\masm32, where %root% is the root of your selected drive (e.g., C:\)


The first thing the installer will tell you is about some faulty anti-virus scanner who often flag MASM32 as infected or potentially dangerous, while it is really safe:

"Some AV scanners do not have properly developed heuristic scanning and produce false positives when scanning very small files that are common in assembler programming. This is unfortunately a consequence of rushed commercial demand and lack of programming skills on the part of some AV vendors who attempt to impose a subset of the Microsoft Portable Executable specifications for 32 bit Windows executable files to cover some of their own technical shortcomings.

The MASM32 SDK has been built in a fully isolated environment from its original source code in text format and has been successfully installed on millions of computers around the world and it does not contain any viral infection or trojan code.

If you installation is damaged or interfered with by an installed AV scanner you may need to change the settings so that it does not delete or damage files in the MASM32 installation"


This is your hint to turn-off your anti-virus scanner for a while., only during installation. Don't worry, as I said, it is safe.

After installation, you'll get a nice greeting telling you that installation is successful:


That's it! You now have a complete MASM assembler environment. You can now turn your anti-virus program back on., and include your masm32 directory to exclusion, so it won't bother you much about false-positives.

Now let's see the important directories created for us by MASM32:

%masm32%\help 
     in here you can find lots of useful HELP files. If you're a beginner, do check asmintro.chm and opcodes.chm.

%masm32%\examples
     in here you will find tons of examples. Do check them out everytime you need to learn how to get something done, you may find it in one of the examples.

%masm32%\include
    
in here, you will find include files mostly traslated from platform SDK for assembly programmers to include in their programs. It also contains masm32.inc include file that has all the defines and prototypes of MASM32 library. check masm32.chm for reference.

%masm32%\lib
     in here, you'll find library files mostly taken from platform SDK for assembly programmers to include in their programs. It also contains masm32.lib file, see description for \include

\bin
    
in here are the binaries for assembling, linking, dump, debug etc.,

%masm32%\tutorial
    has various tutorials for using the MASM32 package.

%masm32%\macros
    in here are the macros for making your assembly programming experience quick, easy, fun and challenging.

Additional Downloads:

Below are recomended downloads to help you on your learning experiences about assembly programming on windows:

Windows Platform SDK - You must have this one (the latest is Windows 7 SDK Beta).
Visual C++ 2008 Express Edition - A free C++ IDE from Microsoft. You can set it up for MASM programming.
Iczelion's Tutorials - Most beginners find these tutorials useful and informative.
MASM 8.0
- If you want the latest MASM binary from microsoft, get this and replace the old ones in your masm32\bin (be sure to make a backup before you replace them)
Processor Manuals - I'm using Intel processor, both IA32 and IA64. -- you can google for the manual of your processor for a more precise link.
Art of Assembly eBook - Get a free copy of AoA!
OllyDBG - A great free debugger, this is a must download.

Trying your new environment:

Open Quick Editor that is included in MASM32 package. It is located in %masm32%\qeditor.exe. Or simply double-click the desktop shortcut that was created for you by MASM32 installer (if you allowed desktop shortcut creation during install).

In Quick Editor, type this simple program (it's a simple message box program, don't worry for now if you can't understand it, you'll get used to it later):

include \masm32\include\masm32rt.inc

.data
   caption db "MASM32", 0
   text    db "It works!", 0

.code
start:

    invoke MessageBox, 0, addr text, addr caption, MB_OK or MB_ICONINFORMATION
    invoke ExitProcess, 0

end start


Save it (again to directory with no space in directory name - also, you filename should not contain space either) then go to "Project" and hit "Build All".
Quick editor will build the program for you!

Now run your program, click the "Program" menu, and hit "Run Program"
You should see a messagebox saying "It Works!":

Congratulation, you now have a working MASM32 installed in your system. Welcome to the club.

Next time, I'll walk you through more about Quick Editor, and how to setup an IDE for your assembly programming.

For now, it's already late. Until next time.

Cool

Posted by cvega with 2 comment(s)
Filed under:

An assembly language only blog

Kamusta mundo!

Always busy at work and have little time to spare on thinking what else "good" to blog about, let alone post. But hold on., I'm not saying this because I'm going to retire this blog, but actually I have a better plan.

After reviewing visit logs, I think posts that are about assembly programming has the most visits., which help me decide to limit my topic to mostly assembly language things, that's from now on.

Anything that's about assembly language that I have encountered., whether an inline assembly, MASM or other assemblers, ILAsm, or most things that got me interrested, I will blog.

So then, stay tuned and see you then next time.

Long live assembly language!

Cool

Posted by cvega with 3 comment(s)
Filed under:

Load PNG/JPEG from resource using GDI+ (MASM)

Following my previous post on how to load JPG/PNG file from resource using GDI+:
http://devpinoy.org/blogs/cvega/archive/2008/07/28/loading-png-and-jpg-image-from-resource-using-gdi.aspx

I’ve written an equivalent function for MASM32 users:
http://www.masm32.com/board/index.php?topic=10191.0

Just follow these simple steps and you’re set to use resource image in your program in no time.

    gdiplusLoadBitmapFromResource,
              hInstance,
              resourceName,
              resourceType,
              outImage

    where:
       hInstance      - the module handle where to load the resource
       resourceName   - the name or the ID of the resource
       resourceType   - string pointer that will indicate the type
                        of the resource., e.g., "PNG",0
       outImage       - address of variable where to put the handle
                        of loaded image


Here's how to use it:

1. Add the function gdiplusLoadBitmapFromResource to your program, or include gdiplusLoadBitmapFromResource.inc.

2. Add the proto (so you can use INVOKE to call gdiplusLoadBitmapFromResource):

gdiplusLoadBitmapFromResource proto :HMODULE, :LPSTR, :LPSTR, :DWORD


3. Initialize GDI+ on your program's start

GdiplusStartupInput struc
    GdiplusVersion dd ?
    DebugEventCallback dd ?
    SuppressBackgroundThread BOOL ?
    SuppressExternalCodecs BOOL ?
GdiplusStartupInput ends

.data
      gdiplusToken dd ?
      gdiplusSInput GdiplusStartupInput <1, NULL, FALSE, FALSE>

.code
      invoke GetModuleHandle, 0
      mov hInstance, eax
     
      ; Initialize GDI+
      invoke GdiplusStartup, addr gdiplusToken, addr gdiplusSInput, NULL


4. In your resource script, add your image with specified type, something like:

9000 PNG "myImage.png"


where
9000 is the ID of the resource, and PNG is the type

5. Add a null-terminated string entry to your data section for the type of resource, e.g., "PNG"

.data
    pngImage dd NULL
    pngType db "PNG", 0


6. Load the image using gdiplusLoadBitmapFromResource:

invoke gdiplusLoadBitmapFromResource, hInstance, 9000, addr pngType, addr pngImage


7. When you're done using the image, dispose it using GdipDisposeImage function:

invoke GdipDisposeImage, addr pngImage


8. Finally, shutdown GDI+ before you exit your program:

invoke GdiplusShutdown, gdiplusToken


Hope you find this little code useful.



Cheers,

-chris



 

 

Posted by cvega with no comments
Filed under:

[REDUX] Message Cracker for MASM

About 3 years ago, I’ve released a MASM version of message cracker for handling windows messages here:  http://devpinoy.org/forums/p/516/1524.aspx#1524

I really find this include file useful whenever I am working on a GUI based win32 program using MASM. Unfortunately, only few people know about it, so I hope this blog post will provide a late introduction about what this include file is all about.


About message cracker:


To make it simple, message cracker is a set of macros that you can line-up to your message-handling routine to enable window-message handling to a separate (or inline) procedure. This line-up of macro calls may improve the readability of your program compared to a long list of
.IF/.ELSEIF/.ENDIF.

To see the advantage of using a message-cracker, let’s see how a typical message-handling routine would look like:

WinProc proc hWnd:HWND, uMsg:dword, wParam:WPARAM, lParam:LPARAM
    LOCAL ps:PAINTSTRUCT

        .if uMsg == WM_INITDIALOG
            invoke LoadIcon, hInstance, ICON_APP
            invoke SendMessage, hWnd, WM_SETICON, ICON_BIG or ICON_SMALL, eax
        .elseif uMsg == WM_COMMAND
            mov eax,  wParam
            .if eax == ID_BUTTON1
            ; ID_BUTTON1 was accessed, handle the event here
            .elseif eax == ID_BUTTON2
            ; ID_BUTTON2 was accessed, handle the event here
            .endif
        .elseif uMsg == WM_PAINT
            invoke BeginPaint, hWnd, addr ps
            ; Peform paint routine here
            nvoke EndPaint, hWnd, addr ps
        .elseif uMsg == WM_CLOSE
              invoke EndDialog, hWnd, 0
        .endif

        xor eax,eax
        ret
WinProc endp

And that’s kind of clean and readable, because the procedure handles only 4 window-messages. However, you can imagine how this procedure will look like if it handles 20 or more window-messages. It will become a long procedure that is hard to trace and not too readable.

And as you have already known it, there’s a neat solution for that kind of situation. This is, to break the handler for each window-message to their own respective handler-procedure. If I break-up a the example above, it will be done similar to:

WinProc proc hWnd:HWND, uMsg:dword, wParam:WPARAM, lParam:LPARAM
      .if uMsg == WM_INITDIALOG
            push hWnd
            call WmInitDialog
        .elseif uMsg == WM_COMMAND
            push hWnd
            push wParam
            call WmCommand
        .elseif uMsg == WM_PAINT
            push hWnd
            call WmPaint
        .elseif uMsg == WM_CLOSE
              invoke EndDialog, hWnd, 0
        .endif

        xor eax,eax
        ret                
WinProc endp

WmInitDialog proc hWnd:HWND
      invoke      LoadIcon, hInstance, ICON_APP
      invoke      SendMessage, hWnd, WM_SETICON, ICON_BIG or ICON_SMALL, eax
      ret
WmInitDialog endp

WmCommand proc hWnd:HWND, wParam:WPARAM
      mov eax, wParam
      .if eax == ID_BUTTON
      ; ID_BUTTON was accessed, handle the event here
      .elseif eax == ID_BUTTON2
      ; ID_BUTTON2 was accessed, handle the event here
      .endif
      ret
WmCommand endp

WmPaint proc hWnd:HWND
      LOCAL ps:PAINTSTRUCT
      invoke BeginPaint, hWnd, addr ps
      ; Peform paint routine here
      invoke EndPaint, hWnd, addr ps
      ret
WmPaint endp

Then, the more window-messages you add, the more handler-procedure you will need to add as well. Or you may leave it inline if the handler contains only 1 line, similar to what I’ve done to
WM_CLOSE above.

The idea of a message-cracker is just that -> Break the handler for each window-message to their own respective handler-procedure. In addition, the message-cracker helps you get the needed information for quickly handing a particular message.

For example, the
WM_MOUSEMOVE message passes the x and y coordinates of mouse-pointer into LPARAM. You need to extract the high-word (y) and low-word (x) from LPARAM to actually use the x and y coordinate.

When assigning a handler-procedure to handle a window-message, message-cracker will actually do much of the work for these small details. Your handler-procedure will receive only the needed information (argument) to work with the window-message itself.

Here’s how the handler of WM_MOUSEMOVE looks like:

WmMouseMove proc hWnd:HWND, x:DWORD, y:DWORD
      ; add code to handle mouse move
      ret
WmMouseMove endp

There’s no more
LPARAM to worry about. Your handler-procedure will receive x and y coordinates, as it should.


Using it:


First you need to get the message-cracker include file. Download the attachment, and extract the file MsgCrack.inc.

In your program, include the MsgCrack.inc

include MsgCrack.inc

Then you’re ready message cracking.


How to add handler

Inside your window procedure, start cracking messages with this block:

.handle_msg_begin
.handle_msg_end

The .handle_msg_begin accepts 4 optional arguments:

.handle_msg_begin [HWND], [MSG], [WPARAM], [LPARAM], [REG]

The default is:
  HWND = hWnd
  MSG = uMsg
  WPARAM = lParam
  LPARAM = wParam
  REG = EAX


If your window procedure is defined this way:

WndProc proc hWnd:HWND, uMsg:dword, wParam:WPARAM, lParam:LPARAM
   xor eax, eax
   ret
WndProc endp


Where all the arguments matches the default arguments, then you don’t need to specify anything, just add the block as is:

WndProc proc hWnd:HWND, uMsg:dword, wParam:WPARAM, lParam:LPARAM
  .handle_msg_begin
  .handle_msg_end

   xor eax, eax
   ret
WndProc endp

However, if your window procedure is defined differently, something like this one:

WndProc proc hWin:DWORD, uMsg:DWORD, aParam:DWORD, bParam:DWORD
   xor eax, eax
   ret
WndProc endp

Then you have to tell the message-cracker which identifier should be used:

WndProc proc hWin:DWORD, uMsg:DWORD, aParam:DWORD, bParam:DWORD
  .handle_msg_begin hWin, uMsg, aParam, bParam, eax
  .handle_msg_end

   xor eax, eax
   ret
WndProc endp


That’s the quick part of it. Check the comment I’ve written inside MsgCrack.inc for detail about these default identifier.

Now, let’s move to the next part. Let’s register a handler-procedure with window-message.  This is done using the macro
.handle_msg with the following arguments:

.handle_msg <window message constant>, <handler function>

Where
<window message constant> is the constant defined in windows.inc include file (MASM32), WM_PAINT, WM_MOUSEMOVE and WM_CLOSE, are some of the window-message constant. The macro won’t work if you used integer value, so you should always use the defined constant. Then the <handler function> is the name of your handler-procedure.

Here’s the similar code above, redefined to use the message cracker:

WinProc proc hWnd:HWND, uMsg:dword, wParam:WPARAM, lParam:LPARAM
      .handle_msg_begin
            .handle_msg WM_INITDIALOG, WmInitDialog
            .handle_msg WM_COMMAND, WmCommand
            .handle_msg WM_PAINT, WmPaint
            .handle_msg_inline WM_CLOSE
                  invoke EndDialog, hWnd, 0
      .handle_msg_end

        xor eax,eax
        ret                
WinProc endp

WmInitDialog proc hWnd:HWND, defCtrl:HWND, initData:dword
      invoke      LoadIcon, hInstance, ICON_APP
      invoke      SendMessage, hWnd, WM_SETICON, ICON_BIG or ICON_SMALL, eax
      ret
WmInitDialog endp

WmCommand proc hWnd:HWND, id:dword, hWndCtl:HWND, codeNotify:dword
      .if id == ID_BUTTON
      ; ID_BUTTON was accessed, handle the event here
      .elseif id == ID_BUTTON2
      ; ID_BUTTON2 was accessed, handle the event here
      .endif
      ret
WmCommand endp

WmPaint proc hWnd:HWND
      LOCAL ps:PAINTSTRUCT
      invoke BeginPaint, hWnd, addr ps
      ; Peform paint routine here
      invoke EndPaint, hWnd, addr ps
      ret
WmPaint endp

The noticeable difference is the replacement of .if/.elseif/.endif statements into .handle_msg_begin/.handle_msg/.handle_msg_inline/.handle_msg_end. And in the handler-procedures, the arguments have changed to reflect the information passed by the window-message (see the argument list of WmCommand handler).

Now, if you notice
WM_CLOSE message handling is different, because we don’t want to branch the handler to a separate handler-procedure, so we use .handle_msg_inline to indicate that WM_CLOSE handling follows on the next line (inline):

            .handle_msg_inline WM_CLOSE

Another good thing about message-cracker is, you can register similar window-messages to a single handler-procedure, if they share similar argument listing. For example, assigning 3 button-up messages,
WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP to WmButtonUp should be as easy as this:

      .handle_msg WM_LBUTTONUP, WmButtonUp
      .handle_msg WM_MBUTTONUP, WmButtonUp
      .handle_msg WM_RBUTTONUP, WmButtonUp


From this point, I’ve probably covered the how-to-use part of the include file., now let me tell you how you can create your handler-procedure.

Creating Handler Procedure:

Open MsgCrack.inc file, then search the window-message you want to handle e.g., WM_SETCURSOR.  You can see the defined macro for handling that window-message as:

; WM_handler(hWnd:HWND, hWndCursor:HWND, codeHitTest:dword, msg:dword)
.handle_WM_SETCURSOR macro in_hWnd, in_lParam, in_wParam, addr_handler

The part we are interested is the comment line above it, as:
WM_handler(argument-listing)

That’s your cue about the argument listing, inside the parentheses. Copy-it, then paste it in a new procedure, similar to this one:

WmSetCursor proc hWnd:HWND, hWndCursor:HWND, codeHitTest:dword, msg:dword
      ret
WmSetCursor endp

That’s it. For any questions, suggestions, bug-report, or any feedback, please post it below.

See the attachment for the sample program and the include file.

Happy coding.

-chris

 

Posted by cvega with 1 comment(s)
Filed under:

How To: OOP in assembly language

This post is a response to forum question posted by modchip:

"Recently, I've seen a lot of stuff about doing OOP in assembly language. Most of the stuff I've seen almost fried my brain. So... does anybody have some simple (by simple, I mean very simple) examples to get n00bs like me started? What are the basic requirements? What are its advantages? I would definitely want to learn more about this."


Definition:


Objects in assembly is implemented only by using structure (which serves as the class definition), defined to have its first member as a pointer to the class's virtual table (vtable), something like this:

    Animal struc
        vtable dd 0
        m_kind db 32 dup (0)
    Animal ends


Instance methods on the other hand are written as normal procedure having the “instance of the class“ as the first argument, known as the `this’ pointer, see these two methods for the Animal class I’ve written:

    GetKind@Animal proc $this:dword

       mov eax, $this                 ; setup the $this argument to EAX
       add eax, offset Animal.m_kind  ; Add the offset of member variable m_kind
       ret                            ; Return it

    GetKind@Animal endp

    SetKind@Animal proc uses esi edi $this:dword, lpValue:dword

       invoke GetKind@Animal, $this   ; Get the address of the member variable 
       invoke szCopy, lpValue, eax    ; Set it  with different value

       xor eax, eax
       ret

    SetKind@Animal endp


As you can see, there’s nothing fancy about writing methods, all you need is a naming convention that will help you work with unique namings. I use $this as the name of the `this’ pointer, and for method name, I use method name + ‘@’ character + name of the class who owns the method, thus GetKind@Animal and SetKind@Animal. For overloaded methods, I just append '@' + size of arguments. Something like, if I overloaded GetKind@Animal with argument for catching the output, I'll be writing it as: GetKind@Animal@4 where @4 means 1 DWORD argument pass the $this pointer.

Inside each methods, all you need is knowledge of working with assembly structures to get around with the $this pointer. In my example, I simply added the offset of the member I’m interested in, with the $this pointer:

    mov eax, $this                    ; setup the $this argument to EAX
    add eax, offset Animal.m_kind     ; Add the offset of member variable m_kind
my_class struc
        vtable dd 0
    my_class ends


Note: you only need vtable if there are virtual members defined (members that can be overridden by derived classes). I'll get to that on my next post.

This structure also holds all instance variables for that class.
Let’s assume we have a class called Animal with instance variable m_kind as 32 bytes, then our structure will be written like this:

That’s how I set register to point to the correct member variable. The code above, EAX now holds the effective address of Instance.m_kind. Then we can return it, or perform whatever logic we desire to that member variable.


Instanciation:

Creating an instance of the class is simply declaring a variable of type structure we’ve defined earlier:

     .data
       AnimalInstance Animal <>

Then call the constructor as "the first thing" before using the instance (if you want). C++ calls the constructor automagically for you (even creating default constructor for you), but in assembly, it’s up to you whether you want to call the constructor or not (you can actually implement constructorless objects).

Ok, assuming we've declared a default constructor ctor@Animal, calling it is similar to calling assembly procedure, passing the instance as the first argument:

    push offset AnimalInstance
    call ctor@Animal

Similar to calling the constructor above, calling the method is no different. Let’s assume we want to set the animal’s kind to “Bird” by calling the methof SetKind@Animal, you can do it this way: 

    .data
        AnimalInstance Animal <>
        animalInstanceKind db "Bird", 0

    .code
        push offset animalInstanceKind
        push offset AnimalInstance
        call SetKind@Animal

 I suggest to define a prototype for the methods, so we can use the MASM’s invoke:

     SetKind@Animal proto :dword, :dword

   
.code
        invoke SetKind@Animal, addr AnimalInstance, addr animalInstanceKind


Benefits:

I can't think of any good benefits, really. Implementing OOP in a non-OOP compiler is simply a kind of workaround which introduces much work and maintenance than working with procedural which is what's available in assembly language.

Benefits probably will count if OOP is available built-in in an assembler. HLA is one of the 'compiler' that provides this "built-in" functionality; and also, there's ObjAsm32 too, implementing OOP using set of MASM macros (emulating OOP keywords).



Closing:

That’s basically pretty much of it, practice and enjoy OOP in assembly language.
Thanks for reading. I’ll cover Overloading, Inheritance, Static and Virtual members on my next post.

Until the next time, happy coding.  

 

 

Posted by cvega with 2 comment(s)
Filed under: ,

C# seems to preserve left-hand value of an assignment statement

Consider this weird piece of code:

  int[] a = new int[] { 0, 1, 2 };

  int i = 2; // Point it to the last item of array

  // Set the value of array indexed by i while
  // changing the value of i
  a[ i ] = ++i + ++i;


The code above will not cause an array's bounds overflow.

The value of i was incremented (++i) then added to its another incremented value (+ ++i),
but for some reason the left hand part seems to remember the original value of i.

I didn't know that Big Smile

Posted by cvega with 6 comment(s)

Loading PNG (and JPG) image from resource using GDI+

Last night while I was translating some of my old animation program from GDI32 to GDI+, I’ve hit a roadblock where GDI+ cannot load PNG (and JPEG) file stored as resource: 

// This code doesn't work
Gdiplus::Bitmap* m_image = Gdiplus::Bitmap::FromResource(hInst, L"IDB_IMAGE1");

I’m thinking of an alternative using Bitmap::FromStream / FindResource / LoadResource combo, but I have one problem, I’m not familiar with Bitmap::FromStream. So I’ve checked CodeProject for some sample code on how to use Bitmap::FromStream, this I think will be a good start at what I want to do.

While I was searching for sample code, I’ve bumped on an article posted by Joe Woodbury entitled Loading JPG & PNG resources using GDI+ (glad I’ve searched CodeProject before going to MSDN). This article and the demo source code is exactly what I need, so I figure I will write a sample program using his CGdiPlusBitmapResource to test it.

Just to make things quicker and smaller, I’ve used David Nash's Win++ for this sample program:

The class CGdiPlusBitmapResource doesn’t need any documentation., all you have to do is create an instance of this class., and call it’s Load function and you’re technically done:

CGdiPlusBitmapResource* m_image = new CGdiPlusBitmapResource();
m_image->Load(IDB_IMAGE, _T("PNG"), hInst);

 

And draw it using Graphics object:

// Create graphics object from HDC
Gdiplus::Graphics g(hDC);

// Draw the PNG image using graohics object
g.DrawImage(*m_image, 0, 0);

 


That’s about it. Then you can delete the m_image when you’re done using it.
Check attached sample program for a working demo. It contains Win++ for writing C++ Win32 application, and CGdiPlusBitmap.h header file for loading images from resources.

If you want to know more about GDI+, here' a good article: Starting with GDI+

Posted by cvega with 2 comment(s)
Filed under: ,

WTL links

Definition taken from Wikipedia Big Smile

The Windows Template Library (WTL) is a free software, object-oriented C++ template library for Win32 development. WTL was created by Microsoft employee Nenad Stefanovic for internal use and later released as an unsupported add-on to Visual Studio and the Win32 Framework SDK. It was developed primarily as a light-weight alternative to the Microsoft Foundation Classes and builds upon Microsoft's ATL, another lightweight API widely used to create COM and ActiveX libraries.

As the subject says, this post only contains useful links about this wonderful library:

Home of WTL in Sorceforge
WTL download from Microsoft download center
WTL on CodeProject - If you're an MFC programmer, check the series WTL for MFC programmers.
GameDev.NET - Using the Windows Template Library part 1
GameDev.NET - Using the Windows Template Library part 2
WTL Wiki
Chris Sells's WTL Makes UI Programming a Joy, Part 1: The Basics
Chris Sells's WTL Makes UI Programming a Joy Part 2: The Bells and Whistles
vicsoe.dk WTL samples

I've also attached the Clipcode's WTL developer's guide ebook (the original link seems to be down at the moment)

Finally, don't forget to join the WTL User Group

Posted by cvega with no comments
Filed under: ,

I'm back :)

Hi guys,

I can't believe my eyes that It's already been 2 years since my last post here. Wow, time flies really fast! 
My hands up, I'm not going to make any excuses for my long absence, the important thing is that I found my way back to DevPinoy Cool

Been busy working with different technologies for the past 2 years, also experienced some bad turns in career shifts etch..
I thought it might be a good refresher to write something about what I learned in my blog.., but I’m kind-of thinking what exactly to write.

Any suggestions?

Posted by cvega with 7 comment(s)

Arrows available in Wingdings 3

Let me show you another good use of applying the trick I've posted earlier, when I wrote the "how-to" for making .NET password field to look more like an XP password field – the trick is done by playing with Fonts.

Now, let's play with fonts even more to have our UI some "arrows" displayed on form without the need to use any arrow-image and/or arrow icons. See the screen-shot below for possible use:



The form above has button displaying up and down arrows, and using the same trick, the arrow buttons doesn't used any images. It is setup using the characters small letter H ('h') and small letter I ('i') with it's font set to Wingdings 3.

Here's the steps in making up arrow button:

1. Add a button
2. Set the button's font to Wingdings 3.
3. Set the Text property to small letter H ('h').

And here's the steps in making the down arrow button:

1. Add a button
2. Set the button's font to Wingdings 3.
3. Set the Text property to small letter I ('i').

In case you might need different arrows, other than up and down arrows, or you want different styles of arrows, here's a small list I've come up which are available arrows inside Wingdings 3:

Play around with the font even more, and you'll see that there are more arrows you can choose from.

Have fun coding your UI!

Cheers,

-chris

Posted by cvega with 2 comment(s)
Filed under:

.NET Password field that looks like Windows XP password field

Here's a trick to make your regular .NET TextBox to have a look similar to Windows XP password field, where it displays large black circles instead of asterisks (****) to "mask" the password (see the Password field shown in the screenshot below):



This trick is fairly easy, and it doesn't require you to perform any complicated owner drawings.

Here's how:

1. Add a TextBox to your Form
2. Set the Font of that TextBox to Wingdings (not Webdings)
3. Set the PasswordChar property to small letter L ('l').

And you're all set, quick and easy.

If you want your password field to have customized look and feel other than the one I described, you may want to experiment using different characters other than small letter L, or use Symbols Font, for more symbols.

Happy coding

-chris

Posted by cvega with 1 comment(s)
Filed under:

Clone a class by using MemberwiseClone method

I am currently working on a project that I accepted to "continue" because the original freelance programmer left the project without completing it. The project was started using VB.NET, and as the company requested, I am now converting it to C# before I go ahead to completing it.

While I'm doing the conversion, I've seen many parts in the codes that are in need of attention. One that I spotted quickly is how the project implemented the Clone method for all cloneable classes (making a copy of the instance rather, as opposed to referencing an instance using the equal (=) assignment operator).

Below is a shorter version how the implementation of a Profile class would look like, converted to C#:

public class Profile : ICloneable
{

 private string m_firstname;
 public string FirstName
 {
  get { return m_firstname; }
  set { m_firstname = value; }
 }

 private string m_lastname;
 public string LastName
 {
  get { return m_lastname; }
  set { m_lastname = value; }
 }

 private int m_age;
 public int Age
 {
  get { return m_age; }
  set { m_age = value; }
 }

 object ICloneable.Clone()
 {
  return this.Clone();
 }

 public Profile Clone()
 {
  Profile temp = new Profile();
  temp.FirstName = this.FirstName;
  temp.LastName = this.LastName;
  temp.Age = this.Age;

  return temp;
 }
}


The above class was purposely shortened, but as you may have imagined, the class has more properties than just FirstName, LastName, and Age, hence the more properties the Profile class have, the larger the implementation of the Clone method. Not very manageable.

The simpliest way to shorten the Clone method is to call the object's MemberwiseClone method, which is provided by .NET to make a shallow copy of an object's instance -- rather than one-by-one copying all the properties, as shown above.

Here's how the updated version would look like:

public class Profile : ICloneable
{
 private string m_firstname;
 public string FirstName
 {
  get { return m_firstname; }
  set { m_firstname = value; }
 }

 private string m_lastname;
 public string LastName
 {
  get { return m_lastname; }
  set { m_lastname = value; }
 }

 private int m_age;
 public int Age
 {
  get { return m_age; }
  set { m_age = value; }
 }

 object ICloneable.Clone()
 {
  return this.MemberwiseClone();
 }

 public Profile Clone()
 {
  return (Profile)this.MemberwiseClone();
 }
}

I am aware that MemberwiseClone uses reflection to make a shallow copy, therefore it won't copy publicly exposed variables.

Anyway, this will be another busy month for me -- work, work, work.

Posted by cvega with no comments
More Posts Next page »