//
// TAPSERVER.C
//
// TAP
// File Transfer Data Sharing
// Server Code
// Revision 1.10
//
// 12/28/94 First Created
//
#define INCL_WIN
#define INCL_DOS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <process.h>
#include <os2.h>
#include "tapserve.h"
#include "tapres.h"
//
// PTAPSERVERINFO InitializeServer_TAP(char szVersion[]);
//
// Initializes the TAP Server
//
// Parameters:
// szVersion
// Server version string, max. 30 characters.
//
// Returns: Pointer to server instance data, or NULL
// on failure.
//
PTAPSERVERINFO InitializeServer_TAP(char szVersion[])
{
PTAPSERVERINFO pTapServerInfo = NULL;
// Create pTapServerInfo
pTapServerInfo = malloc(sizeof(TAPSERVERINFO));
// Did we get back a valid pointer?
if (pTapServerInfo)
{
// Initialize pTapServerInfo
pTapServerInfo -> cb = sizeof(TAPSERVERINFO);
pTapServerInfo -> phWritePipe = NULL;
pTapServerInfo -> lNumPipes = 0;
pTapServerInfo -> lShutdown = FALSE;
pTapServerInfo -> lFileOpen = FALSE;
// Create unowned mutual exclusion semaphore for
// controlling access to the TAP server
DosCreateMutexSem(NULL,
&(pTapServerInfo -> hServerMutex),
0L,
FALSE);
// Initialize version string
strncpy(pTapServerInfo -> szVersion,
TAP_SERVER_VERSION,
sizeof (pTapServerInfo->szVersion) - 1);
// NUL terminate (note that strncpy will not NUL terminate when max len is reached)
pTapServerInfo -> szVersion[sizeof (pTapServerInfo->szVersion) - 1] = '\0';
// Initialize pTapServerInfo -> tiTapInfo (Pipe packet)
pTapServerInfo -> tiTapInfo . szFileName [0] = 0;
pTapServerInfo -> tiTapInfo . lCurrentFileSize = TAP_SIZE_UNKNOWN;
pTapServerInfo -> tiTapInfo . lCompleteFileSize = TAP_SIZE_UNKNOWN;
pTapServerInfo -> tiTapInfo . ulFlags = 0;
// Create pipe update semaphore in set mode
DosCreateEventSem(NULL,
&(pTapServerInfo -> hevUpdate),
0L,
FALSE);
// Start server thread
#ifdef __BORLANDC__
pTapServerInfo -> tidTAPServer = (TID)
_beginthread(ServerThread_TAP, 8192, (void *) pTapServerInfo);
#else
pTapServerInfo -> tidTAPServer = (TID)
_beginthread(ServerThread_TAP, NULL, 8192, (void *) pTapServerInfo);
#endif
}
szVersion = szVersion;
return pTapServerInfo;
}
//
// int DeInitializeServer_TAP(PTAPSERVERINFO pTapServerInfo);
//
// DeInitializes the TAP Server
//
// Parameters:
// pTapServerInfo
// Pointer to the TAP Server instance data.
//
// Returns: TRUE on success.
//
int DeInitializeServer_TAP(PTAPSERVERINFO pTapServerInfo)
{
int iRet = TRUE;
// Request exclusive access to the server
DosRequestMutexSem(pTapServerInfo -> hServerMutex,
(ULONG)SEM_INDEFINITE_WAIT);
// Tell server thread to shutdown,
// it will take care of freeing memory
pTapServerInfo -> lShutdown = TRUE;
iRet = !DosPostEventSem(pTapServerInfo -> hevUpdate);
// Release exclusive access to the server
DosReleaseMutexSem(pTapServerInfo -> hServerMutex);
return iRet;
}
//
// int StartApplication_TAP(PTAPSERVERINFO pTapServerInfo,
// char *szAppPath,
// char *szAppParams,
// char *szAppTitle)
//
// Starts a TAP Application and sets up the TAP Server
// to service the application.
//
// Parameters:
// pTapServerInfo
// Pointer to the TAP Server instance data.
// szAppPath
// Fully qualified application executable specification.
// szAppParams
// Command line parameters sent to the application.
// szAppTitle
// Default TAP Application title (for VIO titlebar).
//
// Returns: TRUE on success
//
int StartApplication_TAP(PTAPSERVERINFO pTapServerInfo,
char *szAppPath,
char *szAppParams,
char *szAppTitle)
{
int iRet = TRUE;
char *szParameters;
PROGDETAILS Details;
PTIB ptib;
PPIB ppib;
char szPipeName[CCHMAXPATH];
// Request exclusive access to the server
DosRequestMutexSem(pTapServerInfo -> hServerMutex,
(ULONG)SEM_INDEFINITE_WAIT);
// Allocate memory for a new pipe
pTapServerInfo -> lNumPipes ++;
if (pTapServerInfo -> phWritePipe)
pTapServerInfo -> phWritePipe = (HFILE *)
realloc(pTapServerInfo -> phWritePipe,
(size_t)(pTapServerInfo -> lNumPipes * sizeof(HFILE)));
else
pTapServerInfo -> phWritePipe = (HFILE *)
malloc((size_t)(pTapServerInfo -> lNumPipes * sizeof(HFILE)));
// Query our environment
// so we can create a unique
// pipe name!
DosGetInfoBlocks(&ptib, &ppib);
// Create pipe name
sprintf(szPipeName,
"\\PIPE\\TapPipe%d_%d_%d",
ppib -> pib_ulpid,
ptib -> tib_ptib2 -> tib2_ultid,
pTapServerInfo -> lNumPipes);
// Create a new named pipe
DosCreateNPipe(szPipeName,
&(pTapServerInfo -> phWritePipe[ pTapServerInfo -> lNumPipes - 1]),
NP_NOWRITEBEHIND |
NP_INHERIT |
NP_ACCESS_DUPLEX,
NP_NOWAIT |
NP_TYPE_BYTE |
1,
1024,
8192,
0);
// Allow a client to connect
DosConnectNPipe(pTapServerInfo -> phWritePipe [ pTapServerInfo -> lNumPipes - 1]);
// Release exclusive access to the server
DosReleaseMutexSem(pTapServerInfo -> hServerMutex);
// ***
// Setup for application launch
// ***
// Query our environment
// to pass on to the shell
DosGetInfoBlocks(&ptib, &ppib);
// Setup calling data structure
memset (&Details, 0, sizeof(PROGDETAILS));
Details.Length = sizeof(PROGDETAILS);
Details.progt.progc = PROG_DEFAULT;
Details.progt.fbVisible = SHE_VISIBLE;
Details.pszTitle = szAppTitle;
Details.pszExecutable = szAppPath;
Details.pszEnvironment = ppib->pib_pchenv;
Details.swpInitial.fl = SWP_ACTIVATE; /* window positioning */
Details.swpInitial.hwndInsertBehind = HWND_TOP;
// Add our parameter to the end of the parameter list
szParameters = (char *) malloc(strlen(szAppParams) + 100);
sprintf(szParameters, "%s /TAP=%s", szAppParams, szPipeName);
// Start application
if (!WinStartApp(NULLHANDLE,
&Details,
szParameters,
NULL,
SAF_STARTCHILDAPP))
iRet=FALSE;
// Free up parameter list
free((void *) szParameters);
// Wait for client to connect
{ ULONG ulMaxRetries = 50; // Wait no longer than 5 seconds!
for (;;) {
AVAILDATA availData;
ULONG ulDummy;
ULONG ulState;
DosPeekNPipe (pTapServerInfo -> phWritePipe [ pTapServerInfo -> lNumPipes - 1],
&ulDummy, 0, &ulDummy, &availData, &ulState);
if (ulState == NP_CONNECTED)
break;
if (ulMaxRetries-- == 0)
return (-1);
DosSleep (100);
}
}
// Request exclusive access to the server
DosRequestMutexSem(pTapServerInfo -> hServerMutex,
(ULONG)SEM_INDEFINITE_WAIT);
// Write server version
{ PTAPPACKET pTapPacket;
ULONG ulBytesWritten;
USHORT usVersionLength = (USHORT)strlen (pTapServerInfo->szVersion);
USHORT usPacketLength = (USHORT)(sizeof (pTapPacket->versionPacket) + usVersionLength);
pTapPacket = malloc (usPacketLength);
pTapPacket->versionPacket.cb = usPacketLength;
pTapPacket->versionPacket.usFlags = TAP_VERSION;
pTapPacket->versionPacket.usVersionLength = usVersionLength;
strcpy (pTapPacket->versionPacket.szVersion, pTapServerInfo->szVersion);
DosWrite (pTapServerInfo -> phWritePipe [ pTapServerInfo -> lNumPipes - 1],
pTapPacket, pTapPacket->versionPacket.cb, &ulBytesWritten);
free (pTapPacket);
}
// If a file is currently open we need to send the new pipe a BOF !
if (pTapServerInfo->lFileOpen) {
PTAPPACKET pTapPacket;
ULONG ulBytesWritten;
USHORT usFileNameLength = (USHORT)strlen (pTapServerInfo->tiTapInfo.szFileName);
USHORT usPacketLength = (USHORT)(sizeof (pTapPacket->beginFilePacket) + usFileNameLength);
pTapPacket = malloc (usPacketLength);
pTapPacket->beginFilePacket.cb = usPacketLength;
pTapPacket->beginFilePacket.usFlags = TAP_BOF;
pTapPacket->beginFilePacket.lCurrentFileSize = pTapServerInfo->tiTapInfo.lCurrentFileSize;
pTapPacket->beginFilePacket.lCompleteFileSize = pTapServerInfo->tiTapInfo.lCompleteFileSize;
pTapPacket->beginFilePacket.usFileNameLength = usFileNameLength;
strcpy (pTapPacket->beginFilePacket.szFileName, pTapServerInfo->tiTapInfo.szFileName);
DosWrite (pTapServerInfo -> phWritePipe [ pTapServerInfo -> lNumPipes - 1],
pTapPacket, pTapPacket->beginFilePacket.cb, &ulBytesWritten);
free (pTapPacket);
}
// Release exclusive access to the server
DosReleaseMutexSem(pTapServerInfo -> hServerMutex);
return iRet;
}
//
// int SelectApplication_TAP(PTAPSERVERINFO pTapServerInfo,
// HWND hWndParent,
// HWND hWndOwner,
// HMODULE hmod);
//
// Allows the user to select from a list of installed
// TAP applications and launches that TAP application.
//
// In order for this function to work you must add the
// resource file TAPSERVE.RC to your resources. To locate
// these resources you must pass the module handle or
// NULLHANDLE if the resources should be loaded from the
// application's EXE.
//
// Alternatively you can launch TAP applications directly
// by calling StartApplication_TAP.
//
// Parameters:
// pTapServerInfo
// Pointer to the TAP Server instance data.
// hWndParent
// Handle to the parent window of the dialog.
// hWndOwner
// Handle to the owner window of the dialog.
// hmod
// Handle to the module that contains the application's
// resources, or NULLHANDLE if resources come from the
// application's EXE.
//
// Returns: TRUE on success.
//
int SelectApplication_TAP(PTAPSERVERINFO pTapServerInfo,
HWND hWndParent,
HWND hWndOwner,
HMODULE hmod)
{
int iRet = TRUE;
// Bring up the application selection dialog
if (WinDlgBox(hWndParent,
hWndOwner,
SelectApplicationDlgProc,
hmod,
DLG_SELECT_TAP,
pTapServerInfo )
== DID_ERROR )
iRet = FALSE;
return iRet;
}
//
// int GetApplications_TAP(char *szApplications, PULONG pulSize);
//
// Gets a list of registered TAP Applications and/or size
// of the list of TAP Applications. The list of TAP applications
// is returned as a buffer of null-terminated ASCII strings,
// the final ASCII string double null-terminated.
//
// For Example: String1\0String2\0FinalString\0\0
//
// Parameters:
// szApplications
// Pointer to a buffer where the application list will
// be stored. If this is NULL, only the application list
// size will be put in pulSize. (Output)
// pulSize
// Size of the szApplications buffer in bytes. (Input)
// Size of the application list, in bytes. (Output)
//
// Returns: TRUE on success.
//
int GetApplications_TAP(char *szApplications, PULONG pulSize)
{
int iRet = TRUE;
// If we have a pointer, get the data
if (szApplications)
if (!PrfQueryProfileString(HINI_SYSTEMPROFILE,
TAP_INI_APPNAME,
NULL,
"\0\0",
szApplications,
*pulSize))
iRet = FALSE;
// And always return how much data we query in pulSize
if (!PrfQueryProfileSize(HINI_SYSTEMPROFILE,
TAP_INI_APPNAME,
NULL,
pulSize))
iRet = FALSE;
return iRet;
}
//
// int GetApplicationInfo_TAP(char *szAppName,
// PTAPAPPENTRY pTapAppInfo);
//
// Given a TAP Application name (retrieved with
// GetApplications_TAP) returns a structure containing
// information about that TAP Application. For more
// information, the structure is located in TAP.H.
//
// Parameters:
// szAppName
// Name of the TAP Application.
// pTapAppInfo
// Pointer to a TapAppInfo structure. (Output)
//
// Returns: TRUE on success.
//
int GetApplicationInfo_TAP(char *szAppName,
PTAPAPPENTRY pTapAppInfo)
{
int iRet = TRUE;
ULONG DataLength;
// Setup length of our data structure
DataLength = sizeof(TAPAPPENTRY);
// Query application information
if (!PrfQueryProfileData(HINI_SYSTEMPROFILE,
TAP_INI_APPNAME,
szAppName,
pTapAppInfo,
&DataLength))
iRet = FALSE;
return iRet;
}
//
// int SetFileName_TAP(PTAPSERVERINFO pTapServerInfo,
// char *szFileName);
//
// Sets the name of the current TAP file.
//
// This filename must include path information (either
// relative or fully qualified). That is, "TAP\TAPSAMP.EXE"
// is an acceptable path. This function will automatically
// fully qualify a relative path.
//
// Parameters:
// pTapServerInfo
// Pointer to the TAP Server instance data.
// szFileName
// Relative or fully qualified file specification.
//
// Returns: TRUE on success.
//
int SetFileName_TAP(PTAPSERVERINFO pTapServerInfo,
char *szFileName)
{
int iRet = TRUE;
// Request exclusive access to the server
DosRequestMutexSem(pTapServerInfo -> hServerMutex,
(ULONG)SEM_INDEFINITE_WAIT);
// Create a fully qualified file name and put
// it into the pipe packet
DosQueryPathInfo(szFileName,
FIL_QUERYFULLNAME,
pTapServerInfo -> tiTapInfo . szFileName,
CCHMAXPATH);
// Set flag indicating we started a new file
pTapServerInfo -> lFileOpen = TRUE;
pTapServerInfo -> tiTapInfo.ulFlags |= TAP_BOF;
// Release exclusive access to the server
DosReleaseMutexSem(pTapServerInfo -> hServerMutex);
return iRet;
}
//
// int SetCompleteSize_TAP(PTAPSERVERINFO pTapServerInfo,
// long lCompleteFileSize);
//
// Sets the complete size of the file. If this size is
// not known it may be set to -1 (TAP_SIZE_UNKNOWN).
//
// Parameters:
// pTapServerInfo
// Pointer to the TAP Server instance data.
// lCompleteFileSize
// Size of the file when transfer is complete.
//
// Returns: TRUE on success.
//
int SetCompleteSize_TAP(PTAPSERVERINFO pTapServerInfo,
long lCompleteFileSize)
{
int iRet = TRUE;
// Request exclusive access to the server
DosRequestMutexSem(pTapServerInfo -> hServerMutex,
(ULONG)SEM_INDEFINITE_WAIT);
// Set complete file size in pipe packet
pTapServerInfo -> tiTapInfo . lCompleteFileSize = lCompleteFileSize;
// Release exclusive access to the server
DosReleaseMutexSem(pTapServerInfo -> hServerMutex);
return iRet;
}
//
// int SetCurrentSize_TAP(PTAPSERVERINFO pTapServerInfo,
// long lCurrentFileSize);
//
// Sets the current size of the file. If thie size is
// not known it may be set to -1 (TAP_SIZE_UNKNOWN).
//
// Parameters:
// pTapServerInfo
// Pointer to the TAP Server instance data.
// lCurrentFileSize
// Size of the file at the current time.
//
// Returns: TRUE on success.
//
int SetCurrentSize_TAP(PTAPSERVERINFO pTapServerInfo,
long lCurrentFileSize)
{
int iRet = TRUE;
// Request exclusive access to the server
DosRequestMutexSem(pTapServerInfo -> hServerMutex,
(ULONG)SEM_INDEFINITE_WAIT);
// Set current file size in pipe packet
pTapServerInfo -> tiTapInfo . lCurrentFileSize = lCurrentFileSize;
// Set flag indicating the file size changed
pTapServerInfo->tiTapInfo.ulFlags |= TAP_NEW_SIZE;
// Send new file information down the pipe
DosPostEventSem(pTapServerInfo -> hevUpdate);
// Release exclusive access to the server
DosReleaseMutexSem(pTapServerInfo -> hServerMutex);
return iRet;
}
//
// int EmergencyClose_TAP(PTAPSERVERINFO pTapServerInfo)
//
// Calls for all TAP Applications to immediately
// close the current file.
//
// This function might be called if the current file needs
// to be erased, moved, copied, etc. Note that this file
// close operation will not take affect as soon as this
// function returns. A 1/4 second delay is recommended
// following this call before attempting any other file
// operations. Normally the operation will succeed, but
// if it fails delay another 1/4 second and retry the
// operation.
//
// NOTE: This does NOT close the current file on the
// server side. You must do this yourself.
//
// Parameters:
// pTapServerInfo
// Pointer to the TAP Server instance data.
//
// Returns: TRUE on success.
//
int EmergencyClose_TAP(PTAPSERVERINFO pTapServerInfo)
{
int iRet = TRUE;
// Request exclusive access to the server
DosRequestMutexSem(pTapServerInfo -> hServerMutex,
(ULONG)SEM_INDEFINITE_WAIT);
// Set flag asking for an emergency close file
pTapServerInfo->tiTapInfo.ulFlags |= TAP_EMERGENCY_CLOSE;
pTapServerInfo -> lFileOpen = FALSE;
// Send new file information down the pipe
DosPostEventSem(pTapServerInfo -> hevUpdate);
// Release exclusive access to the server
DosReleaseMutexSem(pTapServerInfo -> hServerMutex);
return iRet;
}
//
// int Cancel_TAP(PTAPSERVERINFO pTapServerInfo);
//
// Alerts the TAP Applications that the current
// transfer batch has been cancelled.
//
// Parameters:
// pTapServerInfo
// Pointer to the TAP Server instance data.
//
// Returns: TRUE on success.
//
int Cancel_TAP(PTAPSERVERINFO pTapServerInfo)
{
int iRet = TRUE;
// Request exclusive access to the server
DosRequestMutexSem(pTapServerInfo -> hServerMutex,
(ULONG)SEM_INDEFINITE_WAIT);
// Set flag asking for a cancel transfer
pTapServerInfo->tiTapInfo.ulFlags |= TAP_CANCEL;
pTapServerInfo -> lFileOpen = FALSE;
// Send new file information down the pipe
DosPostEventSem(pTapServerInfo -> hevUpdate);
// Release exclusive access to the server
DosReleaseMutexSem(pTapServerInfo -> hServerMutex);
return iRet;
}
//
// int EndOfFile_TAP(PTAPSERVERINFO pTapServerInfo);
//
// Alerts the TAP Applications that we have reached
// the end of the current file.
//
// Parameters:
// pTapServerInfo
// Pointer to the TAP Server instance data.
//
// Returns: TRUE on success.
//
int EndOfFile_TAP(PTAPSERVERINFO pTapServerInfo)
{
int iRet = TRUE;
// Request exclusive access to the server
DosRequestMutexSem(pTapServerInfo -> hServerMutex,
(ULONG)SEM_INDEFINITE_WAIT);
// Set flag saying we've reached the end of this file
pTapServerInfo -> tiTapInfo.ulFlags |= TAP_EOF;
pTapServerInfo -> lFileOpen = FALSE;
// Send new file information down the pipe
DosPostEventSem(pTapServerInfo -> hevUpdate);
// Release exclusive access to the server
DosReleaseMutexSem(pTapServerInfo -> hServerMutex);
return iRet;
}
//
// int EndOfBatch_TAP(PTAPSERVERINFO pTapServerInfo);
//
// Alerts the TAP Applications that we have reached
// the end of the current file transfer batch.
// That is, that the application should expect no more
// files.
//
// Parameters:
// pTapServerInfo
// Pointer to the TAP Server instance data.
//
// Returns: TRUE on success.
//
int EndOfBatch_TAP(PTAPSERVERINFO pTapServerInfo)
{
int iRet = TRUE;
// Request exclusive access to the server
DosRequestMutexSem(pTapServerInfo -> hServerMutex,
(ULONG)SEM_INDEFINITE_WAIT);
// Set flag saying we've reached the end of the batch
pTapServerInfo->tiTapInfo.ulFlags |= TAP_EOB;
pTapServerInfo -> lFileOpen = FALSE;
// Send new file information down the pipe
DosPostEventSem(pTapServerInfo -> hevUpdate);
// Release exclusive access to the server
DosReleaseMutexSem(pTapServerInfo -> hServerMutex);
return iRet;
}
//
// void ServerThread_TAP(void *ServerInfo)
//
// -= Internal only =-
// -= Not to be called from outside this module =-
//
// Handles the dispatch of file information to
// TAP Applications.
//
void ServerThread_TAP (void *ServerInfo) {
PTAPSERVERINFO pTapServerInfo = (PTAPSERVERINFO) ServerInfo;
ULONG PostCount;
ULONG BytesWritten;
long cnter;
PTAPPACKET pTapPacket;
USHORT usPacketLength;
for (;;)
{
// Wait until someone asks us to send a new pipe packet
DosWaitEventSem(pTapServerInfo -> hevUpdate, (ULONG)SEM_INDEFINITE_WAIT);
// Request exclusive access to the server
DosRequestMutexSem(pTapServerInfo -> hServerMutex, (ULONG)SEM_INDEFINITE_WAIT);
// Note that TAP_VERSION is handled elsewhere; it is sent immediately when thread is created!
if (pTapServerInfo->tiTapInfo.ulFlags & TAP_BOF) {
USHORT usFileNameLength = (USHORT)strlen (pTapServerInfo->tiTapInfo.szFileName);
usPacketLength = (USHORT)(sizeof (pTapPacket->beginFilePacket) + usFileNameLength);
pTapPacket = malloc (usPacketLength);
pTapPacket->beginFilePacket.lCurrentFileSize = pTapServerInfo->tiTapInfo.lCurrentFileSize;
pTapPacket->beginFilePacket.lCompleteFileSize = pTapServerInfo->tiTapInfo.lCompleteFileSize;
pTapPacket->beginFilePacket.usFileNameLength = usFileNameLength;
strcpy (pTapPacket->beginFilePacket.szFileName, pTapServerInfo->tiTapInfo.szFileName);
}
else if (pTapServerInfo->tiTapInfo.ulFlags & TAP_NEW_SIZE) {
usPacketLength = (USHORT)sizeof (pTapPacket->newSizePacket);
pTapPacket = malloc (usPacketLength);
pTapPacket->newSizePacket.lCurrentFileSize = pTapServerInfo->tiTapInfo.lCurrentFileSize;
pTapPacket->newSizePacket.lCompleteFileSize = pTapServerInfo->tiTapInfo.lCompleteFileSize;
}
else {
usPacketLength = sizeof (pTapPacket->flagPacket);
pTapPacket = malloc (usPacketLength);
}
pTapPacket->flagPacket.cb = usPacketLength;
pTapPacket->flagPacket.usFlags = (USHORT)pTapServerInfo->tiTapInfo.ulFlags;
// Send the packet down all pipes
for (cnter=0; cnter < pTapServerInfo->lNumPipes; cnter++) {
DosWrite (pTapServerInfo->phWritePipe[cnter], pTapPacket, pTapPacket->flagPacket.cb, &BytesWritten);
}
free (pTapPacket);
// Reset flags
pTapServerInfo -> tiTapInfo . ulFlags = 0L;
// Reset update event semaphore
DosResetEventSem(pTapServerInfo -> hevUpdate, &PostCount);
// Release exclusive access to the server
DosReleaseMutexSem(pTapServerInfo -> hServerMutex);
// If this is a shutdown request break out
if (pTapServerInfo -> lShutdown)
break;
}
// ***
// Shut down code
// ***
// Close semaphores
DosCloseEventSem(pTapServerInfo -> hevUpdate);
DosCloseMutexSem(pTapServerInfo -> hServerMutex);
// Close pipes
for(cnter=0; cnter < pTapServerInfo->lNumPipes; cnter++) {
DosClose(pTapServerInfo -> phWritePipe[cnter]);
}
// Free memory
free((void *) pTapServerInfo -> phWritePipe);
free((void *) pTapServerInfo);
// End this thread
_endthread();
}
//
// void LaunchApplicationThread_TAP(void *data);
//
// Thread to start the TAP application,
// so we don't hog the message queue
//
void LaunchApplicationThread_TAP(void *data)
{
PLAUNCHINFO pLaunchInfo = (PLAUNCHINFO) data;
HAB hab;
HMQ hmq;
// And to make things even more fun,
// StartApplication_TAP requires the
// presence of a message queue
hab=WinInitialize(0);
hmq=WinCreateMsgQueue(hab, 0);
// Start TAP application
StartApplication_TAP(pLaunchInfo -> pTapServerInfo,
pLaunchInfo -> szProgram,
pLaunchInfo -> szParams,
pLaunchInfo -> szTitle);
// We are responsible for freeing this structure
free(pLaunchInfo);
// Free up PM resources
WinDestroyMsgQueue(hmq);
WinTerminate(hab);
// End this thread
_endthread();
}
//
// MRESULT EXPENTRY SelectApplicationDlgProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2);
//
// -= Internal only =-
// -= Not to be called from outside this module =-
//
MRESULT EXPENTRY SelectApplicationDlgProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
MRESULT mResult;
switch (msg)
{
case WM_INITDLG :
{
char *szApps;
ULONG ulSize;
// ***
// Store PTAPSERVERINFO in the window words
// ***
WinSetWindowPtr(hWnd, QWL_USER, (PVOID) mp2);
// ***
// Initialize listbox with TAP applications available
// ***
// Get size of application list
if (GetApplications_TAP(NULL, &ulSize))
{
// Allocate enough memory for list
szApps = (char *) malloc(ulSize + 10);
if (GetApplications_TAP(szApps, &ulSize))
{
ULONG cnter;
char szApp[256];
int iAppLen;
// Traverse the array of strings
for (cnter=0, iAppLen = 0; cnter<ulSize; cnter++)
// Is there more to be added to the app name?
if (szApps[cnter])
szApp[iAppLen++] = szApps[cnter];
else
// No, have we seen two NULLs in a row?
if (!iAppLen)
// We've reached the end of the list
break;
else
{
// This is the end of an app name
szApp[iAppLen] = 0;
iAppLen = 0;
// Insert this application into the
// list box
WinSendDlgItemMsg(hWnd,
ID_APPLIST_TAP,
LM_INSERTITEM,
(MPARAM) LIT_SORTASCENDING,
(MPARAM) szApp);
}
}
// Free up application list
free(szApps);
}
mResult = (MRESULT) FALSE;
break;
}
case WM_CONTROL :
{
USHORT id = SHORT1FROMMP(mp1);
USHORT usNotifyCode = SHORT2FROMMP(mp1);
// Was an application selected in the list box?
if ((id == ID_APPLIST_TAP) &&
(usNotifyCode == LN_SELECT))
{
TAPAPPENTRY TapAppEntry;
char szAppName[256];
SHORT sItemSelected;
IPT MLETextLen;
// Get selected application name
sItemSelected = (SHORT)
WinSendDlgItemMsg(hWnd,
ID_APPLIST_TAP,
LM_QUERYSELECTION,
(MPARAM) LIT_FIRST,
(MPARAM) 0);
WinSendDlgItemMsg(hWnd,
ID_APPLIST_TAP,
LM_QUERYITEMTEXT,
(MPARAM) MPFROM2SHORT(sItemSelected, 256),
(MPARAM) szAppName);
// Get the description of the application
GetApplicationInfo_TAP(szAppName, &TapAppEntry);
// Put new application description into MLE
MLETextLen = (IPT)
WinSendDlgItemMsg(hWnd,
ID_APPDESC_TAP,
MLM_QUERYTEXTLENGTH,
(MPARAM) 0,
(MPARAM) 0);
WinSendDlgItemMsg(hWnd,
ID_APPDESC_TAP,
MLM_SETSEL,
(MPARAM) 0,
(MPARAM) MLETextLen);
WinSendDlgItemMsg(hWnd,
ID_APPDESC_TAP,
MLM_INSERT,
(MPARAM) TapAppEntry.szDescription,
(MPARAM) 0);
}
// Call default handler
mResult = WinDefDlgProc(hWnd, msg, mp1, mp2);
break;
}
case WM_COMMAND :
{
// Should we launch an application?
if (SHORT1FROMMP(mp1) == DID_OK)
{
SHORT sItemSelected;
char szAppName[256];
// Get selected item number
sItemSelected = (SHORT)
WinSendDlgItemMsg(hWnd,
ID_APPLIST_TAP,
LM_QUERYSELECTION,
(MPARAM) LIT_FIRST,
(MPARAM) 0);
if (sItemSelected != LIT_NONE)
{
PTAPSERVERINFO pTapServerInfo;
TAPAPPENTRY TapAppEntry;
PLAUNCHINFO pLaunchInfo;
// Get pTapServerInfo
pTapServerInfo = (PTAPSERVERINFO) WinQueryWindowPtr(hWnd, QWL_USER);
// Get name of selected item
WinSendDlgItemMsg(hWnd,
ID_APPLIST_TAP,
LM_QUERYITEMTEXT,
(MPARAM) MPFROM2SHORT(sItemSelected, 256),
(MPARAM) szAppName);
// Get application's information
GetApplicationInfo_TAP(szAppName, &TapAppEntry);
// Start a thread to launch the application,
// otherwise we will hog the message queue.
// The launch thread will terminate after the
// TAP application has started.
pLaunchInfo = malloc(sizeof(LAUNCHINFO));
pLaunchInfo -> cb = sizeof(LAUNCHINFO);
pLaunchInfo -> pTapServerInfo = pTapServerInfo;
strcpy(pLaunchInfo -> szProgram, TapAppEntry.szProgram);
strcpy(pLaunchInfo -> szParams, TapAppEntry.szParams);
strcpy(pLaunchInfo -> szTitle, "TAP Application");
#ifdef __BORLANDC__
_beginthread(LaunchApplicationThread_TAP,
8192L,
pLaunchInfo);
#else
_beginthread(LaunchApplicationThread_TAP,
NULL,
8192L,
pLaunchInfo);
#endif
}
}
// Call default handler
mResult = WinDefDlgProc(hWnd, msg, mp1, mp2);
break;
}
default :
// Call default handler
mResult = WinDefDlgProc(hWnd, msg, mp1, mp2);
break;
}
return mResult;
}