Jump to content

Introduction to PM Programming - Apr 1994: Difference between revisions

From EDM2
mNo edit summary
Ak120 (talk | contribs)
mNo edit summary
 
(3 intermediate revisions by 2 users not shown)
Line 1: Line 1:
Written by [[Larry Salomon Jr.]]
''Written by [[Larry Salomon Jr.]]''


<h2>Introduction</h2>
==Introduction==
The purpose of this column is to provide the readers out there who are not familiar with PM application development the information necessary to satisfy their curiosity, educate themselves, and give them an advantage over the documentation supplied by IBM. Of course, much of this stuff could probably be found in one of the many books out there, but the problem
with books in general is that they don't answer the questions you have after you read the book the first time through.


<p>The purpose of this column is to provide the readers out there who are not
I will gladly entertain feedback from the readers about what was "glossed over" or what was detailed well, what tangential topics need to be covered and what superfluous crap should have been removed. This feedback is essential in guaranteeing that you get what you pay for. :)
familiar with PM application development the information necessary to
satisfy their curiousity, educate themselves, and give them an advantage
over the documentation supplied by IBM. Of course, much of this stuff
could probably be found in one of the many books out there, but the problem
with books in general is that they don't answer the questions you have
after you read the book the first time through.


<p>I will gladly entertain feedback from the readers about what was "glossed
It should be said that you must not depend solely on this column to teach you how to develop PM applications; instead, this should be viewed as a supplement to your other information storehouses (books, the network conferences, etc.). Because this column must take a general approach, there will be some topics that you would like to see discussed that really do not belong hereSpecific questions can be directed to the Scratch Patch, where an attempt to answer them will be made.
over" or what was detailed well, what tangential topics need to be covered
and what superfluous crap should have been removedThis feedback is
essential in guaranteeing that you get what you pay for. :)


<p>It should be said that you must not depend solely on this column to teach
==Last Month==
you how to develop PM applications; instead, this should be viewed as a
Last month, we began looking at dialog boxes and their components. This month, we'll continue by delving into the source code to HELLO which was presented last monthWe'll examine the messages in our dialog procedure, and will begin looking at how controls are used within dialogs.
supplement to your other information storehouses (books, the network
conferences, etc.).  Because this column must take a general approach,
there will be some topics that you would like to see discussed that really
do not belong hereSpecific questions can be directed to the Scratch
Patch, where an attempt to answer them will be made.


<p>
===nameDlgProc()===
<h2>Last Month</h2>
Below is the dialog procedure from HELLO.C condensed a bit:
 
<p>Last month, we began looking at dialog boxes and their components.  This
month, we'll continue by delving into the source code to HELLO which was
presented last month.  We'll examine the messages in our dialog procedure,
and will begin looking at how controls are used within dialogs.
 
<p>
<h3>nameDlgProc()</h3>
 
<p>Below is the dialog procedure from HELLO.C condensed a bit:
<pre>
<pre>
MRESULT EXPENTRY nameDlgProc(HWND hwndWnd,
MRESULT EXPENTRY nameDlgProc(HWND hwndWnd,
Line 59: Line 37:
}
}
</pre>
</pre>
We looked at the WM_INITDLG message last issue; let's take a look at the other two.


We looked at the WM_INITDLG message last issue; let's take a look at the
====WM_COMMAND====
other two.
This message occurs when a command is to be performed, or when a key combination is translated to a WM_COMMAND accelerator message.
 
;Parameters:param1
<p><h4>WM_COMMAND</h4>
::usId (USHORT)
 
::Identifier of the command or accelerator key.
This message occurs when a command is to be performed, or when a key
::usSource (USHORT)
combination is translated to a WM_COMMAND accelerator message.
::A '''CMDSRC_*''' constant describing the source of the message
 
:param2
<p><h4>Parameters</h4>
::bPointer (BOOL)
<blockquote>
::Pointer indicator
<b>param1</b>
::'''TRUE''' The message is the result of a pointer action.
<blockquote>
::'''FALSE''' The message is the result of a keyboard action.
usId (USHORT)
;Returns:reply
<blockquote>
::ulReserved (BIT32)
Identifier of the command or accelerator key.
::Reserved, and must be zero.
</blockquote><br>
usSource (USHORT)
<blockquote>
 
