Site hosted by Angelfire.com: Build your free website today!

Home
DelphiZeus
13A. MakeApp Examples
Example Code for MakeApp,
with Drag and Drop from Explorer.

Home



Example Code for MakeApp Unit

Here you can look at some code that will give examples for using the functions in the MakeApp.pas unit. Many of the functions were explained in the InUnits Lesson, and the added functions for MakeApp are explained in the Lesson about the MakeApp Unit. So I will not give any more information here about MakeApp functions. You can look at the code and comments in the UseMakeAppU.pas file code below for information about what the code is doing.
There is an API method for simple Drag and Drop from Explorer, which I will talk about here, using the DragAcceptFiles( ) procedure.

Explorer Drag and Drop using DragAcceptFiles( ) Procedure

Doing drag and drop between two different processes (programs) is usually done with the system COM interfaces of  IDropSource, and IDropTarget. . But to do a simple file path drag and drop from explorer, the API offers a way to do it without using the IDropSource or IDropTarget interfaces or any COM methods. You can use the DragAcceptFiles( ) procedure for a window's handle, and the operating system will implement and use (translate) the COM interfaces, then send the system message WM_DROPFILES to that window, whenever files are dropped on that window. When this WM_DROPFILES message is received by a window, you can call two functions to get information about the file paths dropped on the window. The DragQueryFile( ) function is used to get the PChar strings for each file path in the drop, the DragQueryPoint( ) function gets the position of the cursor (TPoint) in the window where the drop happened. Whenever you call one of these functions in a WM_DROPFILES message the system will use the drop Interfaces, so you MUST call the DragFinish( ) function, to tell the system to release and free any COM interfaces or system memory that the system may have used for this. Lets look at the parameters for the DragAcceptFiles( ) function which is defined as -

procedure DragAcceptFiles(
   Wnd: HWND;	// handle to the window for drag and drop
   Accept: BOOL  // accept drop option
   );
This procedure is an OS Shell function so you must have  ShellApi  in your uses clause. The first parameter is the Handle of the window that you want this procedure to affect. The second parameter is a Bool value that is set to True to have the window accept drag and drop, , and set to False to remove the window from drag and drop.

When DragAcceptFiles( ) is set to True for a window, and an explorer file drop happens on that window, the WM_DROPFILES message is sent to that window.

WM_DROPFILES Message
With this WM_DROPFILES message, is the WParam, which will have the "Drop Handle" used for this message (the LParam is not used). . The Drop Handle is a system identifier for information about the dropped files used for this message. This WParam drop handle is used by the DragQueryFile( ), DragQueryPoint( ) and DragFinish( ) functions to get information about the dropped files and end the drop operation. Most always you Do NOT call the window's DefWindowProc( ) with a WM_DROPFILES message. In the windows OS, windows 98 or newer the WM_DROPFILES message is sent even if the Drop happens on a child control of the Drop accept window.

DragQueryFile( ) function
Let's look at the DragQueryFile( ) function -

function DragQueryFile(
  Drop: HDROP;  // drop handle from WParam
  FileIndex: UINT; // index of file path in the drop info
  FileName: PChar; // buffer that recieves the filename
  cb: UINT   // size of buffer for filename
*   ): UINT;
This function has three uses

1 - it can return the number (count) of file path names in the drop
2 - it can return the length (memory block size) of the file path
3 - it can retrive the file path into a buffer.

The Drop parameter is always a drop handle from the system, which is the WParam in a WM_DROPFILES message.

  1. To get the number (Count) of the files dropped, you must have the FileIndex parameter as MaxDWord ($FFFFFFFF, a -1 for UNIT), and the function result will be the number of files in that drop. The FileName and cb parameters are ignored if the FileIndex parameter is MaxDWord.

  2. To get the length of a certain file path, you will need to place the zero based Index of the file in the FileIndex parameter and have the FileName parameter as NIL. The function result will be the Length of the PChar string for that index. The cb parameter is ignored if FileName is NIL.

  3. To recieve the FileName, you include the FileIndex and have the FileName as a memory block (PChar) with enough buffer space to get the full path, you will need to place the size of this memory block in the cb parameter. The function result will be the number of characters (length) placed in the FileName memory block.
