├── .gitignore ├── README.md ├── SUMMARY.md ├── additional-resources.md ├── assets ├── CodeShotOptions.gif ├── GetDlgItemHandle.png ├── HotMenu.gif ├── HotMenuStatic.png ├── IDC_SB2.png ├── KSR - fearless-grey150x140.png ├── KSR - fearless-white250x240.png ├── SimpleButtonDemo.gif ├── SimpleButtonDemoDefaults.gif ├── SimpleButtonGetProperty.gif ├── SimpleButtonGetPropertyAutoComplete.gif ├── SimpleButtonResourceCreation.png ├── SimpleButtonResourceCreation2.png ├── SteamClientMenu.gif ├── SteamClientMenu.png ├── SteamClientMenuStatic.png ├── SteamClientMenus.gif ├── cover_tiny.png ├── mrfearless.jpg ├── win32controls.png ├── win32controls_small.png ├── win32stdcontrols.png └── x64dbgUpdateChecker.gif ├── author.md ├── book.json ├── control-properties.md ├── control-properties ├── internal-wrapper-functions.md ├── property-structures-&-constants.md ├── radasm-auto-complete.md ├── the-memory-used-to-store-properties.md ├── using-macros-to-getset-properties.md └── using-the-win32-api-to-getset-properties.md ├── controls-and-modern-ui-design.md ├── cover.jpg ├── cover_small.jpg ├── creating-our-control.md ├── guidelines.md ├── initializing-our-control.md ├── inside-our-control.md ├── inside-our-control ├── handling-other-messages-for-our-control.md ├── on-creation-wmcreate.md ├── on-destroying-wmncdestroy.md └── the-memory-used-to-store-our-controls-properties.md ├── introduction.md ├── our-first-control.md ├── our-first-control ├── external-end-user-functions.md └── internal-developer-functions.md ├── painting-our-control.md ├── registering-our-control.md ├── styles ├── ebook.css ├── pdf.css └── website.css ├── the-hotmenu-quest.md ├── the-modernui-framework.md └── using-our-control.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Node rules: 2 | ## Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 3 | .grunt 4 | 5 | ## Dependency directory 6 | ## Commenting this out is preferred by some people, see 7 | ## https://docs.npmjs.com/misc/faq#should-i-check-my-node_modules-folder-into-git 8 | node_modules 9 | 10 | # Book build output 11 | _book 12 | 13 | # eBook build output 14 | *.epub 15 | *.mobi 16 | *.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Creating Controls In Assembler 2 | 3 | ![](/assets/cover_tiny.png) 4 | 5 | A book, by [mrfearless](https://github.com/mrfearless), published on [Gitbook.com](/Gitbook.com), about creating controls in assembly language. 6 | 7 | The book introduces the reader to my journey and techniques I discovered and evolved over time, for creating custom controls using the windows win32 API and Microsoft's Macro Assembler \(Masm\). 8 | 9 | It covers the main areas of developing an example control, SimpleButton, which the reader can then use as basis for creating their own custom controls. 10 | 11 | * The Github repository for this book can be found here: [https://github.com/mrfearless/creating-controls-in-assembler](https://github.com/mrfearless/creating-controls-in-assembler) 12 | * The Github repository for the SimpleButton example control is here: [https://github.com/mrfearless/SimpleButton](https://github.com/mrfearless/SimpleButton) 13 | * This Gitbook can be found online here: [https://mrfearless.gitbooks.io/creating-controls-in-assembler](https://mrfearless.gitbooks.io/creating-controls-in-assembler) 14 | * Read or download: [![Online](https://img.shields.io/badge/gitbook-online-brightgreen.svg)](https://mrfearless.gitbooks.io/creating-controls-in-assembler) [![PDF](https://img.shields.io/badge/gitbook-pdf-green.svg)](https://www.gitbook.com/download/pdf/book/mrfearless/creating-controls-in-assembler) [![ePUB](https://img.shields.io/badge/gitbook-epub-yellowgreen.svg)](https://www.gitbook.com/download/epub/book/mrfearless/creating-controls-in-assembler) [![Mobi/Kindle](https://img.shields.io/badge/gitbook-mobi-yellow.svg)](https://www.gitbook.com/download/mobi/book/mrfearless/creating-controls-in-assembler) 15 | * You can contact me: [![Email :](https://img.shields.io/badge/email-sendmail-6C2FDE.svg)](mailto:fearless.is.my.name@gmail.com) [![Twitter:](https://img.shields.io/badge/twitter-fearless0-26A9E9.svg)](https://twitter.com/fearless0) [![Github :](https://img.shields.io/badge/github-mrfearless-7A8E97.svg)](https://github.com/mrfearless) 16 | 17 | [![Creative Commons License](https://i.creativecommons.org/l/by-sa/4.0/88x31.png)](http://creativecommons.org/licenses/by-sa/4.0/) This work is licensed under a [Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/). 18 | 19 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | * [Preface](/README.md) 4 | * [Author](/author.md) 5 | * [Guidelines](/guidelines.md) 6 | * [Introduction](/introduction.md) 7 | * [Controls & Modern UI Design](/controls-and-modern-ui-design.md) 8 | * [The HotMenu Quest](/the-hotmenu-quest.md) 9 | * [Our First Control](/our-first-control.md) 10 | * [External End-User Functions](/our-first-control/external-end-user-functions.md) 11 | * [Internal Functions](/our-first-control/internal-developer-functions.md) 12 | * [Registering Our Control](/registering-our-control.md) 13 | * [Creating Our Control](/creating-our-control.md) 14 | * [Inside Our Control](/inside-our-control.md) 15 | * [On Creation: WM\_CREATE](inside-our-control/on-creation-wmcreate.md) 16 | * [On Destroying: WM\_NCDESTROY](inside-our-control/on-destroying-wmncdestroy.md) 17 | * [Handling Other Messages For Our Control](/inside-our-control/handling-other-messages-for-our-control.md) 18 | * [Initializing Our Control](/initializing-our-control.md) 19 | * [Painting Our Control](/painting-our-control.md) 20 | * [Using Our Control](/using-our-control.md) 21 | * [Control Properties](/control-properties.md) 22 | * [The Memory Used To Store Properties](/control-properties/the-memory-used-to-store-properties.md) 23 | * [Property Structures & Constants](/control-properties/property-structures-&-constants.md) 24 | * [Using Macros To Get/Set Properties](/control-properties/using-macros-to-getset-properties.md) 25 | * [Using The Win32 API To Get/Set Properties](/control-properties/using-the-win32-api-to-getset-properties.md) 26 | * [Internal Wrapper Functions](/control-properties/internal-wrapper-functions.md) 27 | * [Additional Resources](/additional-resources.md) 28 | * [RadASM Auto-complete](/control-properties/radasm-auto-complete.md) 29 | * [The ModernUI Framework](/the-modernui-framework.md) 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /additional-resources.md: -------------------------------------------------------------------------------- 1 | # Additional Resources 2 | 3 | Other online tutorials about custom contol creation: 4 | 5 | | Author | Topic | URL | 6 | | :--- | :--- | :--- | 7 | | Martin Mitáš | Custom Controls in Win API | [www.codeproject.com/Articles/559385/Custom-Controls-in-Win-API-The-Basics](https://www.codeproject.com/Articles/559385/Custom-Controls-in-Win-API-The-Basics) | 8 | | GunnerInc | Creating a hyperlink | [www.dreamincode.net/forums/topic/241669-masm-creating-a-hyperlink/](http://www.dreamincode.net/forums/topic/241669-masm-creating-a-hyperlink/) | 9 | | Forhad Reza | Clock Frame Design Using Assembly | [www.codeproject.com/Tips/1039519/Clock-Frame-Design-Using-Assembly](https://www.codeproject.com/Tips/1039519/Clock-Frame-Design-Using-Assembly) | 10 | | ZetCode | Burning Control | [www.zetcode.com/gui/winapi/customcontrols](https://www.zetcode.com/gui/winapi/customcontrols/) | 11 | | Catch22 | Custom Controls | [www.catch22.net/tuts/win32/custom-controls](https://www.catch22.net/tuts/win32/custom-controls/) | 12 | | Dan Brindle | Writing Windows Custom Controls \(VCR Style Button\) | [www.drdobbs.com/windows/writing-windows-custom-controls/184409155](https://www.drdobbs.com/windows/writing-windows-custom-controls/184409155) | 13 | | Joseph M. Newcomer | Self-Registering Windows Classes \(Compass Control\) | [www.flounder.com/selfregister.htm](http://www.flounder.com/selfregister.htm) | 14 | 15 | Assemblers: 16 | 17 | | Name | Website | 18 | | :--- | :--- | 19 | | MASM32 SDK | [www.masm32.com/download.htm](https://masm32.com/download.htm) | 20 | | UASM \(formerly JWasm/HJWasm\) | [www.terraspace.co.uk/uasm.html](https://www.terraspace.co.uk/uasm.html) | 21 | 22 | Other Resources: 23 | 24 | | Name | Website | 25 | | :--- | :--- | 26 | | ModernUI Project | [https://github.com/mrfearless/ModernUI](https://github.com/mrfearless/ModernUI) | 27 | | ModernUI64 Project | [https://github.com/mrfearless/ModernUI64](https://github.com/mrfearless/ModernUI64) | 28 | | RadASM | [https://github.com/mrfearless/RadASM2](https://github.com/mrfearless/RadASM2) | 29 | | x64dbg x86 & x64 Debugger | [https://github.com/x64dbg/x64dbg](https://github.com/x64dbg/x64dbg) | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /assets/CodeShotOptions.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrfearless/creating-controls-in-assembler/1234c21616a4eb12932f05f8878371dc520d940e/assets/CodeShotOptions.gif -------------------------------------------------------------------------------- /assets/GetDlgItemHandle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrfearless/creating-controls-in-assembler/1234c21616a4eb12932f05f8878371dc520d940e/assets/GetDlgItemHandle.png -------------------------------------------------------------------------------- /assets/HotMenu.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrfearless/creating-controls-in-assembler/1234c21616a4eb12932f05f8878371dc520d940e/assets/HotMenu.gif -------------------------------------------------------------------------------- /assets/HotMenuStatic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrfearless/creating-controls-in-assembler/1234c21616a4eb12932f05f8878371dc520d940e/assets/HotMenuStatic.png -------------------------------------------------------------------------------- /assets/IDC_SB2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrfearless/creating-controls-in-assembler/1234c21616a4eb12932f05f8878371dc520d940e/assets/IDC_SB2.png -------------------------------------------------------------------------------- /assets/KSR - fearless-grey150x140.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrfearless/creating-controls-in-assembler/1234c21616a4eb12932f05f8878371dc520d940e/assets/KSR - fearless-grey150x140.png -------------------------------------------------------------------------------- /assets/KSR - fearless-white250x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrfearless/creating-controls-in-assembler/1234c21616a4eb12932f05f8878371dc520d940e/assets/KSR - fearless-white250x240.png -------------------------------------------------------------------------------- /assets/SimpleButtonDemo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrfearless/creating-controls-in-assembler/1234c21616a4eb12932f05f8878371dc520d940e/assets/SimpleButtonDemo.gif -------------------------------------------------------------------------------- /assets/SimpleButtonDemoDefaults.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrfearless/creating-controls-in-assembler/1234c21616a4eb12932f05f8878371dc520d940e/assets/SimpleButtonDemoDefaults.gif -------------------------------------------------------------------------------- /assets/SimpleButtonGetProperty.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrfearless/creating-controls-in-assembler/1234c21616a4eb12932f05f8878371dc520d940e/assets/SimpleButtonGetProperty.gif -------------------------------------------------------------------------------- /assets/SimpleButtonGetPropertyAutoComplete.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrfearless/creating-controls-in-assembler/1234c21616a4eb12932f05f8878371dc520d940e/assets/SimpleButtonGetPropertyAutoComplete.gif -------------------------------------------------------------------------------- /assets/SimpleButtonResourceCreation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrfearless/creating-controls-in-assembler/1234c21616a4eb12932f05f8878371dc520d940e/assets/SimpleButtonResourceCreation.png -------------------------------------------------------------------------------- /assets/SimpleButtonResourceCreation2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrfearless/creating-controls-in-assembler/1234c21616a4eb12932f05f8878371dc520d940e/assets/SimpleButtonResourceCreation2.png -------------------------------------------------------------------------------- /assets/SteamClientMenu.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrfearless/creating-controls-in-assembler/1234c21616a4eb12932f05f8878371dc520d940e/assets/SteamClientMenu.gif -------------------------------------------------------------------------------- /assets/SteamClientMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrfearless/creating-controls-in-assembler/1234c21616a4eb12932f05f8878371dc520d940e/assets/SteamClientMenu.png -------------------------------------------------------------------------------- /assets/SteamClientMenuStatic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrfearless/creating-controls-in-assembler/1234c21616a4eb12932f05f8878371dc520d940e/assets/SteamClientMenuStatic.png -------------------------------------------------------------------------------- /assets/SteamClientMenus.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrfearless/creating-controls-in-assembler/1234c21616a4eb12932f05f8878371dc520d940e/assets/SteamClientMenus.gif -------------------------------------------------------------------------------- /assets/cover_tiny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrfearless/creating-controls-in-assembler/1234c21616a4eb12932f05f8878371dc520d940e/assets/cover_tiny.png -------------------------------------------------------------------------------- /assets/mrfearless.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrfearless/creating-controls-in-assembler/1234c21616a4eb12932f05f8878371dc520d940e/assets/mrfearless.jpg -------------------------------------------------------------------------------- /assets/win32controls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrfearless/creating-controls-in-assembler/1234c21616a4eb12932f05f8878371dc520d940e/assets/win32controls.png -------------------------------------------------------------------------------- /assets/win32controls_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrfearless/creating-controls-in-assembler/1234c21616a4eb12932f05f8878371dc520d940e/assets/win32controls_small.png -------------------------------------------------------------------------------- /assets/win32stdcontrols.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrfearless/creating-controls-in-assembler/1234c21616a4eb12932f05f8878371dc520d940e/assets/win32stdcontrols.png -------------------------------------------------------------------------------- /assets/x64dbgUpdateChecker.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrfearless/creating-controls-in-assembler/1234c21616a4eb12932f05f8878371dc520d940e/assets/x64dbgUpdateChecker.gif -------------------------------------------------------------------------------- /author.md: -------------------------------------------------------------------------------- 1 | # Author 2 | 3 | ![](/assets/KSR - fearless-grey150x140.png) 4 | 5 | I am Keith Robertson, also known as fearless / mrfearless. I was born in Scotland but now live in Ireland. 6 | 7 | I have a Teacher Trainer Diploma in Information Technology Skills and have worked as a professional programmer for over 5 years. I have used a number of programming languages in production environments and custom built applications for clients using: dBASE, Clipper, Foxpro, Visual Foxpro and Visual Basic. 8 | 9 | I remember being interesting in coding from a young age, starting with the basic language on the ZX Spectrum 48K. 10 | 11 | Over the years I have managed to develop and enhance my skills with other technologies and programming languages that interested me - including assembly language. 12 | 13 | I recall a time in the past, when my then current boss - who was coding in x86 assembler - said to me: 14 | 15 | > Its not for you. You wouldnt be able to understand the low level nature of assembler, its too advanced for you, you should stick to basic and clipper instead. 16 | 17 | I silently vowed I would understand this language, taking it as a personal challenge, and I took every opportunity I could to read all the books and articles on assembly language i could find or buy. 18 | 19 | That was over 15 years ago. I never told my old boss of my self-taught accomplishment, and as far as I know he never learnt that I did infact suceed in learning assembler - including more advanced topics than my boss would have expected. 20 | 21 | Learning is a great and rewarding experience. And sharing that knowledge is a way of repaying that. Never let anyone tell you that you can't do something. 22 | 23 | -------------------------------------------------------------------------------- /book.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Custom Controls in Assembler", 3 | "description": "Use the win32 api and assembly language to create custom controls for windows.", 4 | "plugins": [ 5 | "disqus", 6 | "github", 7 | "meta", 8 | "splitter", 9 | "copy-code-button", 10 | "word-count" 11 | ], 12 | "pluginsConfig": { 13 | "disqus": { 14 | "shortName": "custom-controls-in-assembler" 15 | }, 16 | "github": { 17 | "url": "https://github.com/mrfearless/creating-controls-in-assembler" 18 | }, 19 | "pdf": { 20 | "fontSize": 10, 21 | "margin": { 22 | "right": 32, 23 | "left": 32, 24 | "top": 32, 25 | "bottom": 32 26 | } 27 | }, 28 | "meta": { 29 | "data": [ 30 | { 31 | "name": "keywords", 32 | "content": "asm, assembly, assembler, controls, masm, win32, windows, fearless" 33 | }, 34 | { 35 | "property": "og:title", 36 | "content": "Custom Controls in Assembler" 37 | }, 38 | { 39 | "property": "og:description", 40 | "content": "Use the win32 api and assembly language to create custom controls for windows." 41 | }, 42 | { 43 | "property": "og:url", 44 | "content": "https://mrfearless.gitbooks.io/creating-controls-in-assembler/content/" 45 | }, 46 | { 47 | "property": "og:site_name", 48 | "content": "Custom Controls in Assembler by fearless" 49 | }, 50 | { 51 | "property": "og:image", 52 | "content": "https://github.com/mrfearless/creating-controls-in-assembler/blob/master/assets/mrfearless.jpg" 53 | }, 54 | { 55 | "name": "twitter:card", 56 | "content": "summary" 57 | }, 58 | { 59 | "name": "twitter:title", 60 | "content": "Custom Controls in Assembler" 61 | }, 62 | { 63 | "name": "twitter:image", 64 | "content": "https://github.com/mrfearless/creating-controls-in-assembler/blob/master/assets/mrfearless.jpg" 65 | }, 66 | { 67 | "name": "twitter:creator", 68 | "content": "@fearless0" 69 | }, 70 | { 71 | "name": "twitter:site", 72 | "content": "@fearless0" 73 | }, 74 | { 75 | "name": "twitter:url", 76 | "content": "https://mrfearless.gitbooks.io/creating-controls-in-assembler/content/" 77 | }, 78 | { 79 | "name": "twitter:description", 80 | "content": "Use the win32 api and assembly language to create custom controls for windows." 81 | } 82 | ] 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /control-properties.md: -------------------------------------------------------------------------------- 1 | # Control Properties 2 | 3 | When registering our custom control \(see [Registering Our Control](//registering-our-control.md) for details\), the `cbWndExtra` field of the [WNDCLASSEX](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633577%28v=vs.85%29.aspx) is used for storing additional extra bytes per instance of the control we create. 4 | 5 | In the early days of my control creation I used these extra storage bytes to store anywhere up to 128 bytes of data to hold various variables used by the control. I came across some documentation later on that suggested there was a limit of 40 bytes in some earlier versions of windows os, and that as the bytes are being allocated from the local system heap, the [RegisterClassEx](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633587%28v=vs.85%29.aspx) function might fail if greater than 40 bytes is requested: 6 | 7 | > Extra Window Memory 8 | > 9 | > The system maintains an internal data structure for each window. When registering a window class, an application can specify a number of additional bytes of memory, called extra window memory. When creating a window of the class, the system allocates and appends the specified amount of extra window memory to the end of the window's structure. An application can use this memory to store window-specific data. 10 | > 11 | > Because extra memory is allocated from the system's local heap, an application should use extra window memory sparingly. The RegisterClassEx function fails if the amount of extra window memory requested is greater than 40 bytes. If an application requires more than 40 bytes, it should allocate its own memory and store a pointer to the memory in the extra window memory. 12 | > 13 | > The SetWindowLong function copies a value to the extra memory. The GetWindowLong function retrieves a value from the extra memory. The cbWndExtra member of the WNDCLASSEX structure specifies the amount of extra window memory to allocate. An application that does not use the memory must initialize cbWndExtra to zero. 14 | 15 | Once the extra bytes are allocated, they can accessed and read via calls to [GetWindowLong](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633584%28v=vs.85%29.aspx) and passing the handle of the window \(our control's handle\) and an index offset to the bytes required. For setting the values we use the calls to [SetWindowLong](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633591%28v=vs.85%29.aspx), again passing the window handle, an offset to the bytes to be set and a value to set. 16 | 17 | -------------------------------------------------------------------------------- /control-properties/internal-wrapper-functions.md: -------------------------------------------------------------------------------- 1 | # Internal Wrapper Functions 2 | 3 | The helper functions, used in our example **SimpleButton** control, are just wrapper functions using [GetWindowLong](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633584%28v=vs.85%29.aspx) and [SetWindowLong](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633591%28v=vs.85%29.aspx) to get and set the internal and external variables/properties: `__GetIntProperty`, `__SetIntProperty`, `__GetExtProperty` and `__SetExtProperty`. 4 | 5 | The **internal** variables/properties are _**not**_ exposed to the end-user by design \(this can of course be changed if you need to or your control requires it for whatever reason\). 6 | 7 | I borrowed my earlier technique of using constants to name the properties/variables used, and to define the offsets into the memory blocks, as this allows us to define easily readable property \(or variable\) names to use with out helper functions. It is much easier to use and read code like: 8 | 9 | ```x86asm 10 | Invoke __GetExtProperty, hControl, @SimpleButtonBackColor 11 | ``` 12 | 13 | than: 14 | 15 | ```x86asm 16 | Invoke __GetExtProperty, hControl, 24 17 | ``` 18 | 19 | We can clearly see the property we are referring to, in this case it relates to a back color or background color of our control. 20 | 21 | For the end-user who will use our **SimpleButton** control they can access the **external** properties via calls to `SimpleButtonGetProperty` and `SimpleButtonSetProperty` or by using the custom messages: `SB_GETPROPERTY`, `SB_SETPROPERTY`, `SB_GETSTATE` and `SB_SETSTATE` with the [SendMessage](https://msdn.microsoft.com/en-us/library/windows/desktop/ms644950%28v=vs.85%29.aspx) api call. These functions then call the appropriate internal helper functions \(wrapper functions for [GetWindowLong](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633584%28v=vs.85%29.aspx) and [SetWindowLong](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633591%28v=vs.85%29.aspx)\). 22 | 23 | -------------------------------------------------------------------------------- /control-properties/property-structures-&-constants.md: -------------------------------------------------------------------------------- 1 | # Property Structures & Constants 2 | 3 | Note that in the `WM_CREATE` message of the main processing function `_SB_WndProc`, I use two structures for defining the variables that I will use in the control **internally** _and_ **externally** \(named `_SIMPLEBUTTON_PROPERTIES` and `SIMPLEBUTTON_PROPERTIES`\), although they aren't used directly by most controls, instead I opt to use constant values that are offsets into the allocated memory. 4 | 5 | For example, the **internal** variables structure I use is defined as such: 6 | 7 | ```x86asm 8 | _SIMPLEBUTTON_PROPERTIES STRUCT 9 | dwEnabledState DD ? 10 | dwMouseOver DD ? 11 | dwSelectedState DD ? 12 | dwMouseDown DD ? 13 | _SIMPLEBUTTON_PROPERTIES ENDS 14 | ``` 15 | 16 | with the **internal** variables \(or properties\) used, defined as constants: 17 | 18 | ```x86asm 19 | @SimpleButtonEnabledState EQU 0 20 | @SimpleButtonMouseOver EQU 4 21 | @SimpleButtonSelectedState EQU 8 22 | @SimpleButtonMouseDown EQU 12 23 | ``` 24 | 25 | So the memory block that the four internal variables are stored in, starts at offset 0 for the first one, offset 4 for the next and so on \(assuming all variables are dword values of course\). We will see later on getting and setting these **internal** and **external** variables using the helper functions: `__GetIntProperty`, `__SetIntProperty`, `__GetExtProperty` and `__SetExtProperty`. 26 | 27 | The **external** properties and structure \(`SIMPLEBUTTON_PROPERTIES)`\) is defined similarly in the `SimpleButton.inc` file for the end-user. Typically the end-user wont make use of the structure directly, its just added as a convienance - mainly for the use by the developer. It is easier to use `SIZEOF` _structurename_ to pass to the `__AllocMemProperties` function to determine the size of memory to allocate for our control's properties. 28 | 29 | Here is the list of **external** properties constants that we define for the end-user: 30 | 31 | ```x86asm 32 | @SimpleButtonTextFont EQU 0 ; hFont 33 | @SimpleButtonTextColor EQU 4 ; Colorref 34 | @SimpleButtonTextColorAlt EQU 8 ; Colorref 35 | @SimpleButtonTextColorSel EQU 12 ; Colorref 36 | @SimpleButtonTextColorSelAlt EQU 16 ; Colorref 37 | @SimpleButtonTextColorDisabled EQU 20 ; Colorref 38 | @SimpleButtonBackColor EQU 24 ; Colorref 39 | @SimpleButtonBackColorAlt EQU 28 ; Colorref 40 | @SimpleButtonBackColorSel EQU 32 ; Colorref 41 | @SimpleButtonBackColorSelAlt EQU 36 ; Colorref 42 | @SimpleButtonBackColorDisabled EQU 40 ; Colorref 43 | @SimpleButtonBorderColor EQU 44 ; Colorref 44 | @SimpleButtonBorderColorAlt EQU 48 ; Colorref 45 | @SimpleButtonBorderColorSel EQU 52 ; Colorref 46 | @SimpleButtonBorderColorSelAlt EQU 56 ; Colorref 47 | @SimpleButtonBorderColorDisabled EQU 60 ; Colorref 48 | @SimpleButtonBorderStyle EQU 64 ; Border Style Flags 49 | ``` 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /control-properties/radasm-auto-complete.md: -------------------------------------------------------------------------------- 1 | # RadASM Auto-complete 2 | 3 | Another reason I used the approach of defining properties as constants, is RadASM's auto-complete / intelliSense** **feature. By editing two .api files and adding some information I can include this information to make it easier to code using the **SimpleButton** control and other controls. 4 | 5 | So I easily can add autocomplete for the `SimpleButtonGetProperty` function and it will show a dropdown list of possible values when I am ready to supply the 2nd parameter \(`dwProperty`\) 6 | 7 | We can edit the contents of RadASM\Masm\masmApiCall.api and place the following text: 8 | 9 | ``` 10 | SimpleButtonGetProperty,hSimpleButton,dwProperty 11 | ``` 12 | 13 | And the same with RadASM\Masm\masmApiConst.api, we edit and place the following text: 14 | 15 | ``` 16 | 2SimpleButtonGetProperty,@SimpleButtonTextFont,@SimpleButtonTextColor,@SimpleButtonTextColorAlt, 17 | @SimpleButtonTextColorSel,@SimpleButtonTextColorSelAlt,@SimpleButtonTextColorDisabled,@SimpleButtonBackColor, 18 | @SimpleButtonBackColorAlt,@SimpleButtonBackColorSel,@SimpleButtonBackColorSelAlt,@SimpleButtonBackColorDisabled, 19 | @SimpleButtonBorderColor,@SimpleButtonBorderColorAlt,@SimpleButtonBorderColorSel,@SimpleButtonBorderColorSelAlt, 20 | @SimpleButtonBorderColorDisabled,@SimpleButtonBorderStyle 21 | ``` 22 | 23 | Save the files and restart RadASM for the change to take effect. This is what RadASM's auto-complete looks like when has been implemented for our `SimpleButtonGetProperty` function: 24 | 25 | ![](/assets/SimpleButtonGetProperty.gif) 26 | 27 | The project source for **SimpleButton** also includes the `masmApiCall.api.txt`, `masmApiConst.api.txt`and `masmMessage.api.txt` text files that incorporate these calls and constants for use with RadASM's auto-complete / intelliSense feature, you just need to open the appropriate .api file and paste the contents at the end of the file and restart RadASM for them to be available to you. Instructions are included in the text files themselves as to which file it related to and the typical location of those .api files. 28 | 29 | -------------------------------------------------------------------------------- /control-properties/the-memory-used-to-store-properties.md: -------------------------------------------------------------------------------- 1 | # The Memory Used To Store Properties 2 | 3 | Our `__AllocMemProperties` function which is used in the `WM_CREATE` message of the main processing function `_SB_WndProc`, will allocate the memory size required based on two structures we use named `_SIMPLEBUTTON_PROPERTIES` and `SIMPLEBUTTON_PROPERTIES` \(See [Property Structures & Constants](//control-properties/property-structures-&-constants.md) for details\). Of course we could use other means to pass the size of memory required - I just felt that it was more convenient to use a structure for better organisation of the properties used. 4 | 5 | It is entirely possible to expand on this and create a function for the end-user that can make use of the **external** `SIMPLEBUTTON_PROPERTIES` structure and allow the end-user to pass as a parameter to the function. a pointer to a variable defined as a `SIMPLEBUTTON_PROPERTIES` type. The function could then iterate through each field and set the appropriate values for the control to make use of. Additional checks would be required for the size of the passed parameter to ensure it is correct, to prevent buffer overflows for example. A lot of Microsoft's own structures make use of a `cbSize` field to validate the structure. 6 | 7 | `__AllocMemProperties` will store the pointer to the memory allocated, in the extra window bytes allocated by `cbWndExtra`, by making use of calls to [SetWindowLong](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633591%28v=vs.85%29.aspx). 8 | 9 | Note: `INTERNAL_PROPERTIES` is a constant that equals `0`, whereas the`EXTERNAL_PROPERTIES` constant equals `4` - created for myself just for convenience as a wrapper to call the [SetWindowLong](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633591%28v=vs.85%29.aspx) function with the specified offset into the extra memory reserved by `cbWndExtra` at our controls registration. 10 | 11 | Internally the `__AllocaMemProperties` function calls either of the following: 12 | 13 | `Invoke SetWindowLong, hControl, 0, PtrAllocMem`- To set the pointer to the memory that will store the internal properties. 14 | 15 | `Invoke SetWindowLong, hControl, 4, PtrAllocMem` - To set the pointer to memory that will store the external properties. 16 | 17 | `PtrAllocMem` is the pointer to our memory that was allocated using [GlobalAlloc](https://msdn.microsoft.com/en-us/library/windows/desktop/aa366574%28v=vs.85%29.aspx) from within `__AllocMemProperties` 18 | 19 | -------------------------------------------------------------------------------- /control-properties/using-macros-to-getset-properties.md: -------------------------------------------------------------------------------- 1 | # Using Macros To Get/Set Properties 2 | 3 | When I was using the earlier technique of allocating as much bytes as I wanted in `cbWndExtra` \(without realising or coming across any downsides\) I used a series of macros to help get/set the variables and constants to help define the offsets the macro would get/set, for example: 4 | 5 | ```x86asm 6 | @Style EQU 0h ; some style flags 7 | @MouseOverFlag EQU 4h ; 0 = no mouse over, 1 = mouse is over control 8 | @SelectedState EQU 8h ; 0 = not selected, 1 = selected 9 | @ControlFont EQU 12 ; hFont 10 | ... 11 | ``` 12 | 13 | With the constants defined and appropriate named \(using a prefix of '@'\) we could then define macros to get and set our property values. Each constant is an offset into the extra window bytes allocated by `cbWndExtra` during the control's registration via [RegisterClassEx](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633587%28v=vs.85%29.aspx). 14 | 15 | The macros then called the [GetWindowLong](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633584%28v=vs.85%29.aspx) or [SetWindowLong](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633591%28v=vs.85%29.aspx) to get or set the value at the appropriate index offset. 16 | 17 | Here is and example of some macros used to get and set the various 'properties' as defined above as constants: 18 | 19 | ```x86asm 20 | _GetMouseOverFlag MACRO hControl:REQ 21 | Invoke GetWindowLong, hControl, @MouseOverFlag 22 | ENDM 23 | 24 | _SetMouseOverFlag MACRO hControl:REQ, ptrControlData:REQ 25 | Invoke SetWindowLong, hControl, @MouseOverFlag, ptrControlData 26 | ENDM 27 | 28 | _GetSelectedState MACRO hControl:REQ 29 | Invoke GetWindowLong, hControl, @SelectedState 30 | ENDM 31 | 32 | _SetSelectedState MACRO hControl:REQ, ptrControlData:REQ 33 | Invoke SetWindowLong, hControl, @SelectedState, ptrControlData 34 | ENDM 35 | ``` 36 | 37 | The macros could then be placed in code and used like so: 38 | 39 | ```x86asm 40 | ... 41 | _SetMouseOverFlag hControl, TRUE 42 | ... 43 | 44 | ... 45 | _GetSelectedState hControl 46 | mov bState, eax 47 | ... 48 | ``` 49 | 50 | Using macros to get and set our control's properties is still a valid technique if the amount of data store for these properties is less than 40 bytes \(see the [Control Properties](/control-properties.md) section and [here](https://msdn.microsoft.com/en-us/library/ms633574%28VS.85%29.aspx#extra_window_memory) for why\). 51 | 52 | It is also possible to make use of the [GetProp](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633564%28v=vs.85%29.aspx) / [SetProp](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633568%28v=vs.85%29.aspx) api calls, which make use of [integer atoms](https://msdn.microsoft.com/en-us/library/windows/desktop/ms649053%28v=vs.85%29.aspx#_win32_Integer_Atoms) - which is faster than [GetProp](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633564%28v=vs.85%29.aspx) / [SetProp](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633568%28v=vs.85%29.aspx) with a [string atoms](https://msdn.microsoft.com/en-us/library/windows/desktop/ms649053%28v=vs.85%29.aspx#_win32_String_Atoms), but use of [GetProp](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633564%28v=vs.85%29.aspx) / [SetProp](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633568%28v=vs.85%29.aspx) with both atoms types are still slower than [GetWindowLong](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633584%28v=vs.85%29.aspx) / [SetWindowLong](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633591%28v=vs.85%29.aspx) as far as I am aware. 53 | 54 | -------------------------------------------------------------------------------- /control-properties/using-the-win32-api-to-getset-properties.md: -------------------------------------------------------------------------------- 1 | # Using The Win32 API To Get/Set Properties 2 | 3 | Ultimately, as the controls I created became more complex with more internal variables stored in the `cbWndExtra` bytes, I changed my technique to only use 8 bytes in the `cbWndExtra` field. 4 | 5 | I used the [GetWindowLong](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633584%28v=vs.85%29.aspx) api function to retrieve data in the extra window memory of `cbWndExtra`, and the [SetWindowLong](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633591%28v=vs.85%29.aspx) api function to set data in this memory. 6 | 7 | The data to get or set was one `DWORD` value \(`Invoke GetWindowLong, hControl, 0`\) for a pointer to a structure that stored internal variables, and another `DWORD` value \(`Invoke GetWindowLong, hControl, 4`\) for a pointer to a structure that stored variables that are visible and can be modified externally by the user of the control. 8 | 9 | The actual allocation of memory for these structures used for internal and external variables is handled in the `WM_CREATE` message of the main controls window procedure by the `__AllocMemProperties` internal function \(see [Inside Our Control](//inside-our-control.md) for details\). 10 | 11 | The freeing of this allocated memory is handled by `__FreeMemProperties` internal function in the WM\_NCDESTROY message. 12 | 13 | In our example **SimpleButton** control the `_SB_WndProc` procedure calls the `__AllocMemProperties` function to allocate thie memory and store the pointer in the appropriate `cbWndExtra` location - \(`Invoke GetWindowLong, hControl, 0`\) for a pointer to a structure that stores **internal** variables, and \(`Invoke GetWindowLong, hControl, 4`\) for a pointer to a structure that stores **external** variables. 14 | 15 | -------------------------------------------------------------------------------- /controls-and-modern-ui-design.md: -------------------------------------------------------------------------------- 1 | # Controls & Modern UI Design 2 | 3 | The windows controls - the basic and custom controls - are available for users to create in assembler via calls to the win32 api. The image below shows examples of some of the most commonly used ones \(see [here](https://msdn.microsoft.com/en-us/library/windows/desktop/bb773169%28v=vs.85%29.aspx) for a full list of controls\): 4 | 5 | ![](/assets/win32stdcontrols.png) 6 | 7 | Over the years newer UI technologies and frameworks have appeared and improved on the standard controls available in windows, and in some cases have given the developers new controls, or ways to create newer UI controls with more flexibility, more customization and better ways to present information to their end-users. [GDI+](https://msdn.microsoft.com/en-us/library/ms533798%28v=vs.85%29.aspx), [Windows Forms](https://msdn.microsoft.com/en-us/library/dd30h2yb%28v=vs.110%29.aspx), [DirectX/Direct3D](https://msdn.microsoft.com/en-us/library/windows/desktop/bb153256%28v=vs.85%29.aspx), [OpenGL](https://www.opengl.org/), [Vulcan](https://www.khronos.org/vulkan/), [Windows Presentation Foundation](https://msdn.microsoft.com/en-us/library/aa663364.aspx), Microsoft Design Language & [Microsoft Fluent Design System](https://developer.microsoft.com/en-us/windows/apps/design) show us that the evolution of modern UI/UX has changed, taking inspiration from many sources including web 2.0 UI style designs. 8 | 9 | Unfortunately for assembly language developers, enthusiasts or hobbyists, we have been left behind to some extant - even though it is still possible in some cases, with some work and knowledge, to interface with some of the above mentioned technologies or frameworks. 10 | 11 | But that does not mean all is lost. We can adapt and take inspiration from all those new UI/UX design styles and create something similar for ourselves in assembly language - with a little work. 12 | 13 | -------------------------------------------------------------------------------- /cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrfearless/creating-controls-in-assembler/1234c21616a4eb12932f05f8878371dc520d940e/cover.jpg -------------------------------------------------------------------------------- /cover_small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrfearless/creating-controls-in-assembler/1234c21616a4eb12932f05f8878371dc520d940e/cover_small.jpg -------------------------------------------------------------------------------- /creating-our-control.md: -------------------------------------------------------------------------------- 1 | # Creating Our Control 2 | 3 | The `SimpleButtonCreate` function will allow the user to create the **SimpleButton** control directly with this function. The parameters for `SimpleButtonCreate` are `hWndParent`, `lpszText`, `xpos`, `ypos`, `controlwidth`, `controlheight`, `dwResourceID`, and finally `dwStyle`. This is more or less typical for creating a control with [CreateWindowEx](https://msdn.microsoft.com/en-us/library/windows/desktop/ms632680%28v=vs.85%29.aspx) and as such we try to keep our function as similar to that as we can, so that it is easier for the end user to use. 4 | 5 | Most of the parameters of the `SimpleButtonCreate` function are self-explanatory: the width, height, position of the control, the text to display, the parent handle of our child control and the resource id number associated with the control. 6 | 7 | The `dwStyle` parameter gives us a number of options to allow us or the user to tailor the control to our requirements, based on the styles we define for its usage. Unfortunately their isn't much in the microsoft documentation to indicate what values we can pass to the `dwStyle` parameter apart from the standard windows defined ones: `WS_BORDER`, `WS_VISIBLE`, `WS_CHILD` etc 8 | 9 | The most useful information I came across that explains the `dwStyle` flags parameter of [CreateWindowEx](https://msdn.microsoft.com/en-us/library/windows/desktop/ms632680%28v=vs.85%29.aspx) is from Raymond Chen's old new thing [blog](https://blogs.msdn.microsoft.com/oldnewthing/20031203-00/?p=41633/) 10 | 11 | > The low 16 bits of the dwStyle parameter are defined by the implementer of the window class \(by the person who calls RegisterClass\) 12 | 13 | That means we have `0x0` - `0xFFFF` reserved for defining styles for our controls - 65535 possible values or 16 values if we require bitmasked unique values \(1111111111111111\). And we can incorporate the standard style flags as well if we so desire \(`WS_BORDER`, `WS_VISIBLE` etc\). So our **SimpleButton** styles we will use are: 14 | 15 | ```x86asm 16 | ; SimpleButton Button Styles: 17 | SBBS_CENTER EQU 0h ; Align text centrally 18 | SBBS_LEFT EQU 1h ; Align text to the left of the button 19 | SBBS_HAND EQU 2h ; Show a hand when mouse moves over button. 20 | SBBS_PUSHBUTTON EQU 4h ; Simulate button movement when clicked. 21 | SBBS_AUTOSTATE EQU 8h ; Automatically toggle state when clicked. 22 | 23 | ; SimpleButton Edge (Border) Styles: 24 | SBES_NONE EQU 0 25 | SBES_LEFT EQU 1 26 | SBES_TOP EQU 2 27 | SBES_BOTTOM EQU 4 28 | SBES_RIGHT EQU 8 29 | SBES_ALL EQU SBES_LEFT + SBES_TOP + SBES_BOTTOM + SBES_RIGHT 30 | ``` 31 | 32 | So our `SimpleButtonCreate` function is just a wrapper to register the control if not already registered and a call to [CreateWindowEx](https://msdn.microsoft.com/en-us/library/windows/desktop/ms632680%28v=vs.85%29.aspx) to create it, returning the handle to the newly created control in `eax`. Also we check with the `dwStyle` parameter which flags are passed to `SimpleButtonCreate`, to ensure for example that `WS_CHILD` and `WS_VISIBLE` is included and any other flags we might want as well. This check is also performed in the `_SB_Init` procedure in case our **SimpleButton** control was created via a dialog resource. Of course you are free to define how you want your control to behave at creation and what flags if any you want to force to be included or even excluded from use. 33 | 34 | Here is our `SimpleButtonCreate` function: 35 | 36 | ```x86asm 37 | ;------------------------------------------------------------------------------------- 38 | ; SimpleButtonCreate - Returns handle in eax of newly created control or NULL 39 | ;------------------------------------------------------------------------------------- 40 | SimpleButtonCreate PROC PRIVATE hWndParent:DWORD, lpszText:DWORD, xpos:DWORD, / 41 | ypos:DWORD, controlwidth:DWORD, controlheight:DWORD, / 42 | dwResourceID:DWORD, dwStyle:DWORD 43 | LOCAL wc:WNDCLASSEX 44 | LOCAL hinstance:DWORD 45 | LOCAL hControl:DWORD 46 | LOCAL dwNewStyle:DWORD 47 | 48 | Invoke GetModuleHandle, NULL 49 | mov hinstance, eax 50 | 51 | Invoke SimpleButtonRegister ; register our control if its not already registered. 52 | 53 | mov eax, dwStyle 54 | mov dwNewStyle, eax 55 | and eax, WS_CHILD or WS_VISIBLE or WS_CLIPCHILDREN 56 | .IF eax != WS_CHILD or WS_VISIBLE or WS_CLIPCHILDREN 57 | or dwNewStyle, WS_CHILD or WS_VISIBLE or WS_CLIPCHILDREN 58 | .ENDIF 59 | 60 | Invoke CreateWindowEx, NULL, Addr SimpleButtonClass, lpszText, dwNewStyle, xpos, / 61 | ypos, controlwidth, controlheight, hWndParent, / 62 | dwResourceID, hinstance, NULL 63 | ret 64 | SimpleButtonCreate ENDP 65 | ``` 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /guidelines.md: -------------------------------------------------------------------------------- 1 | # Guidelines 2 | 3 | The design and coding process, I used to create controls, went through lots of evolutions. Different techniques and/or better code implementations were used once I discovered them or figured out via trial and error the best way to accomplish some tasks. I hope to show some of these techniques here. 4 | 5 | Obviously this is my way of creating controls, and there are bound to be many ways to achieve the same results and alternate techniques to use that are all valid, like [subclassing](https://msdn.microsoft.com/en-us/library/windows/desktop/bb773183%28v=vs.85%29.aspx) existing win32 controls for example, or utilizing [custom draw](https://msdn.microsoft.com/en-us/library/windows/desktop/ff919569%28v=vs.85%29.aspx) or [ownerdrawn](https://msdn.microsoft.com/en-us/library/windows/desktop/dd373487%28v=vs.85%29.aspx) features. 6 | 7 | So consider all this a guideline, code in your own style and take what you want from it and adapt any code and techniques in your own fashion to your own projects. 8 | 9 | I use RadASM as my editor of choice and I create templates for my own use that helps speed up development. Feel free to use whatever environment suits for you. 10 | 11 | I use the [Masm32 SDK](http://masm32.com/download.htm) for developing x86 assembler and [JWasm/HJWasm/UASM](http://www.terraspace.co.uk/uasm.html) for x64 assembler. The assembler code samples shown in the examples that follow all use masm assembler syntax. 12 | 13 | Note: Error checking code is omitted for brevity. In some places I use the word 'variable' or 'variables', 'property' or 'properties'. The terms should be considered as interchangeable, meaning the same thing. Similarly function names, structures and parameters referring to or including the word 'property' or 'properties' means the same as 'variables' in that context as well. 14 | 15 | -------------------------------------------------------------------------------- /initializing-our-control.md: -------------------------------------------------------------------------------- 1 | # Initializing Our Control 2 | 3 | `_SB_Init` function is called from the `WM_CREATE` message of the `_SB_WndProc` main window messaging function. It initializes our **SimpleButton** with some default values: like colors for background and text and others like default font to use. In `_SB_Init` we also check the `dwStyle` flags passed to the **SimpleButton** control \(via direct call to [CreateWindowEx](https://msdn.microsoft.com/en-us/library/windows/desktop/ms632680%28v=vs.85%29.aspx), call to `SimpleButtonCreate` or via dialog resource child control creation\) and we can override the `dwStyle` flags specified and/or force specific flags to be used or excluded \(in case the end-user forgot\), for example we can set our control to always use `WM_CHILD` plus `WM_VISIBLE` etc: 4 | 5 | ```x86asm 6 | ... 7 | ; get style and check it is our default at least 8 | Invoke GetWindowLong, hControl, GWL_STYLE 9 | mov dwStyle, eax 10 | and eax, WS_CHILD or WS_VISIBLE or WS_CLIPCHILDREN 11 | .IF eax != WS_CHILD or WS_VISIBLE or WS_CLIPCHILDREN 12 | mov eax, dwStyle 13 | or eax, WS_CHILD or WS_VISIBLE or WS_CLIPCHILDREN 14 | mov dwStyle, eax 15 | Invoke SetWindowLong, hControl, GWL_STYLE, dwStyle 16 | .ENDIF 17 | ... 18 | ``` 19 | 20 | We also set some default values for our control's external properties, like standard colors that might be used for text and background when creating our control. So some of the default values we will set for our control's properties are: 21 | 22 | ```x86asm 23 | ... 24 | Invoke __SetExtProperty, hControl, @SimpleButtonTextColor, SBRGBCOLOR(51,51,51) 25 | Invoke __SetExtProperty, hControl, @SimpleButtonBackColor, SBRGBCOLOR(255,255,255) 26 | Invoke __SetExtProperty, hControl, @SimpleButtonBorderColor, SBRGBCOLOR(204,204,204) 27 | Invoke __SetExtProperty, hControl, @SimpleButtonBorderStyle, SBES_ALL 28 | ... 29 | ``` 30 | 31 | Only some of the external properties are shown for brevity, the ones that are shown are define in `SimpleButton.inc` as: 32 | 33 | ```x86asm 34 | @SimpleButtonTextColor EQU 4 35 | @SimpleButtonBackColor EQU 24 36 | @SimpleButtonBorderColor EQU 44 37 | @SimpleButtonBorderStyle EQU 64 38 | ``` 39 | 40 | For color properties \([COLORREF](https://msdn.microsoft.com/en-us/library/vs/alm/dd183449%28v=vs.85%29.aspx)\) we make use of a macro called `SRGBCOLOR` that is included in `SimpleButton.inc`: 41 | 42 | ```x86asm 43 | SBRGBCOLOR MACRO red:REQ, green:REQ, blue:REQ 44 | EXITM < red or green shl 8 or blue shl 16 > 45 | ENDM 46 | ``` 47 | 48 | Here is our what our **SimpleButton** control will look like, in the image below, if it is created with the default property values we have assigned to it in our initialization function `_SB_Init`: 49 | 50 | ![](/assets/SimpleButtonDemoDefaults.gif) 51 | 52 | Note that it doesnt make use of the blue text color and border shown in our earlier image in the [Our First Control](//our-first-control.md) section. 53 | 54 | So by implementing this initialization routine for the end-user, it means they can use the **SimpleButton** control straight away, or they can choose to modify any of the **external** properties to customize it to their requirements after the control is created, whichever suits. See the [Control Properties](/control-properties.md) section later on for more details. 55 | 56 | -------------------------------------------------------------------------------- /inside-our-control.md: -------------------------------------------------------------------------------- 1 | # Inside Our Control 2 | 3 | `_SB_WndProc` is a standard main window messaging procedure, that handles specific `WM_` messages for our **SimpleButton** control. We have complete control over what messages are handled but we also have responsibility to handle specific messages, as we are implementing the core code ourselves and have to handle painting, mouse & keyboard interaction, and other features. 4 | 5 | We wont cover all the messages implemented in the `_SB_WndProc`, see the code for the full **SimpleButton** project on [github](https://github.com/mrfearless/SimpleButton) if you wish to see more detail. We will cover a few important messages that the control handles. 6 | 7 | Note: windows messages that we don't specify or include wont be handled. This is different from subclassing controls, where you can safely call the [DefWindowProc](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633572%28v=vs.85%29.aspx) for windows to handle messages that you have no interest in, and override only the ones you are interested in. In our control we do not have that luxury of letting windows handle the default messaging, instead it is expected that our control will do all the work. 8 | 9 | For example if you wish to handle keyboard interaction for your control you will need to provide for that, and possibly handle some of the following messages: `WM_CHAR`, `WM_DEADCHAR`, `WM_SYSCHAR`, `WM_SYSDEADCHAR`, `WM_UNICHAR`, `WM_HOTKEY`, `WM_SYSCOMMAND`, `WM_KILLFOCUS`, `WM_SETFOCUS`, `WM_ACTIVATE`, `WM_KEYDOWN`, `WM_KEYUP`, `WM_SYSKEYDOWN`, `WM_SYSKEYUP`. See the Microsoft documentation [About Keyboard Input](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646267%28v=vs.85%29.aspx) for more details. 10 | 11 | Similary if you wish to handle mouse interaction for your control you will need to possibly handle some of the following message: `WM_LBUTTONDBLCLK`, `WM_LBUTTONDOWN`, `WM_LBUTTONUP`, `WM_MBUTTONDBLCLK`, `WM_MBUTTONDOWN`, `WM_MBUTTONUP`, `WM_RBUTTONDBLCLK`, `WM_RBUTTONDOWN`, `WM_RBUTTONUP`, `WM_XBUTTONDBLCLK`, `WM_XBUTTONDOWN`, `WM_XBUTTONUP`, `WM_MOUSEHOVER`, `WM_MOUSELEAVE`, `WM_MOUSEMOVE`, `WM_NCMOUSEMOVE`, `WM_NCLBUTTONDOWN`, `WM_NCHITTEST`, `WM_MOUSEWHEEL`, `WM_MOUSEACTIVATE`, `WM_CONTEXTMENU`. See the Microsoft documentation [About Mouse Input](https://msdn.microsoft.com/en-us/library/windows/desktop/ms645601%28v=vs.85%29.aspx) for more details. 12 | 13 | The Microsoft documentation also has a list of [System Defined Messages](https://msdn.microsoft.com/en-us/library/windows/desktop/ms644927%28v=vs.85%29.aspx#system_defined) that may prove useful to refer to. 14 | 15 | ##### 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /inside-our-control/handling-other-messages-for-our-control.md: -------------------------------------------------------------------------------- 1 | # Handling Other Messages For Our Control 2 | 3 | Along with handling the `WM_CREATE` & `WM_NCDESTROY`messages, we have to handle a few more: enabling/disabling our control, setting text, setting fonts, when our control is painted and other features we may wish to include, such as mouse and keyboard interaction \(if applicable to our control\). 4 | 5 | We handle our own painting in our **SimpleButton** like so with these two messages: 6 | 7 | ```x86asm 8 | ... 9 | .ELSEIF eax == WM_ERASEBKGND 10 | mov eax, 1 11 | ret 12 | 13 | .ELSEIF eax == WM_PAINT 14 | Invoke _SB_Paint, hWin 15 | mov eax, 0 16 | ret 17 | ... 18 | ``` 19 | 20 | With the above code, we are specifying that we will handle erasing of our control's background ourself and painting of our **SimpleButton** control via our own paint function `_SB_Paint` see [Painting Our Control](//painting-our-control.md) for more details. 21 | 22 | We can also allow our **SimpleButton** control to be enabled or disabled via a standard `WM_ENABLE` message, which forces a repaint of our control. And similarly we can allow a font change and repaint via a `WM_SETFONT` message. 23 | 24 | ```x86asm 25 | ... 26 | .ELSEIF eax == WM_ENABLE 27 | Invoke __SetIntProperty, hWin, @SimpleButtonEnabledState, wParam 28 | Invoke InvalidateRect, hWin, NULL, TRUE 29 | mov eax, 0 30 | 31 | .ELSEIF eax == WM_SETTEXT 32 | Invoke DefWindowProc, hWin, uMsg, wParam, lParam 33 | Invoke InvalidateRect, hWin, NULL, TRUE 34 | ret 35 | 36 | .ELSEIF eax == WM_SETFONT 37 | Invoke __SetExtProperty, hWin, @SimpleButtonTextFont, lParam 38 | .IF lParam == TRUE 39 | Invoke InvalidateRect, hWin, NULL, TRUE 40 | .ENDIF 41 | ``` 42 | 43 | Our custom messages \(`SB_GETPROPERTY` ,`SB_SETPROPERTY`, `SB_GETSTATE` and `SB_SETSTATE`\) are included as well and are just simple calls to our internal helper functions \(or framework library if using one\): 44 | 45 | ```x86asm 46 | ... 47 | .ELSEIF eax == SB_GETPROPERTY ; wParam = dwProperty, lParam = NULL. 48 | Invoke __GetExtProperty, hWin, wParam ; EAX = dwPropertyValue 49 | ret 50 | 51 | .ELSEIF eax == SB_SETPROPERTY ; wParam = dwProperty, lParam = dwPropertyValue 52 | Invoke __SetExtProperty, hWin, wParam, lParam 53 | ret 54 | .ELSEIF eax == SB_GETSTATE ; wParam = NULL, lParam = NULL. 55 | Invoke __GetIntProperty, hWin, @SimpleButtonSelectedState ; EAX = dwState 56 | ret 57 | 58 | .ELSEIF eax == SB_SETSTATE ; wParam = TRUE/FALSE, lParam = NULL 59 | Invoke __SetIntProperty, hWin, @SimpleButtonSelectedState, wParam 60 | Invoke InvalidateRect, hWin, NULL, TRUE ; repaint control 61 | ret 62 | ... 63 | ``` 64 | 65 | Other standard messages are used to handle mouse interactions: the mouse moving over our control, leaving it, clicking on it etc via `WM_LBUTTONDOWN`, `WM_LBUTTONUP`, `WM_MOUSEMOVE`, `WM_MOUSELEAVE` and other standard win32 api messages. 66 | 67 | -------------------------------------------------------------------------------- /inside-our-control/on-creation-wmcreate.md: -------------------------------------------------------------------------------- 1 | # On Creation: WM\_CREATE 2 | 3 | We use the `WM_CREATE` message of our **SimpleButton** control to initialize the memory that will store blocks of memory for our internal and external variables that will be used by us and by any end-user, and we then call our own initialization routine. I opted to use `WM_CREATE` instead of `WM_NCCREATE` because I found over the years that sometimes the `cbWndExtra` extra data wasn't being allocated sometimes, and any initialization routine that set some defaults values in these extra memory areas could cause an invalid memory address error. I found moving all this code to the `WM_CREATE` was more reliable. 4 | 5 | `WM_NCCREATE` is one of the first messages a control receives and the `WM_NCDESTROY` message is one of the last. Its still possible to make use of the `WM_NCCREATE` message to handle some basic setup of controls, with the above mentioned caveat taken into account. 6 | 7 | Our `WM_CREATE` message of the `_SB_WndProc` function looks like this: 8 | 9 | ```x86asm 10 | ... 11 | .ELSEIF eax == WM_CREATE 12 | Invoke __AllocMemProperties, hWin, INTERNAL_PROPERTIES, SIZEOF _SIMPLEBUTTON_PROPERTIES 13 | Invoke __AllocMemProperties, hWin, EXTERNAL_PROPERTIES, SIZEOF SIMPLEBUTTON_PROPERTIES 14 | Invoke _SB_Init, hWin 15 | mov eax, 0 16 | ret 17 | ... 18 | ``` 19 | 20 | Our `__AllocMemProperties` internal helper function handles the allocation of memory for our control's properties and stores pointers to the **internal** and **external** properties in the extra window memory reserved by `cbWndExtra` when the control was registered with the [RegisterClassEx](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633587%28v=vs.85%29.aspx) api call in our `SimpleButtonRegister` function. See the section [The Memory Used To Store Properties](/control-properties/the-memory-used-to-store-properties.md) for more details on the `__AllocMemProperties`function. 21 | 22 | We define and make use of two structures, one prefixed with an underscore for internal properties and the other for use with external properties. See the section [Property Structures & Constants](//control-properties/property-structures-&-constants.md) for more details. 23 | 24 | At the end of the `WM_CREATE` message we then call our own initialization routine `_SB_Init` to handle our own setup of our **SimpleButton** control. At this point we can safely assume the memory allocated for our control has been done so, thus we can call our `_SB_Init` function to handle the next step \(see [Initializing Our Control](//initializing-our-control.md)\). 25 | 26 | See the [Control Properties](/control-properties.md) section later on for more details on the technical aspect of how we handle setting and getting our control's properties. 27 | 28 | -------------------------------------------------------------------------------- /inside-our-control/on-destroying-wmncdestroy.md: -------------------------------------------------------------------------------- 1 | # On Destroying: WM\_NCDESTROY 2 | 3 | When the control is destroyed we free the memory we allocated and call a cleanup routine for any other business \(if required\). Note our `_SB_Cleanup` function in our `WM_NCDESTROY` message \(shown below,\) is called **first** whilst the memory for our variables/properties still exists - This is important in case we have to free any other resources, handles or objects that we have stored previously in our internal or external properties. 4 | 5 | ```x86asm 6 | ... 7 | .ELSEIF eax == WM_NCDESTROY 8 | Invoke _SB_Cleanup, hWin ; cleanup any other stuff as required 9 | Invoke __FreeMemProperties, hWin, INTERNAL_PROPERTIES 10 | Invoke __FreeMemProperties, hWin, EXTERNAL_PROPERTIES 11 | mov eax, 0 12 | ret 13 | ... 14 | ``` 15 | 16 | Our internal helper function `__FreeMemProperties` used [GetWindowLong](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633584%28v=vs.85%29.aspx) to retrieve the appropriate pointer for the internal and external memory blocks used to store our variables and then frees that memory with calls to [GlobalFree](https://msdn.microsoft.com/en-us/library/windows/desktop/aa366579%28v=vs.85%29.aspx). 17 | 18 | -------------------------------------------------------------------------------- /inside-our-control/the-memory-used-to-store-our-controls-properties.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrfearless/creating-controls-in-assembler/1234c21616a4eb12932f05f8878371dc520d940e/inside-our-control/the-memory-used-to-store-our-controls-properties.md -------------------------------------------------------------------------------- /introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | ##### Creating Controls In Assembler 4 | 5 | There are a number of tutorials out on the internet that describe how to create a custom control, but not many that cover creating a control in assembler. Mostly these tutorials are written for C/C++ users, which acts as a basic starting point for assembly developers to port over the code to assembly language. 6 | 7 | For many years I was content to create programs and little utilities in assembler using masm. with what I knew of win32 api from forum discussions, and reading lots of articles and tutorials covering lots of different topics. Mostly I stayed away from the painting stuff \(GDI api functions and handling the WM\_PAINT message\) as I felt it was over my head at that time. 8 | 9 | After some time though, I gradually started to implement small bits of GDI code and functions in my WM\_PAINT message - just enough to begin to understand what was going on under the hood. 10 | 11 | Then one day I was looking at the steam client interface I wondered how they went about creating their menus, what was required, and how it was implemented, and how could the same effect could be achieved in assembler. 12 | 13 | I had an epiphany in realizing windows controls are just little blank 'windows' or canvases or panels \(or whatever you want to call them\) that have been painted to look like something. Sure the paint job in some controls was more advanced - with 3d effects and lines and shadows and all other kinds of fancy bits - but ultimately I realized that it was all smoke and mirrors, that 'controls' where just painted blobs that responded in specific but programmed ways to achieve their interactivity. 14 | 15 | That led me to wonder about user interface controls in general, the ones found in windows and other sources like web 2.0 websites and programs that used .net, and i wondered how I could create a control for myself using the standard win32 API and assembly language. 16 | 17 | The following information describes the path I took in creating custom controls in assembler using the Win32 API and masm assembler. Hopefully you will find it both useful and informative. 18 | 19 | ##### 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /our-first-control.md: -------------------------------------------------------------------------------- 1 | # Our First Control 2 | 3 | I'm going to use a simple button control example to help cover some of the code used in this article. The name of this control will be **SimpleButton**. I wont be covering every single function used, merely the most important or interesting ones. The code for the full project including examples is available for you to browse, read and download here: 4 | 5 | [https://github.com/mrfearless/SimpleButton](https://github.com/mrfearless/SimpleButton) 6 | 7 | Here is what our **SimpleButton** control will look like when its in operation: 8 | 9 | ![](/assets/SimpleButtonDemo.gif) 10 | 11 | Very simple, but for our purposes should be fine to help cover the steps required to create the controls behaviour. We will allow the end-user to specify the background, text and border colors for seperate states such as: selected, enabled and mouse over. We will paint the background, the text and border based on those current states and handle mouse interaction, cursors and emulate a push button effect and/or a toggle state. All these options will be handled by using flags and properties that we define for use with our **SimpleButton** control. 12 | 13 | Firstly I create two files: `SimpleButton.asm` that will contain the main code for the control and an include file called `SimpleButton.inc`. The `SimpleButton.inc` file be included from within `SimpleButton.asm` and will also be distributed along with the compiled static library of the control once we are finished `SimpleButton.lib`. 14 | 15 | `SimpleButton.inc` will include function prototypes for users to call that will create and manipulate the **SimpleButton** control. Also included will be any structures or constants that will be required for the user to use in conjunction with the functions we create, and we will also include some custom messages for our control as well. 16 | 17 | ##### 18 | 19 | ##### 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /our-first-control/external-end-user-functions.md: -------------------------------------------------------------------------------- 1 | # External End-User Functions 2 | 3 | Functions that will defined for use **externally** by the end-user of our control will be: 4 | 5 | ```x86asm 6 | SimpleButtonRegister PROTO 7 | SimpleButtonCreate PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD 8 | SimpleButtonGetProperty PROTO :DWORD, :DWORD 9 | SimpleButtonSetProperty PROTO :DWORD, :DWORD, :DWORD 10 | SimpleButtonGetState PROTO :DWORD 11 | SimpleButtonSetState PROTO :DWORD, :DWORD 12 | ``` 13 | 14 | The `SimpleButton.asm` will contain these functions _and_ other functions designed to be used internally by the control itself. I prefix the functions that will be used **internally** with an **underscore** and an **abbreviation**, but you can use whatever naming convention you desire. 15 | 16 | ##### Custom Messages For The End-User 17 | 18 | Our custom message which are used in conjunction with [SendMessage](https://msdn.microsoft.com/en-us/library/windows/desktop/ms644950%28v=vs.85%29.aspx) api call, can be used instead of the `SimpleButtonSetProperty` / `SimpleButtonGetProperty` and `SimpleButtonGetState` / `SimpleButtonSetState` functions, are defined as: 19 | 20 | ```x86asm 21 | SB_GETPROPERTY EQU WM_USER + 1800 22 | SB_SETPROPERTY EQU WM_USER + 1799 23 | SB_GETSTATE EQU WM_USER + 1798 24 | SB_SETSTATE EQU WM_USER + 1797 25 | ``` 26 | 27 | We will cover the usage of some of these functions and mesages later on. 28 | 29 | -------------------------------------------------------------------------------- /our-first-control/internal-developer-functions.md: -------------------------------------------------------------------------------- 1 | # Internal Functions 2 | 3 | Functions that will defined for use **internally** by the control will be: 4 | 5 | ```x86asm 6 | _SB_WndProc PROTO :DWORD, :DWORD, :DWORD, :DWORD 7 | _SB_Init PROTO :DWORD 8 | _SB_Cleanup PROTO :DWORD 9 | _SB_Paint PROTO :DWORD 10 | _SB_PaintBackground PROTO :DWORD, :DWORD, :DWORD, :DWORD, :DWORD, :DWORD 11 | _SB_PaintText PROTO :DWORD, :DWORD, :DWORD, :DWORD, :DWORD, :DWORD 12 | _SB_PaintBorder PROTO :DWORD, :DWORD, :DWORD, :DWORD, :DWORD, :DWORD 13 | ``` 14 | 15 | These **internal** functions are the core functions that handle the main processing and painting of our **SimpleButton** control. 16 | 17 | In addition, we will define a few other internal helper functions for use in this control. In my own development projects I combine the functions next into a library or framework for easy re-use, but I have recreated them here and included them in the `SimpleButton.asm` file just for ease of use and clarity in covering the features in the control. The internal helper functions are: 18 | 19 | ```x86asm 20 | __AllocMemProperties PROTO :DWORD, :DWORD, :DWORD 21 | __FreeMemProperties PROTO :DWORD, :DWORD 22 | __GetIntProperty PROTO :DWORD, :DWORD 23 | __SetIntProperty PROTO :DWORD, :DWORD, :DWORD 24 | __GetExtProperty PROTO :DWORD, :DWORD 25 | __SetExtProperty PROTO :DWORD, :DWORD, :DWORD 26 | ``` 27 | 28 | These functions are briefly covered later on \(see [Inside Our Control](//inside-our-control.md)\) and some more detail can be found in the [Control Properties](/control-properties.md) section. 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /painting-our-control.md: -------------------------------------------------------------------------------- 1 | # Painting Our Control 2 | 3 | In the `_SB_Paint` function we make the task of painting our **SimpleButton** control a bit easier for ourselves by separating the main tasks into other sub-functions: `_SB_PaintBackground`, `_SB_PaintText` and `_SB_PaintBorder`. We create a double buffer beforehand and BitBlt after the calls to the other `_SB_Paint` sub-functions. 4 | 5 | `_SB_Paint` and the other sub-functions make use of our both our **internal** and **external** variables \(with calls to the internal helper functions: `__GetIntProperty`, `__GetExtProperty`\) to detect states \(selected/not selected\), mouse over \(or not\) and to control styles, colors, fonts and other attributes used in our **SimpleButton** control. 6 | 7 | The sub functions typically are passed some **internal** variables as parameters, for example: 8 | 9 | ```x86asm 10 | ... 11 | LOCAL EnabledState:DWORD 12 | LOCAL MouseOver:DWORD 13 | LOCAL SelectedState:DWORD 14 | ... 15 | 16 | ... 17 | Invoke __GetIntProperty, hControl, @SimpleButtonEnabledState 18 | mov EnabledState, eax 19 | Invoke __GetIntProperty, hControl, @SimpleButtonMouseOver 20 | mov MouseOver, eax 21 | Invoke __GetIntProperty, hControl, @SimpleButtonSelectedState 22 | mov SelectedState, eax 23 | 24 | Invoke _SB_PaintBackground, hControl, hdcMem, Addr rect, EnabledState, MouseOver, SelectedState 25 | Invoke _SB_PaintText, hControl, hdcMem, Addr rect, EnabledState, MouseOver, SelectedState 26 | Invoke _SB_PaintBorder, hControl, hdcMem, Addr rect, EnabledState, MouseOver, SelectedState 27 | ... 28 | ``` 29 | 30 | With all these attributes the end-user will have control our how the **SimpleButton** will look depending on the default properties set and any additional ones the end-user sets themselves. 31 | 32 | Each of the sub-functions will read a particular external property depending on the status of the internal properties, so in our `_SB_PaintBackground` function, depending on whether the mouse is over the control or not it will fetch a different **external** property. 33 | 34 | Here is the complete `_SB_PaintBackground` function to illustrate this: 35 | 36 | ```x86asm 37 | ;------------------------------------------------------------------------------------- 38 | ; _SB_PaintBackground - Paints the background of the SimpleButton control 39 | ;------------------------------------------------------------------------------------- 40 | _SB_PaintBackground PROC PRIVATE hControl:DWORD, hdc:DWORD, lpRect:DWORD, / 41 | bEnabledState:DWORD, bMouseOver:DWORD, / 42 | bSelectedState:DWORD 43 | LOCAL BackColor:DWORD 44 | LOCAL hBrush:DWORD 45 | LOCAL hOldBrush:DWORD 46 | 47 | .IF bEnabledState == TRUE 48 | .IF bSelectedState == FALSE 49 | .IF bMouseOver == FALSE 50 | Invoke __GetExtProperty, hControl, @SimpleButtonBackColor 51 | .ELSE 52 | Invoke __GetExtProperty, hControl, @SimpleButtonBackColorAlt 53 | .ENDIF 54 | .ELSE 55 | .IF bMouseOver == FALSE 56 | Invoke __GetExtProperty, hControl, @SimpleButtonBackColorSel 57 | .ELSE 58 | Invoke __GetExtProperty, hControl, @SimpleButtonBackColorSelAlt 59 | .ENDIF 60 | .ENDIF 61 | .ELSE 62 | Invoke __GetExtProperty, hControl, @SimpleButtonBackColorDisabled 63 | .ENDIF 64 | .IF eax == 0 ; try to get default back color if others are set to 0 65 | Invoke __GetExtProperty, hControl, @SimpleButtonBackColor 66 | .ENDIF 67 | mov BackColor, eax 68 | Invoke GetStockObject, DC_BRUSH 69 | mov hBrush, eax 70 | Invoke SelectObject, hdc, eax 71 | mov hOldBrush, eax 72 | Invoke SetDCBrushColor, hdc, BackColor 73 | Invoke FillRect, hdc, lpRect, hBrush 74 | 75 | .IF hOldBrush != 0 76 | Invoke SelectObject, hdc, hOldBrush 77 | Invoke DeleteObject, hOldBrush 78 | .ENDIF 79 | .IF hBrush != 0 80 | Invoke DeleteObject, hBrush 81 | .ENDIF 82 | ret 83 | _SB_PaintBackground ENDP 84 | ``` 85 | 86 | So if `bEnabled` is `TRUE` and the **SimpleButton** control's selected state \(`bSelectedState`\) is `FALSE` we just have to determine if the mouse is over the control or not. 87 | 88 | If the mouse is **not** over the control we fetch the default `@SimpleButtonBackColor` property which is a `DWORD` [COLORREF](https://msdn.microsoft.com/en-us/library/vs/alm/dd183449%28v=vs.85%29.aspx) value to paint the background with. If however the mouse _is_ over the control we fetch the `@SimpleButtonBackColorAlt` property which is another `DWORD` [COLORREF](https://msdn.microsoft.com/en-us/library/vs/alm/dd183449%28v=vs.85%29.aspx) value \(which may be the same value or a different value than the `@SimpleButtonBackColor` property\). Similarly we can fetch colors for when our control is disabled or if is selected state has been set with our `SimpleButtonSetState` function, or if the state of our control has changed automatically as a result of specifying the `SBBS_AUTOSTATE` flag when created the control \(which allows us to toggle the state of our **SimpleButton** control when it is clicked each time\) 89 | 90 | Then we proceed to paint the background of our **SimpleButton** control with the color retrieved, using the standard [FillRect](https://msdn.microsoft.com/en-us/library/windows/desktop/dd162719%28v=vs.85%29.aspx) api call. 91 | 92 | We then clean up the brushes used, and return to `_SB_Paint` ready to call the next sub-function to handle painting our text and border. Each of those sub-functions works in a similar manner, by fetching the appropriate external property value and then painting based on those values for text or border colors, depending on the status of the control: selected, enabled or if the mouse is over the control. 93 | 94 | -------------------------------------------------------------------------------- /registering-our-control.md: -------------------------------------------------------------------------------- 1 | # Registering Our Control 2 | 3 | The `SimpleButtonCreate` function will call our `SimpleButtonRegister` function to register the class associated with our control. So why do we need the `SimpleButtonRegister` function?, surely we can just handle all this in the `SimpleButtonCreate` function? 4 | 5 | Well, there are number of reasons we want to have a `SimpleButtonRegister` function. When we register a custom window class \(our control\) we allow the creation of it via the [CreateWindowEx](https://msdn.microsoft.com/en-us/library/windows/desktop/ms632680%28v=vs.85%29.aspx "https://msdn.microsoft.com/en-us/library/windows/desktop/ms632680\(v=vs.85\).aspx") api call if we specify the classname to create, and also we can facilitate the creation of our control via a dialog resource. 6 | 7 | RadASM allows a custom control to be placed on a dialog and all it requires is a classname. When you look at the dialog resource file it shows the control and the classname. At runtime when the dialog is instantiated, it will automatically enumerate and create all controls in the dialog, and if our custom **SimpleButton** control is registered it will allow the dialog to create the control for our usage. This technique will apply to other IDEs that allow you to specify the control classname \(or if you need, you can edit the Dialog's .rc resource file directly to include this information\) 8 | 9 | The image below shows what a .rc dialog resource file might look like when creating our custom control in this manner: 10 | 11 | ![](/assets/SimpleButtonResourceCreation2.png) 12 | 13 | Using RadASM's UserDefinedControl, shown in the image below, we can specify the text to be used in the `Caption` property, the class to use, which in this example will be '_SimpleButton\_Control_' and we can also modify the `xStyle` property flags to include `0x6` which corresponds to `SBBS_HAND` plus `SBBS_PUSHBUTTON`. These flags are covered in more detail later on. 14 | 15 | ![](/assets/IDC_SB2.png) 16 | 17 | Later in our code we can retrieve the handle to the dialog's child control that is our **SimpleButton**, and use this handle to set other properties of our control, like in the example image below: 18 | 19 | ![](/assets/GetDlgItemHandle.png) 20 | 21 | So we allow our end-user the ability to create our custom **SimpleButton** control, directly with the `SimpleButtonCreate` function, or via the [CreateWindowEx](https://msdn.microsoft.com/en-us/library/windows/desktop/ms632680%28v=vs.85%29.aspx) function or via a resource dialog control entry. The last two will require the `SimpleButtonRegister` function to have been called before the call to [CreateWindowEx](https://msdn.microsoft.com/en-us/library/windows/desktop/ms632680%28v=vs.85%29.aspx) or before the dialog is created. 22 | 23 | ##### SimpleButtonRegister 24 | 25 | The `SimpleButtonRegister` function makes use of the [WNDCLASSEX](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633577%28v=vs.85%29.aspx\) structure to define the behaviour of our control. When you create a win32 api control via [CreateWindowEx](https://msdn.microsoft.com/en-us/library/windows/desktop/ms632680%28v=vs.85%29.aspx) using one of the predefined class names: static, edit, button, listbox etc, once it returns you have a handle to that control that can be used in other related api functions for that control. But where is the main code routine and how is it defined. Well the [WNDCLASSEX](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633577%28v=vs.85%29.aspx) structure is where this main function for the class is defined. 26 | 27 | Here is our `SimpleButtonRegister` function, that registers out new **SimpleButton** control and sets the main internal procedure \(`_SB_WndProc`\) that we use for handling the messages to this control. 28 | 29 | In the .data section we create a string that will be unique for use with our control: 30 | 31 | ```x86asm 32 | .DATA 33 | SimpleButtonClass DB "SimpleButton_Control",0 34 | ``` 35 | 36 | And this is the control's register function: 37 | 38 | ```x86asm 39 | ;------------------------------------------------------------------------------------- 40 | ; SimpleButtonRegister - Registers the SimpleButton control 41 | ; Can be used at start of program for use with RadASM custom control 42 | ; Custom control class must be set as 'SimpleButton_Control' 43 | ;------------------------------------------------------------------------------------- 44 | SimpleButtonRegister PROC PUBLIC 45 | LOCAL wc:WNDCLASSEX 46 | LOCAL hinstance:DWORD 47 | 48 | Invoke GetModuleHandle, NULL 49 | mov hinstance, eax 50 | 51 | invoke GetClassInfoEx, hinstance, Addr SimpleButtonClass, Addr wc 52 | .IF eax == 0 ; if class not already registered do so 53 | mov wc.cbSize, SIZEOF WNDCLASSEX 54 | lea eax, SimpleButtonClass 55 | mov wc.lpszClassName, eax 56 | mov eax, hinstance 57 | mov wc.hInstance, eax 58 | mov wc.lpfnWndProc, OFFSET _SB_WndProc ; points to main controls window proc 59 | mov wc.hCursor, NULL ; not set, we can handle this in our main window proc 60 | mov wc.hIcon, 0 61 | mov wc.hIconSm, 0 62 | mov wc.lpszMenuName, NULL ; no menu needed 63 | mov wc.hbrBackground, NULL ; handle drawing ourselves in main window proc 64 | mov wc.style, NULL 65 | mov wc.cbClsExtra, 0 66 | mov wc.cbWndExtra, 8 ; dword ptr to internal & external properties memory 67 | Invoke RegisterClassEx, Addr wc 68 | .ENDIF 69 | ret 70 | SimpleButtonRegister ENDP 71 | ``` 72 | 73 | When registering a class with [RegisterClassEx](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633587%28v=vs.85%29.aspx), the `lpszClassName` field of the [WNDCLASSEX](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633577%28v=vs.85%29.aspx) will hold our custom classname \(in this case '_SimpleButton\_Control_'\) and the `lpfnWndProc` field will hold the address of our custom controls main window procedure \(`_SB_WndProc`\), which is very much like a standard windows procedure, that handles specific `WM_` messages. 74 | 75 | The `cbWndExtra` of [WNDCLASSEX](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633577%28v=vs.85%29.aspx) is used to store some extra bytes for use with our control. See the [Control Properties](/control-properties.md) section later on for more details. 76 | 77 | -------------------------------------------------------------------------------- /styles/ebook.css: -------------------------------------------------------------------------------- 1 | cite{ 2 | margin-top: -30px; 3 | font-size:10px; 4 | text-align: center; 5 | color: #666; 6 | } 7 | 8 | .page-inner ul, .page-inner ol { 9 | margin-bottom:15px !important; 10 | } 11 | 12 | small{ 13 | font-size:10px; 14 | } 15 | 16 | 17 | h1 { 18 | margin-top: 0; 19 | padding:0; 20 | } 21 | 22 | .markdown-section h1, h1 23 | { 24 | margin-top: 0px; 25 | padding: 0px; 26 | } -------------------------------------------------------------------------------- /styles/pdf.css: -------------------------------------------------------------------------------- 1 | p, 2 | blockquote, 3 | dl, 4 | table { 5 | text-align: justify; 6 | } 7 | 8 | pre { 9 | word-break: break-all; 10 | /* Non standard for webkit, but it does work on the Mac when generating the PDF */ 11 | word-break: break-word; 12 | } 13 | 14 | h1 { 15 | margin-top: 0; 16 | padding:0; 17 | } 18 | 19 | .markdown-section h1, h1 20 | { 21 | margin-top: 0px; 22 | padding: 0px; 23 | } -------------------------------------------------------------------------------- /styles/website.css: -------------------------------------------------------------------------------- 1 | cite{ 2 | margin-top: -30px; 3 | font-size:10px; 4 | text-align: center; 5 | color: #666; 6 | } 7 | 8 | .page-inner ul, .page-inner ol { 9 | margin-bottom:15px !important; 10 | } 11 | 12 | small{ 13 | font-size:10px; 14 | } 15 | 16 | h1 { 17 | margin-top: 0; 18 | padding:0; 19 | } 20 | 21 | .markdown-section h1, h1 22 | { 23 | margin-top: 0px; 24 | padding: 0px; 25 | } -------------------------------------------------------------------------------- /the-hotmenu-quest.md: -------------------------------------------------------------------------------- 1 | # The HotMenu Quest 2 | 3 | So after my epiphany about controls being painted blobs and using smoke and mirrors to display how it worked, I began my quest to discover more, and how to create a control for myself. 4 | 5 | My earliest attempt was a control called **HotMenu** - which was a menu panel system based on the Steam client menus. For those of you that have not used Steam or are not aware of it: 6 | 7 | > Steam is a digital distribution platform developed by Valve Corporation, which offers digital rights management \(DRM\), multiplayer gaming, video streaming and social networking services. Steam provides the user with installation and automatic updating of games on multiple computers, and community features such as friends lists and groups, cloud saving, and in-game voice and chat functionality. 8 | 9 | The image below depicts the normal Steam client menu usage. The menu panel drops down to display a list of menu items to choose from. As the mouse moves over the menu items they are highlighted. Additionally when the menu bar is clicked on any menu bar item and the mouse then hovers over any of the other menu bar items, the menu panel dropdown automatically is displayed, again with its list of menu items: 10 | 11 | ![](/assets/SteamClientMenu.gif) ![](/assets/SteamClientMenu.png) 12 | 13 | So taking inspiration from the Steam client menu system and wanted to adapt it to a custom control in win32 assembler, I began the development of **HotMenu.** 14 | 15 | It worked by creating a rectangle shape when the mouse moved over the menu bar area, the rectangle menu panel was drawn just below this menu bar and then it iterated through a list of menu items, which where in reality child static controls of text I created and spaced accordingly in a vertically manner. When the mouse was 'clicked' on a menu item and detected \(using `SS_NOTIFY`\) on one of these static controls, it sent the notification back to the parent window/dialog and thus it could be processed as a menu item that had been clicked. 16 | 17 | Here is the prototype of the **HotMenu** control, with all the settings set to emulate the Steam client menu: 18 | 19 | ![The HotMenu Control](/assets/HotMenu.gif) ![](/assets/HotMenuStatic.png) 20 | 21 | The **HotMenu** control had a number of properties that allowed the user to control the overall look and feel of the menu bar, menu panel and menu items. I added a few more features like optional background image for the menu panel, images for menu items and static text in places. I took inspiration from a number of web based menu systems and online retailers, hoping to expand the flexibility of the **HotMenu** control to accommodate all different possibilities. 22 | 23 | It all worked, but the **HotMenu** control didn't handle cascading sub menus, and I always meant to go back to it at some point to add more features, but other projects and interests pulled my attention away. But it still served as a basis for my development of controls I would develop in future. 24 | 25 | -------------------------------------------------------------------------------- /the-modernui-framework.md: -------------------------------------------------------------------------------- 1 | # The ModernUI Framework 2 | 3 | Readers might be interested in my other project which is related to creating custom controls in assembler: **ModernUI** 4 | 5 | It uses many of the techniques that we have covered in creating controls and implementing property constants to allow the end-user to easily customize the controls look and/or behaviour. Of particular interest to readers that followed the creating of our **SimpleButton** control is the **ModernUI** control `ModernUI_Button` which expands on the **SimpleButton** control and adds more features and capabilities, like allowing bmp, ico or png images as well as text 6 | 7 | There is two versions of the project, one for x86 **32bit **windows, and one for x64 **64bit **windows: 8 | 9 | * [ModernUI](https://github.com/mrfearless/ModernUI) 10 | * [ModernUI64](https://github.com/mrfearless/ModernUI64) 11 | 12 | The **ModernUI** project, which is still a work in progress, includes a framework library that contains many of the helper functions already covered here, bundled into one convienent library \(`ModernUI.inc` & `ModernUI.lib`\). 13 | 14 | Each control utilizes the main **ModernUI **library to handle the low level internals required to create the controls and some other functions to help ease development and use of them. 15 | 16 | The current list of controls that are available are: 17 | 18 | * `ModernUI_CaptionBar` 19 | * `ModernUI_Button` 20 | * `ModernUI_ProgressBar` 21 | * `ModernUI_Checkbox` 22 | * `ModernUI_SmartPanel` 23 | 24 | In addition to the released controls, I have included some RadASM project as examples of usage for each control. Also there is RadASM auto-complete / intelliSense .api text files, and RadASM custom control .dll files that help the end-user implement the current list of controls, within RadASM and allow the end-user to specify some of the initial style flags. Some icons for use with GUI are also included in the releases section along with the other files listed above. 25 | 26 | For those that are interested in contributing to the project, the main design document of the project is on the wiki, here is the introduction of the design document: 27 | 28 | > For years, new control types and UI designs for operating system and web have progressed, whilst older win32 base controls which are used by win32 assemblers \(masm32 etc\) have remained untouched. The ModernUI project has been created to help modernize these existing controls and add to them. The main goals of the project are: 29 | > 30 | > * Provide a modern update to existing win32 base class visual controls. 31 | > * Add new control types to reflect newer UI/UX design influences. 32 | > * Emulate control types from UWP, WPF, .Net & Web 2.0 platforms. 33 | 34 | Here are some examples of dialogs and controls created by and using the ModernUI framework and associated controls: 35 | 36 | ![](/assets/CodeShotOptions.gif) 37 | 38 | ![](/assets/x64dbgUpdateChecker.gif) 39 | 40 | -------------------------------------------------------------------------------- /using-our-control.md: -------------------------------------------------------------------------------- 1 | # Using Our Control 2 | 3 | The end-user will make use of our control **SimpleButton**, using the functions, custom messages, and constants \(properties\) that we define and are available for use in our `SimpleButton.inc file`. 4 | 5 | Just to remind ourselves, these are the **external** functions available to the end-user: 6 | 7 | ```x86asm 8 | SimpleButtonRegister PROTO 9 | SimpleButtonCreate PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD 10 | SimpleButtonGetProperty PROTO :DWORD, :DWORD 11 | SimpleButtonSetProperty PROTO :DWORD, :DWORD, :DWORD 12 | SimpleButtonGetState PROTO :DWORD 13 | SimpleButtonSetState PROTO :DWORD, :DWORD 14 | ``` 15 | 16 | And the custom messages for our control are: 17 | 18 | ```x86asm 19 | SB_GETPROPERTY EQU WM_USER + 1800 20 | SB_SETPROPERTY EQU WM_USER + 1799 21 | SB_GETSTATE EQU WM_USER + 1798 22 | SB_SETSTATE EQU WM_USER + 1797 23 | ``` 24 | 25 | With very little code we can create our control, all we need to define is the text to display and the resource id we will use for our control: 26 | 27 | ```x86asm 28 | .const 29 | IDC_SB1 EQU 1001 ; resource id to use 30 | 31 | .data 32 | SBText DB 'SimpleButton Rules!',0 ; text to display 33 | 34 | .data? 35 | hSB1 DD ? ; handle for SimpleButton control 36 | ``` 37 | 38 | And we then call our `SimpleButtonCreate` function and save the returned handle \(in `eax`\) in a variable: 39 | 40 | ```x86asm 41 | Invoke SimpleButtonCreate, hWin, Addr SBText, 40, 60, 200, 30, IDC_SB1, / 42 | WS_CHILD or WS_VISIBLE or SBBS_CENTER or / 43 | SBBS_HAND or SBBS_PUSHBUTTON 44 | mov hSB1, eax ; save handle to our control 45 | ``` 46 | 47 | Our `SimpleButtonCreate` function takes a number of parameters: 48 | 49 | * `hWndParent` \(`DWORD`\) is the parent handle of our main dialog window, with which to create a child control for. 50 | * `xpos` \(`DWORD`\) is the left position of our control relative to the parent's client space. 51 | * `ypos` \(`DWORD`\) is the top position of our control relative to the parent's client space. 52 | * `controlwidth` \(`DWORD`\) is the width of our control. 53 | * `controlheight` \(`DWORD`\) is the height of our control 54 | * `dwResourceID` \(`DWORD`\) is the resource id used by our control 55 | * `dwStyle` \(`DWORD`\) is a combination of constants \(flags\) that define some features of our control. 56 | 57 | The `dwStyle` parameter can accept windows style flags: `WS_CHILD`, `WS_VISIBLE`, and flags we defined for our controls usage in `SimpleButton.inc`: 58 | 59 | ```x86asm 60 | SBBS_CENTER EQU 0h ; Align text centrally (default) 61 | SBBS_LEFT EQU 1h ; Align text to the left of the button 62 | SBBS_HAND EQU 2h ; Show a hand when mouse moves over button. 63 | SBBS_PUSHBUTTON EQU 4h ; Simulate button movement when clicked. 64 | SBBS_AUTOSTATE EQU 8h ; Automatically toggle state when clicked. 65 | ``` 66 | 67 | With our example code above, we create our control with the the text aligned in the center \(`SBBS_CENTER`\) and an option to show a hand cursor when the mouse moves over our control \(`SBBS_HAND`\), and we simulate a small movement of our control when it is clicked \(`SBBS_PUSHBUTTON`\) - the **SimpleButton** controil moves very slightly down when the left click button is pressed and back again when the left click button is released. 68 | 69 | Additional properties of our control which are defined in our `SimpleButton.inc` file allow us to change the look and feel. This is the full list of properties \(constant values\) that we define for **SimpleButton**: 70 | 71 | ```x86asm 72 | @SimpleButtonTextFont EQU 0 ; hFont 73 | @SimpleButtonTextColor EQU 4 ; Colorref 74 | @SimpleButtonTextColorAlt EQU 8 ; Colorref 75 | @SimpleButtonTextColorSel EQU 12 ; Colorref 76 | @SimpleButtonTextColorSelAlt EQU 16 ; Colorref 77 | @SimpleButtonTextColorDisabled EQU 20 ; Colorref 78 | @SimpleButtonBackColor EQU 24 ; Colorref 79 | @SimpleButtonBackColorAlt EQU 28 ; Colorref 80 | @SimpleButtonBackColorSel EQU 32 ; Colorref 81 | @SimpleButtonBackColorSelAlt EQU 36 ; Colorref 82 | @SimpleButtonBackColorDisabled EQU 40 ; Colorref 83 | @SimpleButtonBorderColor EQU 44 ; Colorref 84 | @SimpleButtonBorderColorAlt EQU 48 ; Colorref 85 | @SimpleButtonBorderColorSel EQU 52 ; Colorref 86 | @SimpleButtonBorderColorSelAlt EQU 56 ; Colorref 87 | @SimpleButtonBorderColorDisabled EQU 60 ; Colorref 88 | @SimpleButtonBorderStyle EQU 64 ; Border Style Flags 89 | ``` 90 | 91 | The end-user can choose which properties are set, with default values having been applied to the control when we initialized it \(see [Initializing Our Control](//initializing-our-control.md) section for details\) 92 | 93 | For example we can set the text color of our control, the border color and the border color when the mouse moves over our control: 94 | 95 | ```x86asm 96 | Invoke SimpleButtonSetProperty, hSB1, @SimpleButtonTextColor, SBRGBCOLOR(26,103,140) 97 | Invoke SimpleButtonSetProperty, hSB1, @SimpleButtonBorderColor, SBRGBCOLOR(27,161,226) 98 | Invoke SimpleButtonSetProperty, hSB1, @SimpleButtonBorderColorAlt, SBRGBCOLOR(27,161,226) 99 | ``` 100 | 101 | We can optionally use our custom message `SB_SETPROPERTY` \(instead of the `SimpleButtonSetProperty` function\) with the [SendMessage](https://msdn.microsoft.com/en-us/library/windows/desktop/ms644950%28v=vs.85%29.aspx) api call, to also set our control's properties: 102 | 103 | ```x86asm 104 | Invoke SendMessage, hSB1, SB_SETPROPERTY, @SimpleButtonTextColor, SBRGBCOLOR(26,103,140) 105 | Invoke SendMessage, hSB1, SB_SETPROPERTY, @SimpleButtonBorderColor, SBRGBCOLOR(27,161,226) 106 | Invoke SendMessage, hSB1, SB_SETPROPERTY, @SimpleButtonBorderColorAlt, SBRGBCOLOR(27,161,226) 107 | ``` 108 | 109 | As we have specified the resource id defined for our control \(`IDC_SB1`\), we can handle processing of when our control is clicked using the standard `WM_COMMAND` message in our example project's main dialog message processing procedure: 110 | 111 | ```x86asm 112 | ... 113 | .ELSEIF eax == WM_COMMAND 114 | mov eax, wParam 115 | and eax, 0FFFFh 116 | .IF eax == IDM_FILE_EXIT 117 | Invoke SendMessage,hWin,WM_CLOSE,0,0 118 | 119 | .ELSEIF eax == IDM_HELP_ABOUT 120 | Invoke ShellAbout,hWin,addr AppName,addr AboutMsg,NULL 121 | 122 | .ELSEIF eax == IDC_SB1 ; handle our SimpleButton being clicked, show a message. 123 | Invoke MessageBox, NULL, Addr szMsgText, Addr szMsgTitle, MB_OK 124 | 125 | .ENDIF 126 | ... 127 | ``` 128 | 129 | In the example code above, we show a simple [MessageBox](https://msdn.microsoft.com/en-us/library/windows/desktop/ms645505%28v=vs.85%29.aspx) when our **SimpleButton** control is clicked. 130 | 131 | --------------------------------------------------------------------------------