Jump to content

Samuel's OS/2 Programming Tricks: Difference between revisions

From EDM2
 
(9 intermediate revisions by 2 users not shown)
Line 1: Line 1:
By [[Samuel Audet]]
''By [[Samuel Audet]]''


Last Modified: March 1, 2005
Last Modified: March 1, 2005


 
==Autodetecting installed CD-ROM drive letters==
==== Autodetecting installed CD-ROM drive letters ====
There is a way to autodetect the CD-ROM drive letter through undocumented ioctls, even though I heard they may have come from the DDK.
 
<pre>
 
HFILE CDDevice;
There is a way to autodetect the CD-ROM drive letter through undocumented
ioctls, eventhough I heard they may have come from the DDK.
 
<pre>HFILE CDDevice;
ULONG action;
ULONG action;
ULONG len;
ULONG len;
Line 20: Line 16:


len = sizeof(CDInfo);
len = sizeof(CDInfo);
if(!DosOpen("\\DEV\\CD-ROM2$", &amp;CDDevice, &amp;action, 0,
if(!DosOpen("\\DEV\\CD-ROM2$", &CDDevice, &action, 0,
             FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS,
             FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS,
             OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY, NULL))
             OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY, NULL))
{
{
   if(!DosDevIOCtl(CDDevice, 0x82, 0x60, NULL, 0, NULL, &amp;CDInfo, len, &amp;len))
   if(!DosDevIOCtl(CDDevice, 0x82, 0x60, NULL, 0, NULL, &CDInfo, len, &len))
   {
   {
       for(i = 0; i &lt; CDInfo.CountCD; i++)
       for(i = 0; i < CDInfo.CountCD; i++)
       {
       {
         char driveLetter[3] = { (char) ('A' + CDInfo.FirstCD + i), ':', 0};
         char driveLetter[3] = { (char) ('A' + CDInfo.FirstCD + i), ':', 0};
Line 35: Line 31:
}
}
</pre>
</pre>
==== Making a program find its own directory ====


==Making a program find its own directory==
This's one is a bit tricky, but it's pretty obvious once you know how.
This's one is a bit tricky, but it's pretty obvious once you know how.
 
<pre>
<pre>ULONG PathLength;
ULONG PathLength;
char *Path;
char *Path;


/* query max path length */
/* query max path length */


if (!DosQuerySysInfo(QSV_MAX_PATH_LENGTH, QSV_MAX_PATH_LENGTH, &amp;PathLength, sizeof(ULONG)))
if (!DosQuerySysInfo(QSV_MAX_PATH_LENGTH, QSV_MAX_PATH_LENGTH, &PathLength, sizeof(ULONG)))
   Path = (char *) malloc(2*PathLength*sizeof(char)+1);
   Path = (char *) malloc(2*PathLength*sizeof(char)+1);


Line 55: Line 50:
   PPIT ppit;
   PPIT ppit;


   DosGetInfoBlocks(&amp;ppit, &amp;ppib);
   DosGetInfoBlocks(&ppit, &ppib);
   DosQueryModuleName(ppib->pib_hmte, 2*PathLength+1, Path);
   DosQueryModuleName(ppib->pib_hmte, 2*PathLength+1, Path);


Line 65: Line 60:
}
}
</pre>
</pre>
==== Notebook dialogs ====


==Notebook dialogs==
So, what would you like to do with Notebook dialogs?
So, what would you like to do with Notebook dialogs?
* [[Easily Load and Manage Pages]]
* [[Making Help Manager Useable]]


* [[Easily load and manage pages]]
== WinHSWITCHfromHAPP() ==
* [[Making Help Manager useable]]
This function is hidden in PMSHAPI.DLL, and you can import it in any of your programs (in the DEF file using "IMPORTS PMSHAPI.WINHSWITCHFROMHAPP" for example). The C syntax is:
 
HSWITCH APIENTRY16 WINHSWITCHFROMHAPP(HAPP happ);
==== WINHSWITCHFROMHAPP() ====
Doesn't seem useful? Guess what is the "open handle" of the VIEWITEM and VIEWFILE structure. You got it... You can then do whatever you are used to doing with an HSWITCH.


This function is hidden in PMSHAPI.DLL, and you can import it in any of
And you can do some pretty amazing things with this and [[WinStartApp]]().
your programs (in the DEF file using "IMPORTS PMSHAPI.WINHSWITCHFROMHAPP"
Makes me wonder what WinStartApp() ''really'' does, as [[DosStartSession]]() doesn't do half of what you can find with those.
for example). The C syntax is:
 
<pre>HSWITCH APIENTRY16 WINHSWITCHFROMHAPP(HAPP happ);
</pre>
 
Doesn't seem useful? Guess what is the "open handle" of the VIEWITEM and
VIEWFILE structure. You got it... You can then do whatever you are used
to do with an HSWITCH.
 
 
And you can do some pretty amazing things with this and WinStartApp().
Makes me wonder what WinStartApp() ''really'' does, as DosStartSession()
doesn't do half of what you can find with those.
 
 
Note however that for WPS windows, "open handle" is a window handle,
so try to use it as a window handle, if it fails, use WINHSWITCHFROMHAPP().


Note however that for WPS windows, "open handle" is a window handle, so try to use it as a window handle, if it fails, use WINHSWITCHFROMHAPP().


Thanks to [[Uri Joseph Stern]] for this one, I needed it dearly.
Thanks to [[Uri Joseph Stern]] for this one, I needed it dearly.


 
==Checking the class of a window handle==
==== Checking the class of a window handle ====
 
Ok, here's the trick:
Ok, here's the trick:


 
(example, if you want to know if hwnd is a scroll bar)
(example if you want to know if hwnd is a scroll bar)
<pre>
 
CHAR achClass[256]
 
<pre>CHAR achClass[256]


WinQueryClassName(hwnd,sizeof(achClass),achClass);
WinQueryClassName(hwnd,sizeof(achClass),achClass);
Line 116: Line 92:
   /* this is not a scroll bar */;
   /* this is not a scroll bar */;
</pre>
</pre>
Thanks to [[Larry Salomon Jr.]] in EDM/2 and to [[Robert Mahoney]] for letting me know about it.
==Masking File Names in Strings==
[http://www.step.polymtl.ca/~guardia/archives/fnmatch.zip fnmatch.zip] - 5 kB


Thanks to Larry Salomon, Jr. in [[EDM/2]]
This is a wildcard string matcher that I "ported" from EMX to VisualAge C++ (although source codes are included). I have replaced EMX functions with VAC++ equivalents, and I have stripped out DBCS support, since, euh, I didn't know how to support it in VAC++.
and to [[Robert Mahoney]] for letting
me know about it.
   
{| border="1"
|-
!Masking File Names in Strings
| [[fnmatch.zip]]
5 kB


|}
The advantage of this routine over Dos*() API filename wildcard matcher is that you don't need an actual file to match a wildcard, you only need two strings. This can be very useful in many situations.
This is a wildcard string matcher that I "ported" from EMX to VisualAge
C++ (although source codes are included). I have replaced EMX functions
with VAC++ equivalents, and I have stripped out DBCS support, since, euh,
I didn't know how to support it in VAC++.


==Hooks and the Workplace Shell==
If you plan on using hooks from the Workplace Shell, make sure you make one DLL for the WPS Class and another DLL for the hook. I learned the hard way that a hook from a WPS DLL just doesn't work right (God knows why).


The advantage of this routine over Dos*() API filename wildcard matcher
==Leaving Hooks loaded after program execution==
is that you don't need an actual file to match a wildcard, you only need
two strings. This can be very useful in many situations.
 
 
==== Hooks and the Workplace Shell ====
 
If you plan on using hooks from the Workplace Shell, make sure you make
one DLL for the WPS Class and another DLL for the hook. I learned the hard
way that a hook from a WPS DLL just doesn't work right (God knows why).
 
==== Leaving Hooks loaded after program execution ====
 
You can leave a hook loaded any time after a program has finished executing.
You can leave a hook loaded any time after a program has finished executing.
In theory, you would only need not to execute WinReleaseHook(), but it
In theory, you would only need not execute WinReleaseHook(), but it seems WinSetHook() executes asynchronously from the calling program. There must be a better way to know when the hook is loaded, but here's how I do it (this requires a shared memory segment or a single stack DLL):
seems WinSetHook() executes asynchronously from the calling program. There
must be a better way to know when the hook is loaded, but here's how I
do it (this requires a shared memory segment or a single stack DLL):
 


In the Hook DLL, I have this code:
In the Hook DLL, I have this code:
 
<pre>
 
BOOL loaded = FALSE;
<pre>BOOL loaded = FALSE;


BOOL EXPENTRY WinHookProc(HAB hab,PQMSG pqmsg, USHORT usRemove)
BOOL EXPENTRY WinHookProc(HAB hab,PQMSG pqmsg, USHORT usRemove)
Line 171: Line 124:
}
}
</pre>
</pre>
In the hook loader, I call WaitLoaded() before returning from the main() function. Note that this only seems to work for VIO executables... :( An example of this is in [http://www.step.polymtl.ca/~guardia/archives/numcomma.zip numcomma.zip] (31 kB).


In the hook loader, I call WaitLoaded() before returning from the main()
==Scroll Bars "style"==
function. Note that this only seems to work for VIO executables... :( An
If you ever need to check if a scroll bar is horizontal or vertical, check with SBS_VERT first (or only) since SBS_HORZ is actually set to 0 in PMWIN.H, which will always make an if statement fail. i.e.:
example of this is in [[numcomma.zip]]
<pre>
(31 kB).
if(WinQueryWindowULong(hwndscroll,QWL_STYLE) & SBS_VERT)
 
==== Scroll Bars "style" ====
 
If you ever need to check if a scroll bar is horizontal or vertical, check
with SBS_VERT first (or only) since SBS_HORZ is actually set to 0 in PMWIN.H,
which will always make an if statement fail. ie.:
 
<pre>if(WinQueryWindowULong(hwndscroll,QWL_STYLE) &amp; SBS_VERT)
   /* this is a vertical scroll bar */;
   /* this is a vertical scroll bar */;
else
else
   /* this is an horizontal scroll bar */;
   /* this is a horizontal scroll bar */;
</pre>
</pre>
and NOT
and NOT
 
<pre>
<pre>if(WinQueryWindowULong(hwndscroll,QWL_STYLE) &amp; SBS_HORZ)
if(WinQueryWindowULong(hwndscroll,QWL_STYLE) & SBS_HORZ)
   /* this is an horizontal scroll bar */;
   /* this is a horizontal scroll bar */;
else
else
   /* this is a vertical scroll bar */;
   /* this is a vertical scroll bar */;

Latest revision as of 15:25, 18 May 2025

By Samuel Audet

Last Modified: March 1, 2005

Autodetecting installed CD-ROM drive letters

There is a way to autodetect the CD-ROM drive letter through undocumented ioctls, even though I heard they may have come from the DDK.

HFILE CDDevice;
ULONG action;
ULONG len;
struct
{
    USHORT CountCD;
    USHORT FirstCD;
} CDInfo;

len = sizeof(CDInfo);
if(!DosOpen("\\DEV\\CD-ROM2$", &CDDevice, &action, 0,
            FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS,
            OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY, NULL))
{
   if(!DosDevIOCtl(CDDevice, 0x82, 0x60, NULL, 0, NULL, &CDInfo, len, &len))
   {
      for(i = 0; i < CDInfo.CountCD; i++)
      {
         char driveLetter[3] = { (char) ('A' + CDInfo.FirstCD + i), ':', 0};
         /* got one drive letter in driveLetter, use it */
      }
   }
   DosClose(CDDevice);
}

Making a program find its own directory

This's one is a bit tricky, but it's pretty obvious once you know how.

ULONG PathLength;
char *Path;

/* query max path length */

if (!DosQuerySysInfo(QSV_MAX_PATH_LENGTH, QSV_MAX_PATH_LENGTH, &PathLength, sizeof(ULONG)))
   Path = (char *) malloc(2*PathLength*sizeof(char)+1);

/* multiplied by 2 to include the filename length too */

if(Path)
{
   PPIB ppib;
   PPIT ppit;

   DosGetInfoBlocks(&ppit, &ppib);
   DosQueryModuleName(ppib->pib_hmte, 2*PathLength+1, Path);

   *(strrchr(Path,'\\')) = 0;

   Path = (char *)realloc(Path, (strlen(Path)+1)*sizeof(char));

   /* got the path in Path, use it */
}

Notebook dialogs

So, what would you like to do with Notebook dialogs?

WinHSWITCHfromHAPP()

This function is hidden in PMSHAPI.DLL, and you can import it in any of your programs (in the DEF file using "IMPORTS PMSHAPI.WINHSWITCHFROMHAPP" for example). The C syntax is:

HSWITCH APIENTRY16 WINHSWITCHFROMHAPP(HAPP happ);

Doesn't seem useful? Guess what is the "open handle" of the VIEWITEM and VIEWFILE structure. You got it... You can then do whatever you are used to doing with an HSWITCH.

And you can do some pretty amazing things with this and WinStartApp(). Makes me wonder what WinStartApp() really does, as DosStartSession() doesn't do half of what you can find with those.

Note however that for WPS windows, "open handle" is a window handle, so try to use it as a window handle, if it fails, use WINHSWITCHFROMHAPP().

Thanks to Uri Joseph Stern for this one, I needed it dearly.

Checking the class of a window handle

Ok, here's the trick:

(example, if you want to know if hwnd is a scroll bar)

CHAR achClass[256]

WinQueryClassName(hwnd,sizeof(achClass),achClass);
if(WinFindAtom(WinQuerySystemAtomTable(),achClass)
   == LOUSHORT(WC_SCROLLBAR))
   /* this is a scroll bar */;
else
   /* this is not a scroll bar */;

Thanks to Larry Salomon Jr. in EDM/2 and to Robert Mahoney for letting me know about it.

Masking File Names in Strings

fnmatch.zip - 5 kB

This is a wildcard string matcher that I "ported" from EMX to VisualAge C++ (although source codes are included). I have replaced EMX functions with VAC++ equivalents, and I have stripped out DBCS support, since, euh, I didn't know how to support it in VAC++.

The advantage of this routine over Dos*() API filename wildcard matcher is that you don't need an actual file to match a wildcard, you only need two strings. This can be very useful in many situations.

Hooks and the Workplace Shell

If you plan on using hooks from the Workplace Shell, make sure you make one DLL for the WPS Class and another DLL for the hook. I learned the hard way that a hook from a WPS DLL just doesn't work right (God knows why).

Leaving Hooks loaded after program execution

You can leave a hook loaded any time after a program has finished executing. In theory, you would only need not execute WinReleaseHook(), but it seems WinSetHook() executes asynchronously from the calling program. There must be a better way to know when the hook is loaded, but here's how I do it (this requires a shared memory segment or a single stack DLL):

In the Hook DLL, I have this code:

BOOL loaded = FALSE;

BOOL EXPENTRY WinHookProc(HAB hab,PQMSG pqmsg, USHORT usRemove)
{
   loaded = TRUE;
   ...
}

BOOL EXPENTRY WaitLoaded(void)
{
   while(!loaded) DosSleep(10);
   return TRUE;
}

In the hook loader, I call WaitLoaded() before returning from the main() function. Note that this only seems to work for VIO executables... :( An example of this is in numcomma.zip (31 kB).

Scroll Bars "style"

If you ever need to check if a scroll bar is horizontal or vertical, check with SBS_VERT first (or only) since SBS_HORZ is actually set to 0 in PMWIN.H, which will always make an if statement fail. i.e.:

if(WinQueryWindowULong(hwndscroll,QWL_STYLE) & SBS_VERT)
   /* this is a vertical scroll bar */;
else
   /* this is a horizontal scroll bar */;

and NOT

if(WinQueryWindowULong(hwndscroll,QWL_STYLE) & SBS_HORZ)
   /* this is a horizontal scroll bar */;
else
   /* this is a vertical scroll bar */;