DragQueryPoint( ) function
This function will get the mouse cursor position for the Drop, , if the Drop is in the Controls client area. Let's look at the DragQueryPoint( ) function -
function DragQueryPoint(
  Drop: HDROP; // handle to structure for dropped files
  var Point: TPoint // TPoint for control mouse coordinates
  ):
The Drop parameter is always a drop handle from the system, which is the WParam in a WM_DROPFILES message.
The Point parameter will be filled with the control's X an Y position of the mouse cursor of the Drop position on that control. This only happens if the Drop position in on the Client area of the control. If the drop happens on the border or scroll bars, then this DragQueryPoint( ) function returns FALSE and the TPoint if filled with zeros. So you should always check the result of the DragQueryPoint( ) function.

DragFinish( ) procedure
This procedure will tell the system you are finished with the system Drop information and COM interfaces. You must ALWAYS call the DragFinish( ) procedure in a WM_DROPFILES message, so the system can release memory and interfaces it has created for this Drop operation.

procedure DragFinish(Drop: HDROP);
If you set a window to recieve explorer drag and drop with DragAcceptFiles( ), be sure to process the WM_DROPFILES message and call DragFinish( ).

Example code for a WM_DROPFILES message -

WM_DROPFILES:
    begin
    //the WParam has the file drop Handle in it
    StrSize := 256;  // StrSize is an Cardinal variable
    Count := DragQueryFile(WParam, MaxDWord, nil, StrSize);
  {DragQueryFile is called 3 times to get 3 different data information.
   With MaxDWord and nil, it will return the number of file names in the Drop,
   to the Count variable, an Integer}
    for i := Zero to Count- One do 
    // i is Integer used as the Index for the DragQueryFile
      begin
      StrSize := DragQueryFile(WParam, i, nil, StrSize);
      // StrSize will have the number of Charaters
  {DragQueryFile will return the length of the file name string, if you
   have the Index number and also have nil for the PChar}
      if StrSize < One then Continue;
      SetLength(StrLB, StrSize); // StrLB is a String variable
      DragQueryFile(WParam,i,PChar(StrLB), StrSize + One);
  {DragQueryFile will place the file name in PathStr if the PChar is not nil}
      SendMessage(hListBoxPan, LB_ADDSTRING, Zero, Integer(PChar(StrLB)));
      // add the file path to a list box
      end;

    DragFinish(WParam); // IMPORTANT, always call DragFinish
  // IMPORTANT DO NOT LET DefWindowProc be called if you do the WM_DROPFILES
    Exit; // You MUST Exit
    end;
You can see a code example for WM_DROPFILES in the DoListDrop procedure of the UseMakeAppU.pas example below.

the UseMakeApp Program

This program will show you how to use the "Make" functions in the MakeApp Unit and to use the DragAcceptFiles( ) procedure with it's WM_DROPFILES message. The Drag and Drop functions are explained above, you should look at the DoListDrop( ) procedure in the code below for an example of WM_DROPFILES message handling.
  The "Make" functions in the MakeApp unit are all explained in the Lesson 12, MakeApp Unit page, so you can go to that page if you need information about them. Most of them are not difficult to use, but the MakeSubMenu( ) and it's ItemList parameter may take more to learn, so you should look at the different sub-menus created in the MakeProgram( ) function in the code below. There are two "Panels" created in this, and they each need a TPanelFunc function to handle their messages. You can look at their TPanelFunc message functions - PanelMessFunc and PanelMessFunc2