A <b>CMDSRC_*</b> constant describing the source of the message
</blockquote></blockquote><br>
<b>param2</b>
<blockquote>
bPointer (BOOL)
<blockquote>
Pointer indicator


<p><b>TRUE</b>  The message is the result of a pointer action.<br>
====WM_CONTROL====
<b>FALSE</b>  The message is the result of a keyboard action.
This message occurs when a control has a significant event to report to its owner.


</blockquote></blockquote></blockquote>
;Parameters
:'''param1'''
:usId (USHORT)
:Identifier of the control sending the notification.
:usNotify (USHORT)
:The notification code.  This is specific to the window class of the control.
:'''param2'''
:pvData (PVOID)
:Control data.  This is specific to the notification code being sent.


<p><h4>Returns</h4>
;Returns
<blockquote>
:'''reply'''
<b>reply</b>
:ulReserved (BIT32)
<blockquote>
:Reserved, and must be zero.
ulReserved (BIT32)
<blockquote>
Reserved, and must be zero.
</blockquote></blockquote></blockquote>


<p><h4>WM_CONTROL</h4>
Okay, "big deal," you say.  Just add two more entries to your list of messages that you now know about?  Well, these messages are a bit more important than that...


This message occurs when a control has a significant event to report to its
===The WM_COMMAND Message===
owner.
The WM_COMMAND message is important because it is the focal point through which your application will get notified that something needs to get done. Among other things...
 
*menu items send this message when they are selected
 
*pushbuttons send this message when they are selected
<p><h4>Parameters</h4>
*the frame window sends this message whenever the user presses a key combination that is defined in the accelerator table
<blockquote>
*dialogs automatically receive this whenever Enter or Escape are pressed.
<b>param1</b>
It doesn't look like much, but as you travel the PM developer's journey, you'll find that this message is frequently sent. It becomes your central interface to the user, since most actions are requested by the user through menus on client windows and through pushbuttons on dialogs.
<blockquote>
usId (USHORT)
<blockquote>
Identifier of the control sending the notification.
</blockquote><br>
usNotify (USHORT)
<blockquote>
The notification code.  This is specific to the window class of the
control.
</blockquote></blockquote>
 
<p>
<b>param2</b>
 
<blockquote>
pvData (PVOID)
<blockquote>
Control data.  This is specific to the notification code being sent.
</blockquote></blockquote></blockquote>
 
<p>
<h4>Returns</h4>
<blockquote>
<b>reply</b>
<blockquote>
ulReserved (BIT32)
<blockquote>
Reserved, and must be zero.
</blockquote></blockquote></blockquote>
 
<p>
Okay, "big deal," you say.  Just add two more entries to your list of
messages that you now know about?  Well, these messages are a bit more
important than that...
 
<p>
<h4>The WM_COMMAND Message</h4>
 
The WM_COMMAND message is important because it is the focal point through
which your application will get notified that something needs to get done.
Among other things...
 
<p><ul>
<li>menu items send this message when they are selected
<li>pushbuttons send this message when they are selected
<li>the frame window sends this message whenever the user presses a key
combination that is defined in the accelerator table
<li>dialogs automatically receive this whenever Enter or Escape are pressed.
</ul>
 
<p>It doesn't look like much, but as you travel the PM developer's journey,
you'll find that this message is frequently sent. It becomes your central
interface to the user, since most actions are requested by the user through
menus on client windows and through pushbuttons on dialogs.
 
<p>Let's take a look at how this message is treated in HELLO.C.


Let's take a look at how this message is treated in HELLO.C.
<pre>
<pre>
case WM_COMMAND:
case WM_COMMAND:
Line 181: Line 98:
   break;
   break;
</pre>
</pre>
It isn't obvious in the documentation, if I remember correctly, so don't
It isn't obvious in the documentation, if I remember correctly, so don't feel ashamed if you don't understand the constants DID_OK and DID_CANCEL.
feel ashamed if you don't understand the constants DID_OK and DID_CANCEL.


