Windows 10 Lean and the next generation of Raspberry PI like x86 devices

The latest news about a “Windows 10 Lean” version of Windows sounds exciting, but it is not enough. Why ?

The technology today is there to create the tiniest x86 device yet which can run Windows 10 on a device as small as a Raspberry PI Zero. Yes, not just the Raspberry PI size SOC but one as small as the Raspberry PI Zero. We already have TV Stick style x86 devices capable of running Windows 10 and it is not without reason to think that something smaller could be created. But why haven’t we gotten there yet ?

The problem is with how software is written

What is overlooked is the core of Windows which has been there for a long time. Yes, the WIN32 API. Today everything is all about cross platform and mobile and the technologies used for that make some sense, but tiny x86 devices are not about cross platform nor are they all about browsing the web. Such devices would have a use for the so called “Maker” market, robotics and IOT (Internet of Things). A totally different approach is required for such devices. The key to such markets is:

“smaller, faster, smaller, faster, smaller, faster”

and that is not about hardware, but software. This quote was by the late Bob Zale, the creator of the once famous Turbo Basic (Borland International bought it from him) and the great grand child of Turbo Basic, called Powerbasic. I had the privilege to interview Mr. Zale back in 2011 and you can read the article on Tech Republic’s website here:

https://www.techrepublic.com/blog/software-engineer/interview-with-powerbasic-founder-bob-zale/

You can also listen to the Dot.Net Rocks podcast of their interview with Bob Zale and also Ethan Winer (co-founder of Crescent Software) here:

https://www.dotnetrocks.com/default.aspx?showNum=20

What did Bob Zale mean by “smaller, faster” ? Having used his BASIC compilers for nearly 20 years now, I can attest to how fast they compile, how powerful they are and how small an executable they can create. Powerbasic is one of the software industries best kept secrets. The only way to describe Powerbasic is that is it BASIC, with the raw power of C. This is not your grandfathers old interpreted BASIC, but it is a lean and powerful development system. It leverages the raw power of the WIN32 API, something I am well aware of myself. Having coded directly to the WIN32 API for nearly 2 decades now, it still amazes me the raw power there and the blazingly fast performance one can get from it. The beauty of BASIC when it comes to the WIN32 API is that the code is readable and understandable. For example here is a simple example which I created which emulates a Caption Bar inside a real custom control. The control is compiled into a DLL which can be used with any application, even ones written in C.

 

' ------------------------------------------------------------------------
'                          Custom Class ControlClass Constants and Types
' ------------------------------------------------------------------------
%ControlClassExtraData       = 6     ' # of Extra Data Items (Long) for All Custom Window Classes
                                ' Data Items will be indexed from 1 in GetControlData function
' ------------------------------------------------------------------------
$ControlClassName            = "CAPCTRL32"
' ------------------------------------------------------------------------
%WM_MYCOLOR                  = %WM_CTLCOLORSTATIC

' ------------------------------------------------------------------------
'                           Custom Control Library Declares
' ------------------------------------------------------------------------
DECLARE FUNCTION GetControlLong(BYVAL hWnd AS LONG, BYVAL N&) AS LONG
DECLARE SUB SetControlLong(BYVAL hWnd AS LONG, BYVAL N&, BYVAL V&)

' ------------------------------------------------------------------------
'                           Custom Control Control Class Declares
' ------------------------------------------------------------------------
DECLARE SUB RegisterControlClass()
DECLARE SUB ControlClassPaint(BYVAL hWnd AS LONG)
DECLARE SUB ControlClassDraw(BYVAL hWnd AS LONG)
DECLARE SUB BuildBitmap(BYVAL hWnd AS LONG, BYVAL CFlag&)
' ------------------------------------------------------------------------

%CP_CUSTOM_MESSAGE      =   %WM_USER+100
%CP_GETSTATE            =   %WM_USER+101

' ------------------------------------------------------------------------
'                              DLL Entrance - LibMain
' ------------------------------------------------------------------------

FUNCTION LIBMAIN(BYVAL hInstance   AS LONG, _
                 BYVAL fwdReason   AS LONG, _
                 BYVAL lpvReserved AS LONG) EXPORT AS LONG
    SELECT CASE fwdReason
        CASE %DLL_PROCESS_ATTACH    ' =1 - Where DLL starts
            RegisterControlClass
        CASE %DLL_THREAD_ATTACH
        CASE %DLL_THREAD_DETACH
        CASE %DLL_PROCESS_DETACH    ' =0 - Where DLL exits
        CASE ELSE
    END SELECT
    LIBMAIN=1
END FUNCTION