To show you how to have a child control that had focus, to regain focus when the main Window (Form) becomes Active after losing keyboard focus, I have included an integer variable in the UseMakeAppU.pas Unit called ActControl. This is used to store the Active (Focus) control handle when the form loses keyboard focus. You can look in the form's MessageFunc for the WM_ACTIVATE, WM_SETFOCUS, WM_KILLFOCUS, and WM_ACTIVATEAPP messages to see how to store and re-focus a child control

There are comments in the unit code that should give information about how and why I do those things.

Below is the code for the parts of this UseMakeApp program

Code for the   Theme.RC   , resource creation file
    One line of code -
1 24 "Theme.xml"

Code for the Theme.xml manifest document
    Six lines of code -
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="Co.Prd.Prg" type="win32" />
<dependency><dependentAssembly><assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls"
version="6.0.0.0" publicKeyToken="6595b64144ccf1df" language="*" processorArchitecture="*" />
</dependentAssembly></dependency></assembly>

You will need to compile the Theme.RC file with the Delphi   brcc32.exe resource
compiler to get the   Theme.RES   file used in the next code

Code For The UseMakeApp.dpr Program File
    This is like the code for the InUnits program
program UseMakeApp;

uses
  MakeApp, UseMakeAppU;

{$R *.RES}
{$R Theme.RES}
// Theme.RES has a win XP theme manifest

begin
if MakeProgram then // MakeProgram in UseMakeAppU
  RunMsgLoop; // RunMsgLoop in MakeApp
end.

Code For The UseMakeAppU.pas Unit
    See the comments in this code for more information
unit UseMakeAppU;
{this unit will contain the code for the UseMakeApp program
 the code here will give examples of using the functions in the MakeApp unit
 and system Drag and Drop with the DragAcceptFiles function}

interface

var    
hForm1: Integer = 0; // handle of Main Window (Form)

function MakeProgram: Boolean;
{the MakeProgram function will call some functions in MakeApp.pas
to create the windows and controls for this Application.
If there is a creation error for the main window, it returns False}

implementation

uses
  Windows, Messages, ShellApi, MakeApp, SmallUtils;
  // you add the ShellApi to uses in order to use the Shell Drag and Drop

const
One = 1; // I include this because the number 1 is used so many times
ColorPan: Cardinal = $29EEF1; // this is the BASE color for the hPanel1

// below are the constants for control ID numbers
ID_ExitBut = 1000;
ID_PanelBut = 1001;
ID_PanelBut2 = 1002;
ID_Edit1 = 1003;

// below are the constants for menu Items ID
m_TopItem = 10;
m_Second = 11;
m_Add2ListBox = 12;
m_ChangeEdit = 13;
m_Exit = 14;
m_MoveP1 = 20;
m_MoveP2 = 21;
m_ColorP1 = 22;
m_MessBox = 30;
m_AddedItem = 60;

var
hCombo, Font1, FontP, hListBox1, hListBoxPan, hEdit1, hPanel1,
hPanel2, ActControl: Integer;
{ ActControl is used to to store the Active Control Handle,
  which is given focus when the Form regains keyboard focus
  on application activate}
PanelColor: Cardinal = Zero; // holds the current color painted on hPanel1
pListProc: Pointer; // Sub Class function pointer


procedure DoListDrop(wParam: Integer);
var
PathStr: String;
Count, Index, i: Integer;
StrSize: Cardinal;
DropPnt: TPoint;
begin
{this is the procedure to handle the Drag and Drop message on the hListBox1,
 the WParam will have the hDrop, file drop Handle in it}
StrSize := 256;
{DragQueryPoint will get the point location of the "Drop" on the Control}
if DragQueryPoint(WParam, DropPnt) then
  begin
  {I get the List Box Index for the Location where the drop
    mouse button was released since DragQueryPoint will get the cursor
    position on hListBox1 where the Drop happened}
  Index := CallWindowProc(pListProc, hListBox1, LB_ITEMFROMPOINT,
                            Zero, MAKELPARAM(DropPnt.x, DropPnt.y)) and $FFFF;
  end else Index := Zero;
  {DragQueryPoint only returns True if drop was on the Client area of
    the control, drop on the List Box scroll bars will return False}