<p><b>DID_OK</b>  Sent whenever the user presses Enter
<b>DID_OK</b>  Sent whenever the user presses Enter
<br><b>DID_CANCEL</b>  Sent whenever the user presses Escape
<br><b>DID_CANCEL</b>  Sent whenever the user presses Escape


<p>It is imperative that you understand that these messages are not sent by
It is imperative that you understand that these messages are not sent by pushbuttons.  Thus, even though your dialog might not have pushbuttons, it is possible to receive these messages.  (If you don't believe me, comment out the DEFPUSHBUTTON and PUSHBUTTON lines in HELLO.RC, recompile and try.)
pushbuttons.  Thus, even though your dialog might not have pushbuttons, it
is possible to receive these messages.  (If you don't believe me, comment
out the DEFPUSHBUTTON and PUSHBUTTON lines in HELLO.RC, recompile and try.)


<p><h3>Dismissal Revisited</h3>
===Dismissal Revisited===
When reading last month's column, I realized that I was talking about the dismissal of dialogs like we were all old pro's at it; if we were, I thought, this column wouldn't have a reason for existence.
BOOL WinDismissDlg(HWND hwndDlg,ULONG ulResult);


<p>When reading last month's column, I realized that I was talking about the
This function is used to dismiss a dialog.  As was mentioned last time, this does not destroy the dialog by default; it only hides the dialog. What does this have to do with the WM_COMMAND message? Well, the typical action for DID_OK and DID_CANCEL is to dismiss the dialog (for DID_OK, data is usually read from the dialog also and verified), so you can see that
dismissal of dialogs like we were all old pro's at it; if we were, I
thought, this column wouldn't have a reason for existance.
 
<p>BOOL WinDismissDlg(HWND hwndDlg,ULONG ulResult);
 
<p>This function is used to dismiss a dialog.  As was mentioned last time,
this does not destroy the dialog by default; it only hides the dialog.
What does this have to do with the WM_COMMAND message? Well, the typical
action for DID_OK and DID_CANCEL is to dismiss the dialog (for DID_OK, data
is usually read from the dialog also and verified), so you can see that
this function is used frequently.
this function is used frequently.


In the above, no data is read from the dialog. How does the program know what name to display?...


<p>In the above, no data is read from the dialog.  How does the program know
==The WM_CONTROL Message==
what name to display?...
What happens whenever an item in a listbox is selected?  Or whenever the text in an entryfield changes?  Or when a checkbox is clicked on by the user? For all of these, and many other events, the owner of the control is sent a WM_CONTROL message, meaning that something occurred that could have an effect on the behaviour of the application.
 
<p>
<h2>The WM_CONTROL Message</h2>
 
<p>What happens whenever an item in a listbox is selected?  Or whenever the
text in an entryfield changes?  Or when a checkbox is clicked on by the
user? For all of these, and many other events, the owner of the control is
sent a WM_CONTROL message, meaning that something occurred that could have
an effect on the behavior of the application.
 
<p>This is a broad message, which has a specific set of parameters based on
two criteria:


<p><ol>
This is a broad message, which has a specific set of parameters based on two criteria:
<li>the class of the control sending the message
#the class of the control sending the message
<li>the event that generate the message
#the event that generate the message
</ol><p>Thus, for the first scenario, the usNotify is LN_SELECT, and pvData is the
Thus, for the first scenario, the usNotify is LN_SELECT, and pvData is the handle of the listbox.  For the second, usNotify is EN_CHANGE and pvData is the handle of the entryfield.  And so on...
handle of the listbox.  For the second, usNotify is EN_CHANGE and pvData is
the handle of the entryfield.  And so on...
<pre>
<pre>
case WM_CONTROL:
case WM_CONTROL:
Line 264: Line 156:
   break;
   break;
</pre>
</pre>
You probably don't understand the specific functions, but you can see for
You probably don't understand the specific functions, but you can see for yourself by running the application that, whenever an item is selected in the listbox, the name selected is placed in the entryfield.
yourself by running the application that, whenever an item is selected in
the listbox, the name selected is placed in the entryfield.


<p><h3>.And the Point is...</h3>
===.And the Point is...===
The point of introducing the WM_COMMAND and WM_CONTROL messages is to demonstrate the usefulness of them.  As we begin to look at the controls, we will examine how they interact with the application through these messages; careful exploitation will (eventually) allow you to control the execution of your application.


<p>The point of introducing the WM_COMMAND and WM_CONTROL messages is to
==New Functions==
demonstrate the usefulness of them.  As we begin to look at the controls,
In addition to the WinDismissDlg() function, we will look at three additional PM APIs.
we will examine how they interact with the application through these
<pre>
messages; careful exploitation will (eventually) allow you to control the
execution of your application.
 
<p>
<h2>New Functions</h2>
 
<p>In addition to the WinDismissDlg() function, we will look at three
additional PM APIs.
<pre><small>
BOOL WinSetWindowText(HWND hwndWnd,PSZ pszText);
BOOL WinSetWindowText(HWND hwndWnd,PSZ pszText);


Line 287: Line 169:


LONG WinQueryWindowTextLength(HWND hwndWnd);
LONG WinQueryWindowTextLength(HWND hwndWnd);
</small></pre>
</pre>
<b>WinSetWindowText</b> sets the text of the specified window to the specified
<b>WinSetWindowText</b> sets the text of the specified window to the specified value. It returns a success flag.
value. It returns a success flag.
 
<p><b>WinQueryWindowText</b> queries the text of the specified window and copies up
to either the end of the text or lSzBuf characters into the buffer pointed
to by pszBuffer.  It returns the number of characters copied.
 
<p><b>WinQueryWindowTextLength</b> returns the length of the text for the specified
window.


<b>WinQueryWindowText</b> queries the text of the specified window and copies up to either the end of the text or lSzBuf characters into the buffer pointed to by pszBuffer.  It returns the number of characters copied.


<p>It is important to note that how the window text is actually used differs
<b>WinQueryWindowTextLength</b> returns the length of the text for the specified window.
from control to control.  For example, the window text of an entryfield is
what is displayed in the entryfield itself.  This is also true for a
titlebar. However, a listbox has many text entries, which cannot be
described by a single text item so it ignores the window text.  Some
controls use their window text in other ways.  A frame, for example,
notices when its window text changes and updates the titlebar's window
text, if a titlebar exists.


<p>In other words, your mileage may vary. :)
It is important to note that how the window text is actually used differs from control to control. For example, the window text of an entryfield is what is displayed in the entryfield itself. This is also true for a titlebar. However, a listbox has many text entries, which cannot be described by a single text item so it ignores the window text. Some controls use their window text in other ways. A frame, for example, notices when its window text changes and updates the titlebar's window text, if a titlebar exists.


