+----------------------------------------------------------------------+
|                      I * C * E * T * I * P * S                       |
|                                                                      |
|                        Nr 7,  April 9th 1995                         |
|                                                                      |
|                         Presented to you by                          |
|                      Arnor Baldvinsson, ICELAND                      |
|                       Phone/fax:  +354 7 41455                       |
|                      e-mail: arnorbld@centum.is                      |
+----------------------------------------------------------------------+

Have you ever wanted to connect to another Windows program with DDE, or 
just been curious to know if this or that program is running.  Here I'm 
going to present to you a CW version of Task List, you know the little 
program that pops up when you press Ctrl-Esc while in Windows.  It 
implements 3 new API functions: GetWindow, GetWindowText and 
GetWindowTextLength.  

First we must declare these functions in similar manner as we have done in 
previous IceTips.  The best way to do this is to put the following code in 
the "Global Properties, Embeds, Inside The Global Map" section in the 
program.

MODULE('WINDOWS.LIB')
  GetWindow(USHORT,USHORT),RAW,PASCAL,USHORT
  GetWindowText(USHORT,*CSTRING,SHORT),RAW,PASCAL,SHORT
  GetWindowTextLength(USHORT),RAW,PASCAL,SHORT
END

We must also use some constants to work with.  I have long since used a 
simple method here.  I have changed the PROGRAM.TPW to include a 
CONSTANT.CLW file which I store in the LIBSRC directory, along with the 
other include files which are used in every application.  These three 
lines are already in the PROGRAM.TPW.  Search for them... 


PROGRAM.TPW file
----------------
   INCLUDE('Equates.CLW')
   INCLUDE('Keycodes.CLW')
   INCLUDE('Errors.CLW')

and add this line:

   INCLUDE('Constant.CLW')

In the CONSTANT.CLW file I have some constants that I find nice to have around:

CONSTANT.CLW file
-----------------
! Message return values:
IDOK                EQUATE(1)    ! OK button pressed
IDCANCEL            EQUATE(2)    ! Cancel button pressed
IDABORT             EQUATE(3)    ! Abort button pressed
IDRETRY             EQUATE(4)    ! Retry button pressed
IDIGNORE            EQUATE(5)    ! Ignore button pressed
IDYES               EQUATE(6)    ! Yes button pressed
IDNO                EQUATE(7)    ! No button pressed

! Windows constants:
GW_HWNDFIRST        EQUATE(0)
GW_HWNDLAST         EQUATE(1)
GW_HWNDNEXT         EQUATE(2)
GW_HWNDPREV         EQUATE(3)
GW_OWNER            EQUATE(4)
GW_CHILD            EQUATE(5)

You can add any constants that you like here.  Anyway with all this done, 
we can start working on our mission.  What I will show you is how to create 
a list box/queue which will show you all the working programs that are 
active when you run the program.  Incidentally I have found a "bug" in 
CWRUN10.DLL in this process!  We will come to that error later on.

Now you can create an application or if you have one lying around you can 
modify it.  The first thing to do after you have declared the API functions 
and made the changes to the template and added the constant.clw file is to 
create the queue in your procedure.  

 1.  Press the Data button and Add a field.  
 2.  Call the field TaskListNames and select Queue as a data type and 
     press OK. 
 3.  Insert one field into the queue called TaskName and select String as 
     data type and 30 or 40 chars for length - it's not important.  
 4.  **NOTE**  Before you enter the next field you MUST be sure not to 
     enter it in the queue structure.  If you now have an empty "Edit Field 
     Properties" dialog box on your screen, press Cancel to get out to the 
     Local Data dialog box. 
 5.  Press Insert and insert C_TaskName as field name, CSTRING as data 
     type and the same number of characters +1  you entered in 3 
 6.  We're done here so press Close in the Local Data dialog box. 
 7.  Press Window to get to the Window formatter and select the LIST icon 
     in the Control toolbox.  Put it on the window and in the properties box 
     change the following:
       From:  TaskListNames
       Use: ?List1
       Scroll bars: Vertical
 8.  Press Format and Select Populate
 9.  Select the TaskName field and press Select and then OK to get to the 
     Window Formatter again.
10.  Add a button to the screen.  Here is the tricky part.  This is the 
     button you use to close the window.
11.  Right click on the button, select Action, Embeds, Control Event 
     handling after generated code, Accepted, Source.  DON'T  be tempted to 
     use the CloseCurrentWindow.  THIS is the part that will generate GPF 
     when you press the button.  Instead put RETURN in the embedded source 
     point.  This works fine!
12.  Now we are almost done.  All we have to do is put the following code into 
     the procedure "Embeds, After opening the window" embed point.  This is 
     the code that will put all the tasks into the list control in the list box
     on the screen for you to view.

!***  Get task list embed ***
!----------------------------
CurrWnd# = GetWindow(Window{PROP:handle},GW_HWNDFIRST) ! Get the current window

LOOP WHILE CurrWnd# <> 0                             ! LOOP while not 0
  Length# = GetWindowTextLength(CurrWnd#)            ! Get the caption length 
  C_TaskName = ALL(' ',Length#)                      ! space it out
  Length# = GetWindowText(CurrWnd#,C_TaskName,Length#+1)! Get the caption
                                 ! Remember always to use CSTRING varibles with
                                 ! API calls and PASCAL calling convention.
                                 ! I used C_ prefix for C string here    
  IF Length# > 0 THEN                                ! IF there is caption
    TaskName = C_TaskName                            ! Put it into TaskName
    ADD(TaskListNames)                               ! Add it to the TaskList
  END                                                ! END IF Length# > 0
  CurrWnd# = GetWindow(CurrWnd#,GW_HWNDNEXT)         ! Get the next window
END                                                  ! END LOOP WHILE 

I think that's it!  Try it out, but PLEASE SAVE YOUR WORK before running the 
application.  When messing with API calls it's better to be safe than sorry!

If you find errors or you have problems, please let me know

Re-distribution of this file:  If you run a BBS and you think this is of 
interest, you are welcome to put this on the board as long as you keep 
the "header" with it.  You are also welcome to translate this file to 
other languages and add your comments after this text.  

***** COMING UP NEXT on ICETIPS:  *****

More API calls, perhaps something on how to work with MS communication VBX, not 
sure but stay tuned to CW-TALK...

Arnor Baldvinsson
ICELAND