Count := DragQueryFile(WParam, MaxDWord, nil, StrSize);
  {DragQueryFile is called 3 times to get 3 different data information.
  With MaxDWord and nil, it will return the number of file names in the Drop}
for i := Zero to Count- One do
  begin
  StrSize := DragQueryFile(WParam, i, nil, StrSize);
  {DragQueryFile will return the length of the file name string, if you
   have the Index number and also have nil for the FileName PChar}
  if StrSize < One then Continue;
  SetLength(PathStr, StrSize); // StrSize will have the number of Charaters
  DragQueryFile(WParam,i,PChar(PathStr), StrSize + One);
  {DragQueryFile will place the file name in PathStr if the FileName PChar is not nil}

  // add the dropped file path to hListBox1
  CallWindowProc(pListProc, hListBox1, LB_INSERTSTRING, Index, Integer(PChar(PathStr)));
  // I use CallWindowProc instsead of SendMessage code below
  //SendMessage(hListBox1, LB_INSERTSTRING, Zero, Integer(PChar(PathStr)));
  end;

DragFinish(WParam);
{IMPORTANT - you MUST call DragFinish to end and release the Drag methods
 and system resources the system is using for the drop operation}
end;

function ListBFunc(hWnd, Msg, WParam, LParam: Integer): Integer; stdcall;
begin
if Msg = WM_DROPFILES then
  begin
  {the Only message I process for this List box is the
   drag and drop files Message}
  DoListDrop(WParam);
  Result := Zero;
// IMPORTANT DO NOT LET CallWindowProc be called if you do the WM_DROPFILES
  Exit; // You MUST Exit
  end;
Result := CallWindowProc(pListProc,hWnd,Msg,wParam,lParam);
end;


function PanelMessFunc(iMsg,wParam,lParam:Integer):Integer;
var
PaintS: TPaintStruct;
begin
{For a MakeApp Panel, you will need to give a TPanelFunc function in the
 MakePanel creation function, if you want to process that panel messages.
 This is the TPanelFunc function for hPanel1}

{The Result of This function is passed back to the system as the Result
 of this panel's window message proc, and the DefWindowProc will NOT be called,
 EXCEPT if the Result is -2 here}

Result := -2; { the result of -2 here, will call the DEFAULT system message
                processing (DefWindowProc) in this TPanelFunc and
                return that Result}
case iMsg of
  WM_PAINT:
    begin
    { there is NO hWnd paramteter in the TPanelFunc like in the window Message
      functions, but you should know the panel's handle from the MakePanel
      function where you assign this TPanelFunc}
    BeginPaint(hPanel1, PaintS); // use the hPanel1  handle

    // the PatBlt function is used to change the color of this panel
    SelectObject(PaintS.hDC, CreateSolidBrush(PanelColor));
    PatBlt(PaintS.hDC,PaintS.rcPaint.Left,PaintS.rcPaint.Top,
           PaintS.rcPaint.Right, PaintS.rcPaint.Bottom, PATCOPY);
    DeleteObject(SelectObject(PaintS.hDC, GetStockObject(NULL_BRUSH)));

    // the Rectangle functions draws a simple border for this panel
    Rectangle(PaintS.hdc,Zero,Zero,150, 106);
    SelectObject(PaintS.hDC, GetStockObject(WHITE_PEN));
    Rectangle(PaintS.hdc,Zero,Zero,160, 110);

    SetBkMode(PaintS.hdc, TRANSPARENT);
    SSelectObject(PaintS.hdc, FontP);
    TextOut(PaintS.hdc,30,42, 'Click on this Panel',19);
    EndPaint(hPanel1,PaintS);

    Result := Zero; // Does NOT allow DefWindowProc to be called
    // if Result is NOT -2 then default system message processing is NOT called
    end;
  WM_COMMAND: if LOWORD(wParam) = ID_PanelBut then
    SetWindowText(hEdit1, 'Do Edit Text');

  WM_LBUTTONDOWN: SetWindowText(hEdit1, 'Panel Click');
  // the WM_LBUTTONDOWN above is like a click event for this panel
  end;