<p>
In other words, your mileage may vary.  :)
<h2>Summary</h2>


<p>This month we introduced two very important messages - WM_COMMAND and
==Summary==
WM_CONTROL - and described their purpose in a window or dialog procedure.
This month we introduced two very important messages - WM_COMMAND and WM_CONTROL - and described their purpose in a window or dialog procedure.
We also looked at four new PM APIs and looked at window text for the first
We also looked at four new PM APIs and looked at window text for the first time since they were mentioned in volume 2, issue 1.
time since they were mentioned in volume 2, issue 1.


<p>Next month, we will continue with HELLO by begining to examine the controls
Next month, we will continue with HELLO by beginning to examine the controls within it individually.
within it individually.


[[Category: PM Articles]]
[[Category: PM Articles]]

Latest revision as of 02:15, 2 March 2018

Written by Larry Salomon Jr.

Introduction

The purpose of this column is to provide the readers out there who are not familiar with PM application development the information necessary to satisfy their curiosity, educate themselves, and give them an advantage over the documentation supplied by IBM. Of course, much of this stuff could probably be found in one of the many books out there, but the problem with books in general is that they don't answer the questions you have after you read the book the first time through.

I will gladly entertain feedback from the readers about what was "glossed over" or what was detailed well, what tangential topics need to be covered and what superfluous crap should have been removed. This feedback is essential in guaranteeing that you get what you pay for.  :)

