The answer is that the programmer who has done the hard yards will have the interface up and going in the time it takes the RAD operator to pick their way through the property list with a mouse.
This is the difference between rapid front end development, bloat and all, and rapid application development based on good quality low level code. The programmer who bothers to write their own "objects" can throw them around at a rate that will make RAD operators go looking for their handbook."
08 May 98 | SLH | ~ | hutch1.htm | The supression and resurrection of assembler programming. | papers | ~ | fra_0116 |
16 May 98 | SLH | ~ | hutch_61.htm | The Bridge: In Pursuit Of Lost Knowledge | papers | ~ | fra_011C |
21 May 98 | SLH | ~ | hutquest.htm | THE QUEST: Building the launch pad | papers | ~ | fra_011F |
SLH > THROUGH THE WARP > > The software warriors > > In the year 1520, Prince Suleiman became the Sultan of the Ottoman Empire. > Two years later he successfully drove the last of the crusaders from the > island of Rhodes, the Order of the Knight of Saint John. > > In 1530, the Emperor Charles V of Austria granted the Knights tenure on the > Island of Malta where they rebuilt and re-established their Order. > > Suleiman, the greatest of the Ottoman Sultans, expanded the Ottoman Empire, > in part because of the aggressive stance of Europe and the previous invasions > by the crusaders. His reign saw not only military campaigns but art, law, > and architecture. > > Suleiman saw himself as the defender of Islam and waged war in places > ranging from Iran to Austria to make the Ottoman Empire one of the greatest > of its time. > > In 1565, he undertook a campaign against the Island of Malta to establish a > base to launch attacks on Europe. In one of the most ferocious sieges in > history, the heavily outnumbered Knights and the heroic people of Malta > eventually drove the invaders back until they withdrew after suffering > terrible losses. > > A year later, Suleiman died after the battle of Szegedvar in Hungary and > was succeeded by his remaining son Selim. The decline and fall of the > Ottoman Empire over the next 300 years is generally attributed to the lack > of Suleiman's genius by those who succeeded him. > > The parallels to the modern world of computing are very strong, empire > building, major battles between corporate giants, great winners and ruined > losers, the stuff that headlines are made from. In between are the little > guys who were the vehicle of empire building, now dispossessed by the greed > of those who used them. > > Those who have undertaken the quest to recover lost knowledge will have > their API template up, running and honed like Excalibur. The next step is > to start learning the art of swordplay. > > The art of swordplay > ~~~~~~~~~~~~~~~~~~~~ > One of the additional "features" in 32 bit windows was the capacity to > dynamically change colours and operating system component sizes. This > capacity enabled normal users to customise the appearance of their system > to meet their own needs and preferences but its implementation also created > many headaches for win 32 programmers. > > Design an interface in VGA resolution and it is to small to read at high > resolution, likewise, design an interface at a high resolution and it will > not fit the screen at VGA or Super VGA resolution. Hard code the size of > the buttons in VGA mode and the text will not fit onto them if the user > has selected large fonts at high resolution. > > You can hard code the font size from a true type font so that it does not > mess up the display but the solution is to dynamically size the interface > to fit the users choice of resolution and font and this is done in a number > of ways depending on the type of interface. > > For an MDI or similar window size interface, the process is relatively > simple, the following two API calls get the current screen size in pixels > which allows the window to be sized as it is being created. > > Sw=GetSystemMetrics(SM_CXSCREEN) > Sh=GetSystemMetrics(SM_CYSCREEN) > > Wid = Sw * .75 ' Set width and height as percentages > Hgt = Sh * .70 ' of screen size. > > Feed this set of numbers into the four size parameters in the CreateWindowEx > call and you have a resolution independent window that always starts at a > similar appearance. > > An interface that is more like a dialog box with numerous controls on it is > a bit more complex to size. You use the following function to get the base > dialog units which return to you the width and height of the system font. > > ' Some variables for the processing of the return value > ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > GLOBAL uWd as LONG ' Put these two in the header file so that they > GLOBAL uHt as LONG ' are accessible from any part of your app. > > LOCAL Unit as LONG > LOCAL lw as WORD > LOCAL hw as WORD > > Unit = GetDialogBaseUnits() > > This is a simple function call but it leaves you with a problem in that the > two values are returned as the high and low WORD values of a LONG value. > This is less than convenient when much of the number twiddling that will be > needed has to occur as LONG data types. > > There are ways of doing the conversions in high level languages but it is > here where inline assembler provides an elegant solution. The technique > treats the LONG value as an array of bytes at offsets 0,1,2,3. Copying the > address of "Unit" at offset 0 into the ax register gets the low WORD of > "Unit". Doing the same at offset 2 gets the high WORD. > > mov ax, Unit[0] ; 1 Get the loword of Unit > mov lw, ax ; 1 copy it to 16 bit variable > xor eax, eax ; 1 clear eax > mov ax, lw ; 1 copy word variable to ax > cwde ; 3 convert ax to 32 bit in eax > mov uWd, eax ; 1 copy eax into 32 bit variable > > mov ax, Unit[2] ; 1 Get the hiword of Unit > mov hw, ax ; 1 copy it to 16 bit variable > xor eax, eax ; 1 clear eax > mov ax, hw ; 1 copy word variable to ax > cwde ; 3 convert ax to 32 bit in eax > mov uHt, eax ; 1 copy eax into 32 bit variable > > The result is the font width in [ uWd ] and the font height in [ uHt ] as > LONG values which can be used for later sizing of controls. While this > example is hardly speed critical, it makes the point that if you want to > do something that would be clumsy in a higher level language, write it in > assembler and it will be both small and fast. > > The numbers in the comment columns are the clock cycles for each mnemonic > used, at 16 clock cycles you won't be burdened waiting for the code to > execute at load time. > > Colours set by the user in the "3D objects" option in the system's display > properties are another source of headache for the win32 programmer. Make > the assumption that everything is in generic grey and when a user sets their > 3D objects to lime green or hot pink, you interface looks like a patchwork > quilt. > > You basically have two choices, either control the entire interface or use > the system colours that are available. The first option is difficult but > possible under win 32, the second is reasonably straightforward. > > The system colours are listed under the WNDCLASSEX data type / structure in > win32.hlp. With the "wc.hbrBackground" member of the WNDCLASSEX structure > that provides the class background brush, substitute, > > GetStockObject(LTGRAY_BRUSH) > > with one of the system colours. For a windows client area that is used for > applications such as text or images, you are probably safer to stick to the > standard "COLOR_APPWORKSPACE" where if you are laying out a dialog style > interface, using "COLOR_BTNFACE" keeps the window the same colour as a > normal dialog box. > > The M$ literature requires the colour to have a [ + 1 ] added to it so your > WNDCLASSEX member will look like this, > > wc.hbrBackground = COLOR_BTNFACE + 1 > > Controls > ~~~~~~~~ > Without a RAD front end generator, there is only one way to create controls, > CreateWindow or CreateWindowEx API calls. The initial coding takes a little > longer but once you place it in a function, a control is only a function > call away. Controls differ from ordinary windows in as much as they are > pre-defined classes where you don't have to set the class information in a > WNDCLASS or WNDCLASSEX structure / Data type. > > Look up CreateWindow in win32.hlp and you will find the names of the popular > control classes, "BUTTON", "EDIT", "LISTBOX" etc which you use when you make > the CreateWindow call. > > FUNCTION = CreateWindow("BUTTON","&OK", _ > WS_VISIBLE or WS_CHILD, _ > x,y,wid,hgt, _ > hParent,ID,hInstance,0) > > Put this into a function call and you can re-use it as often as your code > requires a button. You test if the button has been pressed by using a > WM_COMMAND in your WNDPROC function. By trapping the LOWORD(wParam) part of > the message, you get the control ID which identifies what action to take. > > If you use a control that needs additional processing, you "subclass" it. > This is nothing more than a buzz term for writing a message handling > function similar to a WNDPROC function. > > Call your function first to get its handle, > > hEdit = MyEditCtrl( Parameters .... ) > > then you call the API, > > lpMyProc=SetWindowLong(hEdit,GWL_WNDPROC, PointerTo-> MyCtrlProc) > > and set the LONG value of the control's window class to the address of your > message handler. Put the return address [ lpMyProc ] in the header file as a > global variable so that your app can find it and then write the message > handler. > --------------------------------------------------------------------------- > FUNCTION MyCtrlProc(BYVAL hCtl as LONG, _ > BYVAL Msg as LONG, _ > BYVAL wParam as LONG, _ > BYVAL lParam as LONG) EXPORT AS LONG > > Process messages .... > > FUNCTION=CallWindowProc(BYVAL lpMyProc,hCtl,_ > Msg,wParam,lParam) > > END FUNCTION > --------------------------------------------------------------------------- > Make sure that the return value from SetWindowLong() is the first parameter > in the CallWindowProc() function or you will get an instant GP fault. Once > you have this running, you can then process any message you like that is > sent to the control by using a normal switch block / Select Case process. > > To make this easier the next time you need to "subclass" a control, save > this function as a file and put placeholders [ProcName] etc. where the names > and addresses are in the function so that next time you need the function, > you copy it into a text editor, globally replace each placeholder with the > name or address that you need and then just paste it into your code. > > This is where code reusability works for you, get it right once and you can > just keep on re-using it. Sure is a lot quicker than re-inventing your own > wheel over and over again. > > The messenger > ~~~~~~~~~~~~~ > Message Processing is done with one of the most efficient selection methods > available to programmers, the switch block / Select Case technique. It was > not all that long ago that RAD vendors were claiming that this technique > was too complicated and error prone for most programmers so they provided a > solution by preventing programmers from accessing message processing by this > technique. > > To make the point about the efficiency of this technique, MASM & TASM both > have a macro capacity to emulate Switch block / Select Case techniques. > > .IF condition > Do_This > .ELSEIF condition > Do_That > .ELSEIF condition > Do_This > .ELSEIF condition > Do_That > .ELSE > Otherwise_Do_This > .ENDIF > > In C it is simple brace matching, where you open a brace "{" at the start, > you must provide a closing brace at the other end "}". > > { // ----------------------------------> open 1 > switch (Msg) > { // ================================> open 2 > PAINTSTRUCT ps; > char lpszBuffer[128]; > > case WM_PAINT: > { // ******************************> open 3 > BeginPaint(hWnd, &ps); > PaintWindow (hWnd); > EndPaint(hWnd, &ps); > break; > } // ******************************> } // ================================ > } // ---------------------------------- > In basic it is even simpler, for each Select Case that you start, you must > have a corresponding End Select. > > Select Case Msg ' ---------------- open 1 > Case WM_COMMAND > Select Case LoWrd(wParam) ' ====== open 2 > Case 100 > > Case 101 > > Case Else > > End Select ' ===================== close 2 > > End Select ' --------------------- close 1 > > If you observe the basic discipline of writing both the opening and closing > parts of this technique and then writing you code in the middle, you will > not get into trouble. Indent each new switch block / Select Case and it > becomes easy to read and much easier to add to or modify later. > > If you dump any of these, they start to look surprisingly similar, compares > between messages and ID numbers, conditional jumps and labels. When you > process messages with this technique, you are right where the action is, not > having your hand held by a RAD vendor telling you that you are too stupid to > write a switch block / Select Case. > > Instead of fighting your way through a gaggle of different windows hoping to > find one that will do the job, you just code what you want in a normal > switch block / Select Case, and you have absolute control over your message > processing. > > At the other end of the message processing spectrum, the functions that > either send or post messages are also very efficient. You need to know > enough about where and why you are sending or posting a message but in most > instances, if you want an "object" to do something, you send a message to > it. > > The format for both SendMessage() and PostMessage() are close enough to the > same, handle, message, wParam & lParam. There has been a tendency to wrap > or encapsulate these functions on the assumptions that sending messages is > too difficult for many to use (read "too stupid to use") but this loses the > general purpose advantage that messaging functions have. Sending messages is > both very flexible and very powerful in a message based operating system so > it is to the programmers advantage to get used to the technique. > > The fun stuff > ~~~~~~~~~~~~~ > Now once you have your controls and subclassing routines up and reliable, > you can start to do cheeky things with them. A good example is a dialog > type application where you need a matrix of buttons for things like > calculators. Armed with the unit size of the system font that was returned > by GetDialogBaseUnits() you can write functions that will display the > numeric keypad, 1 to 9, 0, "." and "=" in a single function call. > > Twiddle the numbers for the function call and you can change the button > sizes, spacing, number of rows and columns. Make a second call for the > function block of buttons, + - * / ^ etc and if you index the starting > position to the first call, all you need to do when adjusting the interface > is to twiddle the numbers for the starting point at the top left corner and > you can position the whole button pad where you want. > > When you compile a "number" like this, it will display correctly at any > resolution and at any font size by autosizing dynamically. What happens > when a programmer undertakes the quest for the lost knowledge of low level > power is that they not only find it, they use it. > > With a library of procedures of this type in whatever category of components > are seen as useful by the programmer, production suddenly rises very > dramatically. Now some may ask, isn't this what RAD systems are for, just > draw up the interface with a mouse and you don't have to do all this hard > coding ? > > The answer is that the programmer who has done the hard yards will have the > interface up and going in the time it takes the RAD operator to pick their > way through the property list with a mouse. > > This is the difference between rapid front end development, bloat and all, > and rapid application development based on good quality low level code. The > programmer who bothers to write their own "objects" can throw them around at > a rate that will make RAD operators go looking for their handbook. > > It is the difference between doing a backup over an entire drive using an > archiving package where you type in the command line and parameters, press > the enter key and it goes BANG all by itself rather than having to pick > every file out of a drive with a mouse and put it into a directory. How > long would it take to pick a couple of thousand files out of a GUI with > a mouse ? > > The time warp > ~~~~~~~~~~~~~ > With the speed in which information is developed and communicated across the > Internet, the notion of time is subject to what could be called compression. > The rate of change often leaves high quality information behind over a > period of only a couple of years, even though this is like a millennium in > computer information terms. > > While much of this information languishes in an archive on a hard disk > waiting to be trashed to make room for something else, every so often, one > of the ancient warriors who did battle in another world and time will come > through the time warp for just a moment and post lost information so that > it can be used by the next generation of software warriors. > > To any of these ancient worriors who still bother to roam the Internet in > search of the way the world used to be, here is the challenge, don't trash > the fruits of your imagination, labour and passion, tidy it up and pass it > on to those who will do it justice. Trash it and you have let the greedy > corporate vendors get away with their treachery. There are things that you > know that will help to bring in a new order. > > Now this may be difficult for some who may have suffered non-disclosure > agreements and contracts that prevent them from working in the computer > industry for years after they were fired but there is a simple solution to > the problem, post you pieces of lost knowledge using a pseudonym, "FrEdDo > dUr PhRoGG", "ZuR uNdUrTaKur", "MySs_PyGgI" or whatever appeals to your > sense of humour, as long as you do post it. > > Interestingly enough, the risk is probably not as high as it used to be, so > many of the old software houses have gone to the wall, invective, debts, tax > liabilities and all. Much of their former management are on "permanent > holidays" in strange and exotic places to avoid their debts and to avoid > prosecution for tax evasion. > > The great circus > ~~~~~~~~~~~~~~~~ > We have unfolding before us, all of the necessary ingredients of a passion > play, a comic opera and a 19th century melodrama all rolled up into one > great circus, the action being taken by the US Department of Justice against > the monolith that Microsoft has become. > > We will see martyrs, the righteous, the self righteous, the greedy, the > ambitious and eventually, the winners and losers. History tells us that > Microsoft will go down the same road as Standard Oil, IBM and others when > they turned into arrogant monopolies that were more interested in market > share than delivering performance. > > The power of all those little people who have been used or treated like > unrealized profits by greedy corporations comes in the form of their > collective power as voters. This is seen in the form of law that is designed > to protect a society from excesses that it does not want. > > Monopolies dictate prices, products and performance to satisfy their own > corporate financial requirements, a very familiar tune to those in the > computer software industry, the only solution is to break their monopoly by > law when the normal processes of competition have been perverted by ugly and > often illegal business practices. > > You can fool all of the people some of the time > You can fool some of the people all of the time > But you can't fool all of the people all of the time. > > Abraham Lincoln, 1864 > > An interesting piece of quantifier calculus from a statesman who had other > things in mind but for Microsoft, the penny has dropped and nobody is > fooled anymore. Maybe the folks at Microsoft didn't think Abe was right. > > As Suileman the Magnificent brought in order, peace, law and all the > advantages of protection by great power and vision, his successors let the > gains slide bit by bit as they became progressively more decadent and > detached from the world that Suileman had shaped. > > The occupation of the Balkan peninsular by the Ottoman Empire as it decayed > over a period of hundreds of years did so much damage to the society and > morale of the people who lived their that the problems that follow from the > area's often tragic history are still unresolved today. > > Turkey was rescued from the collapse of the Ottoman Empire at the end of the > first world war by a young military officer, Mustafa Kemal who became known > as Kemal Ataturk, the Father of the Turks. > > Computer users, from private to business users cannot afford to have one of > the useful tools in society crippled by a monopoly on its way out. How much > better it is to address the problem front on and use the political power > that belongs to the majority in society to bring this monster to its knees > before it does any more damage. > > For those ancient warriors who have come back through the time warp for a > moment and given some of their hard won knowledge to another generation of > software warriors, its time for a small reward. > > From wherever your world and time may be, whether its carving out a career, > consolidating a hard won business or setting up a comfortable retirement, > pick your favorite bottle of pure malt, (ancient warriors know their way > around such things), pour yourself a dram (never too much, it dulls the > senses) and ponder whether the world will be a better place in the future. > > If your favorite malt is a truly excellent example of the highland's finest, > then no matter where you are, whether it is a hot and steamy lowland, a cold > and wind swept mountain, a tropical island where the monsoon season rains > never stop or a parched and desolate place with cracks in the ground, a wee > dram will let you hear the soft rain on the roof, the distant sounds of > people with a strange accent, the wind will drop to a murmur and the answer > will be yes, the world will be a better place. > > THROUGH THE WARP >