' ------------------------------------------------------------------------
'                          Custom Control ControlClass Functions / Subs
' ------------------------------------------------------------------------

SUB RegisterControlClass()
    LOCAL windowclass    AS WndClassEx
    LOCAL szClassName AS ASCIIZ * 80
    szClassName            = $ControlClassName+CHR$(0)
    windowclass.cbSize        = SIZEOF(windowclass)
    windowclass.style         = %CS_HREDRAW OR %CS_VREDRAW OR %CS_PARENTDC OR %CS_DBLCLKS
    windowclass.lpfnWndProc   = CODEPTR(ControlClassWndProc)
    windowclass.cbClsExtra    = 0
    windowclass.cbWndExtra    = %ControlClassExtraData*4
    windowclass.hInstance     = GetModuleHandle(BYVAL %NULL)
    windowclass.hIcon         = %NULL
    windowclass.hCursor       = LoadCursor( %NULL, BYVAL %IDC_ARROW )
    windowclass.hbrBackground = GetStockObject( %WHITE_BRUSH )
    windowclass.lpszMenuName  = %NULL
    windowclass.lpszClassName = VARPTR( szClassName )
    windowclass.hIconSm       = %NULL
    RegisterClassEx windowclass
END SUB

' ------------------------------------------------------------------------

SUB DefTrueSize(BYVAL hWnd&, AY&, ACY&)
    LOCAL AWS&, AH&
    AWS&=GetWindowLong(hWnd&, %GWL_EXSTYLE) AND %WS_EX_TOOLWINDOW
    IF AWS&=%WS_EX_TOOLWINDOW THEN
        AH&=GetSystemMetrics(%SM_CYSMCAPTION)
    ELSE
        AH&=GetSystemMetrics(%SM_CYCAPTION)
    END IF

    AY&=(AY&+ACY&)-AH&
    ACY&=AY&+AH&-1
END SUB

' ------------------------------------------------------------------------

FUNCTION GetTrueTop(BYVAL hWnd&, BYVAL Y2&) AS LONG
    LOCAL AWS&, AH&
    AWS&=GetWindowLong(hWnd&, %GWL_EXSTYLE) AND %WS_EX_TOOLWINDOW
    IF AWS&=%WS_EX_TOOLWINDOW THEN
        AH&=GetSystemMetrics(%SM_CYSMCAPTION)
    ELSE
        AH&=GetSystemMetrics(%SM_CYCAPTION)
    END IF
    FUNCTION=Y2&-AH&
END FUNCTION

' ------------------------------------------------------------------------

FUNCTION GetHeight(BYVAL hWnd&) AS LONG
    LOCAL AWS&, AH&
    AWS&=GetWindowLong(hWnd&, %GWL_EXSTYLE) AND %WS_EX_TOOLWINDOW
    IF AWS&=%WS_EX_TOOLWINDOW THEN
        AH&=GetSystemMetrics(%SM_CYSMCAPTION)
    ELSE
        AH&=GetSystemMetrics(%SM_CYCAPTION)
    END IF
    AH&=AH&+GetSystemMetrics(%SM_CYDLGFRAME)
    FUNCTION=AH&
END FUNCTION

' ------------------------------------------------------------------------

FUNCTION ControlClassWndProc(BYVAL hWnd   AS LONG, _
                 BYVAL Msg    AS LONG, _
                 BYVAL wParam AS LONG, _
                 BYVAL lParam AS LONG) EXPORT AS LONG

LOCAL RV&, hParent AS LONG

'  If message is processed then set FUNCTION=0 and then EXIT FUNCTION