It should be said that you must not depend solely on this column to teach you how to develop PM applications; instead, this should be viewed as a supplement to your other information storehouses (books, the network conferences, etc.). Because this column must take a general approach, there will be some topics that you would like to see discussed that really do not belong here. Specific questions can be directed to the Scratch Patch, where an attempt to answer them will be made.

Last Month

Last month, we began looking at dialog boxes and their components. This month, we'll continue by delving into the source code to HELLO which was presented last month. We'll examine the messages in our dialog procedure, and will begin looking at how controls are used within dialogs.

nameDlgProc()

Below is the dialog procedure from HELLO.C condensed a bit:

MRESULT EXPENTRY nameDlgProc(HWND hwndWnd,
                             ULONG ulMsg,
                             MPARAM mpParm1,
                             MPARAM mpParm2)
{
   switch (ulMsg) {
   case WM_INITDLG:
        :
      break;
   case WM_CONTROL:
         :
      break;
   case WM_COMMAND:
         :
      break;
   default:
      return WinDefDlgProc(hwndWnd,ulMsg,mpParm1,mpParm2);
   } /* endswitch */

   return MRFROMSHORT(FALSE);
}

We looked at the WM_INITDLG message last issue; let's take a look at the other two.

WM_COMMAND

This message occurs when a command is to be performed, or when a key combination is translated to a WM_COMMAND accelerator message.

Parameters
param1
usId (USHORT)
Identifier of the command or accelerator key.
usSource (USHORT)
A CMDSRC_* constant describing the source of the message
param2
bPointer (BOOL)
Pointer indicator
TRUE The message is the result of a pointer action.
FALSE The message is the result of a keyboard action.
Returns
reply
ulReserved (BIT32)
Reserved, and must be zero.

WM_CONTROL

This message occurs when a control has a significant event to report to its owner.

Parameters
param1
usId (USHORT)
Identifier of the control sending the notification.
usNotify (USHORT)
The notification code. This is specific to the window class of the control.
param2
pvData (PVOID)
Control data. This is specific to the notification code being sent.
Returns
reply
ulReserved (BIT32)
Reserved, and must be zero.

Okay, "big deal," you say. Just add two more entries to your list of messages that you now know about? Well, these messages are a bit more important than that...

The WM_COMMAND Message

The WM_COMMAND message is important because it is the focal point through which your application will get notified that something needs to get done. Among other things...

  • menu items send this message when they are selected
  • pushbuttons send this message when they are selected
  • the frame window sends this message whenever the user presses a key combination that is defined in the accelerator table
  • dialogs automatically receive this whenever Enter or Escape are pressed.

It doesn't look like much, but as you travel the PM developer's journey, you'll find that this message is frequently sent. It becomes your central interface to the user, since most actions are requested by the user through menus on client windows and through pushbuttons on dialogs.

Let's take a look at how this message is treated in HELLO.C.

case WM_COMMAND:
   switch (SHORT1FROMMP(mpParm1)) {
   case DID_OK:
      WinDismissDlg(hwndWnd,TRUE);
      break;
   case DID_CANCEL:
      WinDismissDlg(hwndWnd,FALSE);
      break;
   default:
      return WinDefDlgProc(hwndWnd,ulMsg,mpParm1,mpParm2);
   } /* endswitch */
   break;

It isn't obvious in the documentation, if I remember correctly, so don't feel ashamed if you don't understand the constants DID_OK and DID_CANCEL.

DID_OK Sent whenever the user presses Enter
DID_CANCEL Sent whenever the user presses Escape