end;


function PanelMessFunc2(iMsg,wParam,lParam:Integer):Integer;
var
PaintS: TPaintStruct;
begin //This is the TPanelFunc function for hPanel1
Result := -2; // -2 will call the Default system message processing
case iMsg of
  WM_PAINT:
    begin
    BeginPaint(hPanel2, PaintS); // use the hPanel2 handle
    SetBkColor(PaintS.hdc, $6A92FF);
    SelectObject(PaintS.hdc, VarFont);
    TextOut(PaintS.hdc,50,32, ' Panel Label ',13);
    EndPaint(hPanel2,PaintS);
    Result := Zero; // Does NOT allow DefWindowProc to be called
    end;
  WM_COMMAND: if LOWORD(wParam) = ID_PanelBut2 then
    MessageBox(hForm1, 'Panel Button Click', 'Click Button', MB_ICONINFORMATION);

  end;
end;

procedure MenuClick;
begin // just a messagebox function for several menu Items
MessageBox(hForm1, 'Menu Item Click', 'Menu Click', MB_ICONINFORMATION);
end;

procedure ShutDown;
begin
DragAcceptfiles(hListBox1, False);
DragAcceptfiles(hForm1, False);
{some MS code examples tell you to call DragAcceptfiles with False,
 if you call it with True}
PostQuitMessage(Zero);
end;