SELECT CASE Msg
    CASE %WM_SIZE
        IF GetControlLong(hWnd,6)=0 THEN
            SetControlLong hWnd,6,1
            FUNCTION = DefWindowProc(hWnd,Msg,wParam,lParam)
            DIM R AS RECT
            GetWindowRect hWnd,R
            R.nTop=R.nBottom-GetHeight(hWnd)
            ScreenToClient GetParent(hWnd), BYVAL VARPTR(R)
            ScreenToClient GetParent(hWnd), BYVAL VARPTR(R)+8
            MoveWindow hWnd, R.nLeft, R.nTop, R.nRight-R.nLeft, R.nBottom-R.nTop, 1
            SetControlLong hWnd,6,0
            EXIT FUNCTION
        END IF
    CASE %WM_CREATE
        DIM CS AS CREATESTRUCT PTR, WS&, EXS&, WP2 AS WINDOWPOS
        CS=lParam
        WS&=@CS.style
        EXS&=@CS.dwExStyle
        WS&=WS& AND (%WS_CHILD OR %WS_VISIBLE OR %WS_CLIPSIBLINGS OR %WS_CLIPCHILDREN OR %WS_SYSMENU)
        WS&=WS& OR %WS_CAPTION
        @CS.style=WS&
        EXS&=EXS& AND %WS_EX_TOOLWINDOW
        @CS.dwExStyle=EXS&
        SetWindowLong hWnd, %GWL_STYLE, WS&
        SetWindowLong hWnd, %GWL_EXSTYLE, EXS&
    CASE %WM_NCHITTEST
        FUNCTION=%HTCLIENT
        EXIT FUNCTION
    CASE %WM_LBUTTONDOWN
        IF GetControlLong(hWnd,5)=0 THEN
            SetControlLong hWnd,5,1
            SendMessage hWnd, %WM_NCACTIVATE, 1,0
        ELSE
            SetControlLong hWnd,5,0
            SendMessage hWnd, %WM_NCACTIVATE, 0,0
        END IF
        hParent=GetParent(hWnd)
        IF hParent<>0 THEN
            ' Uses the Standard Static control message
            SendMessage hParent, %WM_COMMAND,MAKLNG(GetWindowLong(hWnd,%GWL_ID),%STN_CLICKED), hWnd
        END IF
        FUNCTION=0
        EXIT FUNCTION
    CASE %WM_LBUTTONDOWN
        FUNCTION=0
        EXIT FUNCTION
    CASE %CP_CUSTOM_MESSAGE
    CASE %CP_GETSTATE
         FUNCTION=GetControlLong(hWnd,5)
         EXIT FUNCTION
    CASE %WM_PAINT
    CASE %WM_ERASEBKGND
    CASE %WM_SETCURSOR
    CASE %WM_LBUTTONDBLCLK
        hParent=GetParent(hWnd)
        IF hParent<>0 THEN
            ' Uses the Standard Static control message
            SendMessage hParent, %WM_COMMAND, MAKLNG(GetWindowLong(hWnd,%GWL_ID),%STN_DBLCLK), hWnd
        END IF
    CASE %WM_DESTROY
    CASE ELSE
END SELECT

FUNCTION = DefWindowProc(hWnd,Msg,wParam,lParam)

END FUNCTION

' ------------------------------------------------------------------------
'                             Custom Control Library
' ------------------------------------------------------------------------

FUNCTION GetControlLong(BYVAL hWnd AS LONG, BYVAL N&) AS LONG
LOCAL I&, RV&
RV&=0
IF N&>=1 AND N&<=%ControlClassExtraData THEN
    I&=(N&-1)*4
    IF IsWindow(hWnd) THEN
        RV&=GetWindowLong(hWnd, I&)
    END IF
END IF
FUNCTION=RV&
END FUNCTION

' ------------------------------------------------------------------------

SUB SetControlLong(BYVAL hWnd AS LONG, BYVAL N&, BYVAL V&)
LOCAL I&
IF N&>=1 AND N&<=%ControlClassExtraData THEN
    I&=(N&-1)*4
    IF IsWindow(hWnd) THEN
        SetWindowLong hWnd, I&, V&
    END IF
END IF
END SUB

' ------------------------------------------------------------------------

Notice, that despite it being WIN32 API code, it is still quite readable. Yes, BASIC makes WIN32 coding easier. Now this does not mean that one has to write everything in low level WIN32 API code. You can write higher level libraries on top of it or even use PowerBasic’s thin API user interface wrapper (called Dynamic Dialog Tools) to makes things a little easier. I built my own GUI framework using Powerbasic and the runtime for the entire framework is only about 1 megabyte in size and it includes a number of built in custom controls, a 2D sprite engine, a 3D openGL based graphic control and much more. By writing easy to use wrappers over the WIN32, one can build software even faster and more easily. Here is how the code to a simple app looks like using a GUI framework I wrote in Powerbasic:

 

#COMPILE EXE
#DIM ALL
#INCLUDE "..\includes\ezgui50.inc"
' *******************************************************************
'                         Application Constants and Declares
' *******************************************************************
%FORM1_LABEL1             = 100
%FORM1_HScrollBar1         = 105
%FORM1_LABEL2             = 110
DECLARE SUB FORM1_HScrollBar1_Click()
' --------------------
#INCLUDE "..\includes\ezwmain50.inc"         ' EZGUI Include file for WinMain
' --------------------

SUB EZ_Main(VerNum&) EXPORT
    EZ_LoadPatternLib "", ""
    EZ_Color 0,-56
    EZ_Form "FORM1", "", "Select Colors", 0, 0, 48, 18, "C"
