Starting out with OWL

Starting out with OWL

By Steve Page

Overload, 1(1):, April 1993


About six months ago I made the dramatic step of up­grading to Borland C++. Previously I had been a de­vout disciple of C and felt the time had come to find out about the future for C programmers (at least that is what the hype would have us believe). Learning how to use C++ did not cause too many problems; I worked through the tutorials, knocked up a few small pro­grams and generally felt this new language could be useful. Confidence boosted I then felt that the time had come to tackle programming Windows applica­tions with the aid of the OWL class libraries supplied with my Borland compiler. This brought me back down to Earth with a bump!

Basically to learn anything new I tend to scan-read the tutorials and manual that hopefully makes sense, and then find some project that will force me to use the skill. This is usually where it comes crashing home that things are never easy, but it does have the advantage that I do learn the task in hand. Windows programming was no different, and the idea I have for this series (I hope) of articles is to narrate the project I have em­barked upon to teach myself Windows programming using the OWL class libraries.

The task I chose was to develop a file manager. Yes, I know there are probably trillions of these in existence, but the reason that so many have been programmed only goes to show that what has been done so far does not suit everybody's taste! My favourite file manager to date is probably Norton Commander, probably be­cause it favours the 'power user' and not the 'average user' (I'm too sexy for my shirt!). Being a professional programmer I tend to use applications that are key­board rather than mouse intensive such as text editors and debuggers. Many of these applications often have the mouse 'bolted' on to them to bring them into the 1990s (Brief?), and it rarely suits them. For this reason I wanted to develop something that is simple and fast to use, and most importantly would avoid me having to find the mouse from amongst the junk and plastic cof­fee cups on my desk! I know I'm a Luddite (I have even dumped Program Manager for a keyboard-based shell), but I really feel sometimes that Windows appli­cations are aimed at wimps (not WIMPs) and miss out using the power that could be there.

The starting point of any application is to lay down what is really required from the program. It is all too easy to kick the editor off and start programming before really deciding where to go as many of you will know. I decided that the essence of my file manager is that it must be very simple and must, at all costs, avoid the need to use the 'tab' key to move around the child windows (such as file and drive lists, etc.). All input to this application should be seen to be through the one point, the (dare I say it?) 'Command line'. The file list should have a fast search ability. The actions that can be performed on file selections are also to be fairly basic as too much functionality can, I feel, make the application clumsy. Actions I intend to support are: copy, move, delete, view, exec, and attribute change. Any remaining functionality will be served by giving the application the ability to bring selected file names down on to the command line from the file list to act as parameters to other independent programs. A final feature I wish to add (although this may be ambitious) is to allow DOS commands to be passed off to an al­ready running DOS window that has a shell waiting for such tasks. This would get round the problem of DOS windows launched from the 'run' command closing as soon as the program terminates. This would also give the application something like the UNIX '&' command.

Anyway that's enough of the requirements spec and design, lets get on with the interesting bit! Microsoft has provided in the Windows API a very useful control by way of the list box, you can even send it a message to load a file list. When the list box has focus, keyboard entry can be used to a limited degree to locate items, but unfortunately this is limited to the first matching character. I wanted something more for my file man­ager so I set about creating a super list box with a fast search control.

I took TListBox class supplied with OWL as a starting point and set about building an enhanced list box class. I came up with the following class definition:

  _CLASSDEF (TTestListBox)
  class TTestListBox: public TListBox
  {
  public:
    TTestListBox(PTWindowsObject AParent,
                 int AnId, int X, int Y, int W,
                 int H, PTModule AModule = NULL):
             TListBox(AParent, AnId.X,Y,W,H,AModule);

    // Load file list
    int Load(int attr, LPCSTR fspec);

    virtual void SetupWindow() {
      // Default - load current directory into
      // file window
      Load(0, "*.*");
    };

    virtual int FindItemAndMark(RTMessage Msg) =
        [WM_FIRST + CM_FINDNMARK];

    virtual void WMDblClick(RTMessage Msg) =
        [WM_FIRST + WM_LBUTTONDBLCLK];

    virtual void WMChar(RTMessage Msg) =
        [WM_FIRST + WM_CHAR];

    virtual int ActionSelection();
  };

Although I could have sent the list box an LB_DIR message that would load a file list, I wanted to be able to display extra details about a file so I decided I need­ed a 'Load' method to fill the list. At first I placed the first call to Load in the constructor and was surprised to find that the list box did not load. If I created a button and used this to call load everything was fine, so why wouldn't it work in the constructor? The answer was that one of the last things the constructor does is to clear the list box; what a useful feature this is, I thought! Fortunately the designers of the OWL librar­ies realised that we would probably want to display more than blank windows to our users, so they provid­ed the SetUpWindow method. Overriding this method allowed me to call Load and see the effect.

  int TTestListBox::FindItemAndMark(RTMessage Msg) {
    unsigned result;
    Pint         SelList  = NULL;

    result = GetSelCount();
    if   (result  >  0)
    {
      SelList = new int[result];
      GetSelIndexes(SelList, result);
      SetSelIndexes(SelList, result, FALSE);
    }
    result = SetSelStrings(&(LPSTR)Msg.LParam,
                           1, TRUE);
    return result;
  }

The 'FindltemAndMark' method does the searching of the list box using the string pointed to by Msg.LParam. If one is found it selects it clearing all other previous selections, otherwise it leaves none selected.

The remaining methods WMDblClick, WMChar and ActionSelection are to handle mouse double clicks and the 'enter' key being pressed. In both cases they will call ActionSelection.

To make this work all we need now is a dialog box with an edit control and OK button? Only snag is that the text entered into the edit control will only be passed to the listbox control when the OK button is pressed, I wanted to be able to dynamically search as text is en­tered. So I had to create a new edit control:

  _CLASSDEF (TTestEdit)
  class _EXP0RT TTestEdit: public TEdit
  {
  public:
    TTestEdit(PTWindowsObject AParent, int AnId,
              LPSTR Astr, int X, int Y, int W,
              int H, WORD len, BOOL IsMulti) :
          TEdit(AParent, AnId, Astr, X, Y, W, H, len, IsMulti)
    {};

    virtual void HandleChar(RTMessage Msg) =
        [WM_FIRST + WM_CHAR];

  };

The above class that is derived from TEdit allows me to 'catch' characters entered and pass them on to the listbox as they are entered.

  void TTestEdit::HandleChar(RTMessage Msg)
  {
    LRESULT result;
    LPSTRStringz[20];

    DefWndProc(Msg);

    GetLine(Stringz, 20, 0);
    result = SendMessage(((TTestWindow *)Parent->
                  Parent)->ListBox->HWindow,
                  CM_FINDNMARK,0,(LONG)Stringz);
  }

I'm not particularly proud of the way in which I send the message to the list box, but it worked! The dialog box that contains this edit control was then attached to an accelerator key to allow it to be invoked. In my next ar­ticle I hope to take the project further, but in the mean­time I welcome any input from yourselves. Over to you.






Your Privacy

By clicking "Accept Non-Essential Cookies" you agree ACCU can store non-essential cookies on your device and disclose information in accordance with our Privacy Policy and Cookie Policy.

Current Setting: Non-Essential Cookies REJECTED


By clicking "Include Third Party Content" you agree ACCU can forward your IP address to third-party sites (such as YouTube) to enhance the information presented on this site, and that third-party sites may store cookies on your device.

Current Setting: Third Party Content EXCLUDED



Settings can be changed at any time from the Cookie Policy page.