function MessageFunc(hWnd,iMsg,wParam,lParam:Integer):Integer; stdcall;
var
PaintS: TPaintStruct;
posRect: TRect;
Count, StrSize, i: Integer;
StrLB: String;
begin
Result := Zero;
case iMsg of
  WM_DESTROY: ShutDown;
  WM_ACTIVATE: if LOWORD(wParam) = WA_INACTIVE then
    begin
    {there are several messages where I get the current control that has
     focus and assign it's handle to ActControl}
    ActControl := GetFocus;  // can be zero or hWnd
    if (ActControl = Zero) or (ActControl = hWnd) then
      ActControl := hEdit1;
    end;
  WM_SETFOCUS: SetFocus(ActControl);
    {when this form is activated it gets the WM_SETFOCUS message, but NO
     control is given focus, so to have the last control regain focus
     use the SetFocus function for ActControl}
  WM_KILLFOCUS:
    begin
    // do GetFocus for current control
    ActControl := GetFocus;
    if ActControl = Zero then
      ActControl := hEdit1;
    end;
  WM_PAINT:
    begin
    BeginPaint(hWnd, PaintS);
    SetBkMode(PaintS.hdc, TRANSPARENT);
    SelectObject(PaintS.hdc, VarFont);
    TextOut(PaintS.hdc,8,10, 'Drag and Drop on List Box',25);
    EndPaint(hWnd,PaintS);
    Exit;
    end;

  WM_ACTIVATEAPP:
    if wParam = Zero then
    begin
    {with wParam as zero, the app is being DE-activated
     so do GetFocus}
    ActControl := GetFocus;
    if ActControl = Zero then
      ActControl := hEdit1;
    end;
  WM_COMMAND:
    if lParam = Zero then
      begin
      case LOWORD(wParam) of
        // menu Item ID
        m_TopItem: MenuClick;
        m_Second: MenuClick;
        m_Add2ListBox:
          begin
          Count := SendMessage(hListBox1, LB_GETCOUNT, Zero, Zero);
          StrLB := 'New LB Item '+Int2Str(Count);
          SendMessage(hListBox1, LB_ADDSTRING, Zero, Integer(PChar(StrLB)));
          end;
        m_ChangeEdit: SetWindowText(hEdit1, 'Edit Text from Menu');
        m_Exit: PostMessage(hForm1, WM_CLOSE, Zero, Zero);
        m_MoveP1:
          begin
          GetWindowRect(hPanel1, posRect);
          ScreenToClient(hForm1, posRect.TopLeft);
          ScreenToClient(hForm1, posRect.BottomRight);
          posRect.Bottom := posRect.Bottom - posRect.Top;
          posRect.Right := posRect.Right - posRect.Left;
          if posRect.Top = 10 then
            begin
            posRect.Top := 51;
            posRect.Left := 310;
            end else
            begin
            posRect.Top := 10;
            posRect.Left := 230;
            end;
          MoveWindow(hPanel1, posRect.Left,posRect.Top,
              posRect.Right, posRect.Bottom, True);
          end;
        m_MoveP2:
          begin
          GetWindowRect(hPanel2, posRect);
          ScreenToClient(hForm1, posRect.TopLeft);
          ScreenToClient(hForm1, posRect.BottomRight);
          posRect.Right := posRect.Right - posRect.Left;
          if posRect.Left = 106 then
            posRect.Left := 136 else posRect.Left := 106;
          MoveWindow(hPanel2, posRect.Left,posRect.Top, posRect.Right,
                     posRect.Bottom - posRect.Top, True);
          end;
        m_ColorP1:
          begin
          if PanelColor  = ColorPan then
            PanelColor := $EEF100 else
            PanelColor := ColorPan;
          InvalidateRect(hPanel1, nil, False);
          end;
        m_MessBox: MessageBox(hForm1, 'Message Box menu Click', 'Menu Click',
                              MB_ICONINFORMATION);
        m_AddedItem: MessageBox(hForm1, 'Added Item menu Click', 'Menu Click',
                                MB_ICONINFORMATION);
        88: MessageBox(hForm1, '88 click', 'Menu Click',
                                MB_ICONINFORMATION);
        end; // case LOWORD(wParam)

    end else  // if lParam = Zero
      if LOWORD(wParam) = ID_ExitBut then
        PostMessage(hForm1, WM_CLOSE, Zero, Zero);

  WM_DROPFILES:
    begin
    {the WParam has the file drop Handle in it
     see the DoListDrop procedure above for info about DragQueryFile}
    StrSize := 256;
    Count := DragQueryFile(WParam, MaxDWord, nil, StrSize);
    for i := Zero to Count- One do
      begin
      StrSize := DragQueryFile(WParam, i, nil, StrSize);
      if StrSize < One then Continue;
      SetLength(StrLB, StrSize);
      DragQueryFile(WParam,i,PChar(StrLB), StrSize + One);
      SendMessage(hListBoxPan, LB_ADDSTRING, Zero, Integer(PChar(StrLB)));
      end;

    DragFinish(WParam); // IMPORTANT, always call DragFinish
  // IMPORTANT DO NOT LET DefWindowProc be called if you do the WM_DROPFILES
    Exit; // You MUST Exit
    end;
  end; // case iMsg
Result := DefWindowProc(hWnd,iMsg,wParam,lParam);
end;


procedure MakeControls;
begin
PanelColor := ColorPan; // set PanelColor to const
Font1 := MakeFont(-15, 10, 'Arial');
// with MakeFont you can create a font with just 3 parameters
FontP := MakeFont(-12,Zero, 'Arial', [flBold, flItalic]);

DragAcceptFiles(hForm1, True);
{ to set the Main Form as a window that accepts drag and drop files from
 explorer, you can call the function DragAcceptFiles with True}

hCombo := MakeComboBox(160, 30, 122, 115, hForm1,
             #255'Combo Box'#0'Next Item'#0'Lower'#0'Middle'#0'Down'#0+
             'Way Down'#0'Way way Down'#0'Lowest'#0);
{MakeComboBox uses the ListItems parameter as a #0 delimited string to place
 several Items in the Combo Box}
             
hPanel1 := MakePanel(330,51, 150, 106, hForm1, PanelMessFunc, 66, psNone);
{the MakePanel function will make a Container Window, if you have child
 controls on the panel, you will need a PanelMessFunc to process
 their WM_COMMAND messages}

// I palce a button and an Edit on this Panel
MakeButton(32,10,84, 20, 'Do Edit Text', hPanel1, ID_PanelBut);

hEdit1 := CreateWindowEx(WS_EX_CLIENTEDGE,'Edit','Edit Box Text',
    WS_VISIBLE or WS_CHILD {or ES_AUTOHSCROLL} or WS_TABSTOP,
    10,70,130,21,hPanel1,ID_Edit1,hInstance,nil);
SendMessage(hEdit1,WM_SETFONT,VarFont,Zero);

ActControl := MakeButton(392,238,84, 24, 'E X I T', hForm1, ID_ExitBut, Font1);
{ActControl is used to keep track of the Active (Focus) control, which is lost
if the Form is not the foreground window}

hPanel2 := MakePanel(152,94, 170, 144, hForm1, PanelMessFunc2, 67, psTabEdge);

// i put a button and a List Box on the second panel
MakeButton(5,6,76, 22, 'Panel Button', hPanel2, ID_PanelBut2);

hListBoxPan := MakeListBox(3,50, 159, 86, hPanel2,
             #255'Panel List Box'#0'list Item'#0);

hListBox1 := MakeListBox(4,30, 142, 86, hForm1,
             #255'List Box 1'#0'List Item'#0'Next List Item'#0'an Item'#0+
             'Middle Item'#0'Item'#0'Low Item'#0'Lowest Item'#0);

pListProc := Pointer(SetWindowLong(hListBox1, GWL_WNDPROC, Integer(@ListBFunc)));
 { Sub-Class the List Box to get the WM_DROPFILES messages, because
   DragAcceptfiles is called below}

DragAcceptfiles(hListBox1, True);
{DragAcceptfiles is called for the hListBox1, so it will get it's own
 Drag and Drop functioning, separate from the hForm1 drag and drop}

SetFocus(ActControl);
 // set focus to Exit Button, which becomes the Active Control, ActControl
end;



function MakeProgram: Boolean;
var
menuList: String;
hSubM1, hSMenu: Integer;
begin
Result := False;
// start by setting up the main form's window class with SetWinClass
if SetWinClass('MakeApp '#9'Class', @MessageFunc) = Zero then Exit;

{ these next lines of code will create the Main Form's main Menu with the
  MakeSubMenu function, the sub-menu items will be in the ItemList parameter.
  You can set item options in the ItemList with a character like #201}

{this first call to MakeSubMenu will create a "Sub Menu" for the "Main Menu One"
 the #251 is used in the ItemList parameter to tell the function to make a
 Sub Menu that is NOT placed on the main Menu.
 The ItemList MUST be #0 delimited, with a #0 at the end}
hSubM1 := MakeSubMenu(#251'Move Panel 1'#0'Move Panel 2'#0'Change Color Panel 1'#0,
                      id4menu(m_MoveP1,m_MoveP2,m_ColorP1), Zero);
if hSubM1 = Zero then
  begin
  MessageBox(Zero, 'No Sub Menu - MakeSubMenu Failure',
             'ERROR - No menu', MB_ICONERROR);
  Exit;
  end;

{this menuList string will be used as the ItemList parameter in the MakeSubMenu.
 It has the #250 as the first character to tell the function that this is a
 Sub Menu for the main Menu. The first item name "&Main Menu One" will be
 what is shown on the main Menu}
menuList := #250'&Main Menu One'#0'&Top Menu Item'#0#201'&Second Menu Item'+
            #0#203'Change Panels'#0'&Add to List Box'#0'&Change Edit'#0#200' '+
            #0'E &X I T        Alt+F4'#0;
{the #201 places a Check on the menu item, and the #200 makes a "Separator"
 menu Item, and the #203 will add the Sub Menu  -> hSubM1}

MakeSubMenu(menuList, id4menu(m_TopItem,m_Second,m_Add2ListBox,m_ChangeEdit),
            id4menu(m_Exit, Zero), hSubM1);
{when you call MakeSubMenu above, it automaticaly creates the Form's main Menu
 and creates the "Main Menu One" sub menu for the main Menu}


MakeSubMenu(#250'&Next'#0'Message Box'#0'Do Test'#0'List Box Add'#0'non'#0,
            id4menu(m_MessBox,m_Second,m_Add2ListBox,66), Zero);
{the Next menu above has 4 menu Items and will be added to the mainMenu
 because it has the #250 first character in ItemList}

menuList := #251'mMove Panel 1'#0'mMove Panel 2'#0'mChange Color Panel 1'#0;
hSubM1 := MakeSubMenu(menuList, id4menu(m_MoveP1,m_MoveP2,m_ColorP1), Zero);
// this Sub Menu will be added to the Big Menu below

menuList := #250'&Big Menu'#0'MessageBox'#0#200' '#0'Top Item'#0#202'Next Item'+
            #0#203'Sub Menu Item'#0'Some Item'#0#201'This Item'#0'That Item'+
            #0'Bottom Item'#0#200' '#0'Close Program'#0;
hSMenu := MakeSubMenu(menuList, id4menu(m_MessBox,m_Second,m_Add2ListBox,88),
                      id4menu(m_MessBox,m_Second,m_MessBox,m_Exit), hSubM1);
{the MakeSubMenu function is limited to 8 clickable Items, but you can use the
API menu functions to add more Items after you create it.
You must get the sub-menu Handle (hSMenu) to use the API menu functions below}
InsertMenu(hSMenu, 3, MF_BYPOSITION or MF_STRING, m_AddedItem, 'LOOK Added Item');

menuList := #251'Change Color Panel 1'#0'mMove Panel 2'#0'Exit'#0;
hSubM1 := MakeSubMenu(menuList, id4menu(m_ColorP1,m_MoveP2,m_Exit), Zero);
{the MakeSubMenu function can Only add ONE sub Menu Item, but more can be
placed on that sub Menu with the InsertMenu function}
InsertMenu(hSMenu, One, MF_BYPOSITION or MF_STRING or MF_POPUP,
           hSubM1, 'LOOK Added PopUp');

menuList := '';

{ when MakeForm( ) is called the menu created above will automaticaly be the
 Form's Main Menu, so you must Create the menu BEFORE you call MakeForm}
hForm1 := MakeForm(DEF, DEF, 500, 291, 'Use MakeApp',
                   WS_TILEDWINDOW or WS_CLIPCHILDREN);
if hForm1 = Zero then Exit;
Result := True;
MakeControls; // control creation procedure above
end;

initialization

finalization
DeleteObject(Font1);
DeleteObject(FontP);

end.

This should give you some ideas about using the MakeApp Unit, so you can create your own "One Size Fits All" program creation unit, that has the code and constants that you frequently use for program, control, font, or brush creation. And you can even create more units with other common code, that you may use for a certain control or purpose, like a User-Draw control.

  NOTE - If you make several "Common Code" units and include them in your project, you will see the byte size of your executable increase. A "One Size Fits All" unit will add code that may NOT be needed because you have made the code to do many things. If your purpose is to have small and highly efficient programs, you may not want to use any "One Size Fits All" units.

You can create your own units and then try to make some code that is reusable.



                           

Next in Code Container Series
The following page shows you how to make a code container unit that has graphic (non-windowed) controls
  13b. Graphic Control Creation


       

Lesson -     One  Two  Three  Four  Five  Six  Seven  Eight  Nine  Ten  Eleven  Twelve  Thirteen  Fourteen




H O M E