END SUB

' ---------------------------------------------------------

SUB EZ_DesignWindow(FormName$) EXPORT
    SELECT CASE FormName$
        EZ_Color 0, 0
        EZ_UseFont -1
        EZ_UseFont 4
        EZ_Label %FORM1_LABEL1, 1, 1, 46, 10, "", "CS"
        ' --------------------------------
        EZ_Color -1,-1
        EZ_UseFont 4
        EZ_HScroll %FORM1_HScrollBar1, 2, 12, 44, 1.5, ""
        EZ_SetHScroll "FORM1", %FORM1_HScrollBar1, -57, 36, 0, 5
        ' --------------------------------
        EZ_Color 15, 1
        EZ_DefFont 10, "Tahoma",  16, "BV"
        EZ_UseFont 10
        EZ_Label %FORM1_LABEL2, 2, 15, 45, 2, "Move Slider to change colors", "CI"
        ' --------------------------------
        CASE ELSE
    END SELECT
END SUB

' ---------------------------------------------------------

SUB EZ_Events(FormName$, CID&, CMsg&, CVal&, Cancel&) EXPORT
    SELECT CASE FormName$
    CASE "FORM1"
        SELECT CASE CID&
            CASE %EZ_Window
                IF CMsg&=%EZ_Close THEN
                END IF
            CASE  %FORM1_HScrollBar1
                IF CMsg&=%EZ_Change THEN
                    IF CVal&<=31 THEN
                        EZ_SetColor "FORM1", %FORM1_LABEL1, 0, CVal&
                        EZ_SetText "Form1", 0, "Current Color Number is "+STR$(CVal&)
                    END IF
                END IF
            CASE ELSE
        END SELECT
        CASE ELSE
    END SELECT
END SUB

The point is, that one need not have to write code for a Windows Lean using the WIN32 directly, but one can easily build easier to use wrappers over it, but without all the bulk of most of todays UI engines, like dot.net. Yes, dot.net has its place with the cross platform world, but in the IOT world or “Maker” world, coding to the native API’s produce amazingly lean and fast applications and the hardware requirements are minimal. The GUI framework I wrote can work even on an old legacy PC with earlier Windows versions (before XP) with as little as 256 meg ram or even less and the CPU need not be more than 300 MHz (that is megahertz, not gigahertz). The diskspace requirements are almost nothing (less than a floppy disk for app and runtime).

So I have no doubt that a leaner Windows would still perform extremely well if one leveraged the WIN32 API.

Most of the current x86 “Maker” boards (System on a Chip or SOC’s) are targeting at full blown Windows and they need at least 2 GB ram and 32 GB EMMC disk space. But a tiny SOC board with as little as 1 GB ram and an 8 GB EMMC (or even less) would suffice for a very lean (WIN32 only) Windows 10 and apps written using Powerbasic or C. Actually I would not doubt that using Powerbasic, if Windows could run on as little as a 500 MHz CPU, 256 meg RAM and whatever the OS needed for diskspace plus 1 GB extra,  would suffice for developing apps  and running them all on the device itself. Some manufacturers are already making SOC boards with minimal x86 hardware, such as the 86Duino which sports a 300 MHz CPU and has directly accessible GPIO ports on it, which I have not doubt Powerbasic could run on, if a Windows Lean was able to run on it. Check out the 86Duino boards here:

http://shop.dmp.com.tw/INT/products-516

http://www.86duino.com/

Do real software companies actually use the likes of Powerbasic ?

Absolutely!  Fathom Systems in the UK are writing many applications for industrial use using Powerbasic. Check out this video of an amazing piece of industrial equipment where a laptop running an app written using Powerbasic is controlling it:

https://www.youtube.com/watch?v=D9fvdfE59_Y

At about 4 minutes and 33 seconds you will see a laptop running the controlling software which was written in Powerbasic.

Native coding is a must for developing fast and lean applications which can run with minimal hardware. Check out Herb Sutter’s talk (on Channel 9) entitled “Why C++ ?” and notice his comments about the benefits of native coding:

https://channel9.msdn.com/posts/C-and-Beyond-2011-Herb-Sutter-Why-C

The hardware is capable in the x86 world. Now software needs to catch up. This would allow manufacturers of small and tiny x86 devices (SOC’s) to build even smaller and cheaper x86 boards and devices. Imagine school children being able to purchase a tiny x86 board with a Lean Windows 10 on it and be able to write apps on it even in BASIC (a real compiler with the raw power of C). It is doable and I sure would like to see it happen.