It is imperative that you understand that these messages are not sent by pushbuttons. Thus, even though your dialog might not have pushbuttons, it is possible to receive these messages. (If you don't believe me, comment out the DEFPUSHBUTTON and PUSHBUTTON lines in HELLO.RC, recompile and try.)

Dismissal Revisited

When reading last month's column, I realized that I was talking about the dismissal of dialogs like we were all old pro's at it; if we were, I thought, this column wouldn't have a reason for existence.

BOOL WinDismissDlg(HWND hwndDlg,ULONG ulResult);

This function is used to dismiss a dialog. As was mentioned last time, this does not destroy the dialog by default; it only hides the dialog. What does this have to do with the WM_COMMAND message? Well, the typical action for DID_OK and DID_CANCEL is to dismiss the dialog (for DID_OK, data is usually read from the dialog also and verified), so you can see that this function is used frequently.

In the above, no data is read from the dialog. How does the program know what name to display?...

The WM_CONTROL Message

What happens whenever an item in a listbox is selected? Or whenever the text in an entryfield changes? Or when a checkbox is clicked on by the user? For all of these, and many other events, the owner of the control is sent a WM_CONTROL message, meaning that something occurred that could have an effect on the behaviour of the application.

This is a broad message, which has a specific set of parameters based on two criteria:

  1. the class of the control sending the message
  2. the event that generate the message

Thus, for the first scenario, the usNotify is LN_SELECT, and pvData is the handle of the listbox. For the second, usNotify is EN_CHANGE and pvData is the handle of the entryfield. And so on...

case WM_CONTROL:
   switch (SHORT1FROMMP(mpParm1)) {
   case DNAME_LB_NAMELIST:
      switch (SHORT2FROMMP(mpParm1)) {
      case LN_SELECT:
         {
            HWND hwndLb;
            SHORT sIndex;

            hwndLb=WinWindowFromID(hwndWnd,DNAME_LB_NAMELIST);

            sIndex=WinQueryLboxSelectedItem(hwndLb);
            WinQueryLboxItemText(hwndLb,
                                 sIndex,
                                 pndiInfo->achName,
                                 sizeof(pndiInfo->achName));

            WinSetDlgItemText(hwndWnd,
                              DNAME_EF_NAME,
                              pndiInfo->achName);
         }
         break;
      case LN_ENTER:
         WinPostMsg(hwndWnd,WM_COMMAND,MPFROMSHORT(DID_OK),0);
         break;
      default:
         return WinDefDlgProc(hwndWnd,ulMsg,mpParm1,mpParm2);
      } /* endswitch */
      break;
   default:
      return WinDefDlgProc(hwndWnd,ulMsg,mpParm1,mpParm2);
   } /* endswitch */
   break;

You probably don't understand the specific functions, but you can see for yourself by running the application that, whenever an item is selected in the listbox, the name selected is placed in the entryfield.

.And the Point is...

The point of introducing the WM_COMMAND and WM_CONTROL messages is to demonstrate the usefulness of them. As we begin to look at the controls, we will examine how they interact with the application through these messages; careful exploitation will (eventually) allow you to control the execution of your application.

New Functions

In addition to the WinDismissDlg() function, we will look at three additional PM APIs.

BOOL WinSetWindowText(HWND hwndWnd,PSZ pszText);

LONG WinQueryWindowText(HWND hwndWnd,LONG lSzBuf,PSZ pszBuffer);

LONG WinQueryWindowTextLength(HWND hwndWnd);

WinSetWindowText sets the text of the specified window to the specified value. It returns a success flag.

WinQueryWindowText queries the text of the specified window and copies up to either the end of the text or lSzBuf characters into the buffer pointed to by pszBuffer. It returns the number of characters copied.

WinQueryWindowTextLength returns the length of the text for the specified window.

It is important to note that how the window text is actually used differs from control to control. For example, the window text of an entryfield is what is displayed in the entryfield itself. This is also true for a titlebar. However, a listbox has many text entries, which cannot be described by a single text item so it ignores the window text. Some controls use their window text in other ways. A frame, for example, notices when its window text changes and updates the titlebar's window text, if a titlebar exists.

In other words, your mileage may vary.  :)

Summary

This month we introduced two very important messages - WM_COMMAND and WM_CONTROL - and described their purpose in a window or dialog procedure. We also looked at four new PM APIs and looked at window text for the first time since they were mentioned in volume 2, issue 1.

Next month, we will continue with HELLO by beginning to examine the controls within it individually.