home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
xwphescr.zip
/
XWPH0208.ZIP
/
src
/
helpers
/
wphandle.c
< prev
next >
Wrap
C/C++ Source or Header
|
2002-08-05
|
37KB
|
1,112 lines
/*
*@@sourcefile wphandle.c:
* this file contains the logic for dealing with
* those annoying WPS object handles in OS2SYS.INI.
* This does not use WPS interfaces, but parses
* the profiles directly.
*
* Usage: All OS/2 programs.
*
* Function prefixes (new with V0.81):
* -- wph* WPS object helper functions
*
* Thanks go out to Henk Kelder for telling me the
* format of the WPS INI data. With V0.9.16, this
* file was completely rewritten and no longer uses
* his code though.
*
* Note: Version numbering in this file relates to XWorkplace version
* numbering.
*
*@@header "helpers\wphandle.h"
*/
/*
* This file Copyright (C) 1997-2001 Ulrich Möller,
* This file is part of the "XWorkplace helpers" source package.
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, in version 2 as it comes in the
* "COPYING" file of the XWorkplace main distribution.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define OS2EMX_PLAIN_CHAR
// this is needed for "os2emx.h"; if this is defined,
// emx will define PSZ as _signed_ char, otherwise
// as unsigned char
#define INCL_DOSEXCEPTIONS
#define INCL_DOSPROCESS
#define INCL_DOSERRORS
#define INCL_WINSHELLDATA
#define INCL_WINNLS
#include <os2.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <io.h>
#include <setjmp.h>
#include "setup.h" // code generation and debugging options
#include "helpers\except.h"
#include "helpers\linklist.h"
#include "helpers\prfh.h"
#include "helpers\standards.h"
#include "helpers\stringh.h"
#include "helpers\tree.h"
#include "helpers\xstring.h"
#define INCLUDE_WPHANDLE_PRIVATE
#include "helpers\wphandle.h"
/*
*@@category: Helpers\PM helpers\Workplace Shell\Handles (OS2SYS.INI)
* See wphandle.c.
*/
/* ******************************************************************
*
* Load handles functions
*
********************************************************************/
/*
*@@ wphQueryActiveHandles:
* returns the value of PM_Workplace:ActiveHandles
* in OS2SYS.INI as a new buffer.
*
* There are always two buffers in OS2SYS.INI for object
* handles, called "PM_Workplace:HandlesX" with "X" either
* being "0" or "1".
*
* It seems that every time the WPS does something in the
* handles section, it writes the data to the inactive
* buffer first and then makes it the active buffer by
* changing the "active handles" key. You can test this
* by creating a shadow on your Desktop.
*
* This returns a new PSZ which the caller must free()
* after use.
*
* This gets called by the one-shot function
* wphQueryHandleFromPath.
*
*@@changed V0.9.16 (2001-10-02) [umoeller]: rewritten
*/
APIRET wphQueryActiveHandles(HINI hiniSystem,
PSZ *ppszActiveHandles) // out: active handles string (new buffer)
{
PSZ pszActiveHandles;
if (pszActiveHandles = prfhQueryProfileData(hiniSystem,
WPINIAPP_ACTIVEHANDLES,
WPINIAPP_HANDLESAPP,
NULL))
{
*ppszActiveHandles = pszActiveHandles;
return NO_ERROR;
}
return ERROR_WPH_NO_ACTIVEHANDLES_DATA;
}
/*
*@@ wphQueryBaseClassesHiwords:
* returns the hiwords for the WPS base
* classes. Unless the user's system is
* really badly configured, this should
* set
*
* -- pusHiwordAbstract to 2;
* -- pusHiwordFileSystem to 3.
*
* Returns:
*
* -- NO_ERROR
*
* -- ERROR_WPH_NO_BASECLASS_DATA
*
* -- ERROR_WPH_INCOMPLETE_BASECLASS_DATA
*
* This gets called automatically from wphLoadHandles.
*
*@@added V0.9.16 (2001-10-02) [umoeller]
*/
APIRET wphQueryBaseClassesHiwords(HINI hiniUser,
PUSHORT pusHiwordAbstract,
PUSHORT pusHiwordFileSystem)
{
APIRET arc = NO_ERROR;
// get the index of WPFileSystem from the base classes list...
// we need this to determine the hiword for file-system handles
// properly. Normally, this should be 3.
ULONG cbBaseClasses = 0;
PSZ pszBaseClasses;
if (pszBaseClasses = prfhQueryProfileData(hiniUser,
"PM_Workplace:BaseClass",
"ClassList",
&cbBaseClasses))
{
// parse that buffer... these has the base class names,
// separated by 0. List is terminated by two zeroes.
PSZ pszClassThis = pszBaseClasses;
ULONG ulHiwordThis = 1;
while ( (*pszClassThis)
&& (pszClassThis - pszBaseClasses < cbBaseClasses)
)
{
if (!strcmp(pszClassThis, "WPFileSystem"))
*pusHiwordFileSystem = ulHiwordThis;
else if (!strcmp(pszClassThis, "WPAbstract"))
*pusHiwordAbstract = ulHiwordThis;
ulHiwordThis++;
pszClassThis += strlen(pszClassThis) + 1;
}
// now check if we found both
if ( (!(*pusHiwordFileSystem))
|| (!(*pusHiwordAbstract))
)
arc = ERROR_WPH_INCOMPLETE_BASECLASS_DATA;
free(pszBaseClasses);
}
else
arc = ERROR_WPH_NO_BASECLASS_DATA;
return arc;
}
/*
*@@ FreeChildrenTree:
* called from NukeNameTrees for recursion.
*
*@@added V0.9.16 (2001-10-19) [umoeller]
*/
static VOID FreeChildrenTree(TREE **ppChildrenTree,
PLONG plCount)
{
LONG cItems = *plCount;
TREE** papNodes = treeBuildArray(*ppChildrenTree,
&cItems);
if (papNodes)
{
ULONG ul;
for (ul = 0; ul < cItems; ul++)
{
PNODETREENODE pNodeThis = (PNODETREENODE)papNodes[ul];
FreeChildrenTree(&pNodeThis->ChildrenTree,
&pNodeThis->cChildren);
free(pNodeThis);
}
free(papNodes);
*plCount = 0;
treeInit(ppChildrenTree, plCount);
}
}
/*
*@@ NukeNameTrees:
* frees all cache trees.
*
*@@added V0.9.16 (2001-10-19) [umoeller]
*/
static APIRET NukeNameTrees(PHANDLESBUF pHandlesBuf)
{
APIRET arc = NO_ERROR;
LONG cItems = pHandlesBuf->cDrives;
TREE** papNodes = treeBuildArray(pHandlesBuf->DrivesTree,
&cItems);
if (papNodes)
{
ULONG ul;
for (ul = 0; ul < cItems; ul++)
{
PDRIVETREENODE pNodeThis = (PDRIVETREENODE)papNodes[ul];
FreeChildrenTree(&pNodeThis->ChildrenTree,
&pNodeThis->cChildren);
free(pNodeThis);
}
free(papNodes);
treeInit(&pHandlesBuf->DrivesTree,
&pHandlesBuf->cDrives);
}
return arc;
}
/*
*@@ wphRebuildNodeHashTable:
* builds all the complex cache trees in the
* given handles buffer.
*
* If (fQuitOnErrors == TRUE), we'll fail as
* soon as an invalid handle is found. Otherwise
* we will try to continue if the error is not fatal.
*
* Returns:
*
* -- NO_ERROR
*
* -- ERROR_INVALID_PARAMETER
*
* -- ERROR_WPH_CORRUPT_HANDLES_DATA
*
* -- ERROR_WPH_DRIV_TREEINSERT_FAILED: duplicate DRIV node
* (non-fatal)
*
*@@added V0.9.16 (2001-10-02) [umoeller]
*@@changted V0.9.17 (2002-02-05) [umoeller]: added fQuitOnErrors
*/
APIRET wphRebuildNodeHashTable(HHANDLES hHandles,
BOOL fQuitOnErrors)
{
APIRET arc = NO_ERROR;
PHANDLESBUF pHandlesBuf;
if ( (!(pHandlesBuf = (PHANDLESBUF)hHandles))
|| (!pHandlesBuf->pbData)
|| (!pHandlesBuf->cbData)
)
arc = ERROR_INVALID_PARAMETER;
else
{
// start at beginning of buffer
PBYTE pCur = pHandlesBuf->pbData + 4;
PBYTE pEnd = pHandlesBuf->pbData + pHandlesBuf->cbData;
PDRIVETREENODE pLastDriveTreeNode = NULL;
memset(pHandlesBuf->NodeHashTable, 0, sizeof(pHandlesBuf->NodeHashTable));
NukeNameTrees(pHandlesBuf);
// now set up hash table
while ( (pCur < pEnd)
&& (!arc)
)
{
if (!memicmp(pCur, "DRIV", 4))
{
// pCur points to a DRIVE node:
// these never have handles, so skip this
PDRIVE pDriv = (PDRIVE)pCur;
// upper the node name for string comparisons
strupr(pDriv->szName);
// create a drive tree node
// (stored so we can append to this)
if (!(pLastDriveTreeNode = NEW(DRIVETREENODE)))
arc = ERROR_NOT_ENOUGH_MEMORY;
else
{
pLastDriveTreeNode->Tree.ulKey = (ULONG)pDriv->szName;
pLastDriveTreeNode->pDriv = pDriv;
treeInit(&pLastDriveTreeNode->ChildrenTree,
&pLastDriveTreeNode->cChildren);
if (treeInsert(&pHandlesBuf->DrivesTree,
&pHandlesBuf->cDrives,
(TREE*)pLastDriveTreeNode,
treeCompareStrings))
if (fQuitOnErrors)
arc = ERROR_WPH_DRIV_TREEINSERT_FAILED;
}
// next item
pCur += sizeof(DRIVE) + strlen(pDriv->szName);
}
else if (!memicmp(pCur, "NODE", 4))
{
// pCur points to a regular NODE: offset pointer first
PNODE pNode = (PNODE)pCur;
PNODETREENODE pNew;
// upper the node name for string comparisons
strupr(pNode->szName);
// create a node tree node
if (!(pNew = NEW(NODETREENODE)))
arc = ERROR_NOT_ENOUGH_MEMORY;
else
{
TREE **ppTree = NULL;
PLONG pcChildren = NULL;
pNew->Tree.ulKey = (ULONG)pNode->szName;
pNew->pNode = pNode;
treeInit(&pNew->ChildrenTree,
&pNew->cChildren);
// now check where to insert this...
// does it have a parent?
if (pNode->usParentHandle)
{
PNODETREENODE pParent;
if (!(pParent = pHandlesBuf->NodeHashTable[pNode->usParentHandle]))
{
// this parent handle is invalid:
if (fQuitOnErrors)
arc = ERROR_WPH_INVALID_PARENT_HANDLE;
}
else
{
ppTree = &pParent->ChildrenTree;
pcChildren = &pParent->cChildren;
}
}
else
// null parent handle: then the parent
// must be a DRIVE node
if (pLastDriveTreeNode)
{
ppTree = &pLastDriveTreeNode->ChildrenTree;
pcChildren = &pLastDriveTreeNode->cChildren;
}
else
if (fQuitOnErrors)
arc = ERROR_WPH_NODE_BEFORE_DRIV;
if (ppTree && pcChildren)
if (!treeInsert(ppTree,
pcChildren,
(TREE*)pNew,
treeCompareStrings))
{
// store PNODE in hash table
pHandlesBuf->NodeHashTable[pNode->usHandle] = pNew;
// do not free
pNew = NULL;
}
else
;
// @@todo if this fails, there are
// several handles for short name!!!
// arc = ERROR_WPH_NODE_TREEINSERT_FAILED;
if (pNew)
free(pNew);
}
pCur += sizeof(NODE) + pNode->usNameSize;
}
else
{
arc = ERROR_WPH_CORRUPT_HANDLES_DATA;
break;
}
}
}
if (!arc)
pHandlesBuf->fCacheValid = TRUE;
return arc;
}
/*
*@@ wphLoadHandles:
* returns a HANDLESBUF structure which will hold
* all the handles from OS2SYS.INI. In addition,
* this calls wphQueryBaseClassesHiwords and puts
* the hiwords for WPAbstract and WPFileSystem into
* the HANDLESBUF as well.
*
* Prerequisite before using any of the other wph*
* functions.
*
* Call wphFreeHandles to free all data allocated
* by this function.
*
* Returns:
*
* -- NO_ERROR
*
* -- ERROR_NOT_ENOUGH_MEMORY
*
* -- ERROR_INVALID_PARAMETER
*
* -- ERROR_WPH_NO_HANDLES_DATA: cannot read handle blocks.
*
* -- ERROR_WPH_CORRUPT_HANDLES_DATA: cannot read handle blocks.
*
*@@added V0.9.16 (2001-10-02) [umoeller]
*/
APIRET wphLoadHandles(HINI hiniUser, // in: HINI_USER or other INI handle
HINI hiniSystem, // in: HINI_SYSTEM or other INI handle
const char *pcszActiveHandles,
HHANDLES *phHandles)
{
APIRET arc = NO_ERROR;
if (!phHandles)
arc = ERROR_INVALID_PARAMETER;
else
{
PSZ pszKeysList;
if (!(arc = prfhQueryKeysForApp(hiniSystem,
pcszActiveHandles,
&pszKeysList)))
{
PHANDLESBUF pReturn = NULL;
ULONG ulHighestBlock = 0,
ul,
cbTotal;
PBYTE pbData;
const char *pKey2 = pszKeysList;
while (*pKey2)
{
if (!memicmp((PVOID)pKey2, "BLOCK", 5))
{
ULONG ulBlockThis = atoi(pKey2 + 5);
if (ulBlockThis > ulHighestBlock)
ulHighestBlock = ulBlockThis;
}
pKey2 += strlen(pKey2)+1; // next key
}
free(pszKeysList);
if (!ulHighestBlock)
arc = ERROR_WPH_NO_HANDLES_DATA;
else
{
// now go read the data
// (BLOCK1, BLOCK2, ..., BLOCKn)
cbTotal = 0;
pbData = NULL;
for (ul = 1;
ul <= ulHighestBlock;
ul++)
{
ULONG cbBlockThis;
CHAR szBlockThis[10];
sprintf(szBlockThis, "BLOCK%d", ul);
if (!PrfQueryProfileSize(hiniSystem,
(PSZ)pcszActiveHandles,
szBlockThis,
&cbBlockThis))
{
arc = ERROR_WPH_PRFQUERYPROFILESIZE_BLOCK;
break;
}
else
{
ULONG cbTotalOld = cbTotal;
cbTotal += cbBlockThis;
if (!(pbData = (BYTE*)realloc(pbData, cbTotal)))
// on first call, pbData is NULL and this
// behaves like malloc()
{
arc = ERROR_NOT_ENOUGH_MEMORY;
break;
}
if (!PrfQueryProfileData(hiniSystem,
(PSZ)pcszActiveHandles,
szBlockThis,
pbData + cbTotalOld,
&cbBlockThis))
{
arc = ERROR_WPH_PRFQUERYPROFILEDATA_BLOCK;
break;
}
}
}
}
if (!arc)
{
// all went OK:
if (pReturn = NEW(HANDLESBUF))
{
ZERO(pReturn);
treeInit(&pReturn->DrivesTree,
&pReturn->cDrives);
pReturn->pbData = pbData;
pReturn->cbData = cbTotal;
// and load the hiwords too
if (!(arc = wphQueryBaseClassesHiwords(hiniUser,
&pReturn->usHiwordAbstract,
&pReturn->usHiwordFileSystem)))
*phHandles = (HHANDLES)pReturn;
}
else
arc = ERROR_NOT_ENOUGH_MEMORY;
}
if (arc)
// error:
wphFreeHandles((HHANDLES*)&pReturn);
}
}
return arc;
}
/*
*@@ wphFreeHandles:
* frees all data allocated by wphLoadHandles
* and sets *ppHandlesBuf to NULL, for safety.
*
*@@added V0.9.16 (2001-10-02) [umoeller]
*/
APIRET wphFreeHandles(HHANDLES *phHandles)
{
APIRET arc = NO_ERROR;
PHANDLESBUF pHandlesBuf;
if ( (phHandles)
&& (pHandlesBuf = (PHANDLESBUF)*phHandles)
)
{
PBYTE pbData;
NukeNameTrees(pHandlesBuf);
if (pbData = pHandlesBuf->pbData)
free(pbData);
free(pHandlesBuf);
*phHandles = NULLHANDLE;
}
else
arc = ERROR_INVALID_PARAMETER;
return arc;
}
/* ******************************************************************
*
* Get HOBJECT from filename
*
********************************************************************/
/*
*@@ wphSearchBufferForHandle:
* returns the 16-bit file-system handle which corresponds
* to pszFilename, searching pHandlesBuffer. Note that you
* must OR the return value with the proper hiword to make
* this a valid WPS file-system handle.
*
* You must pass a handles buffer to this function which
* has been filled using wphReadAllBlocks above.
*
* This gets called by the one-shot function
* wphQueryHandleFromPath.
*
* Returns:
*
* -- NO_ERROR
*
* -- ERROR_INVALID_PARAMETER
*
* -- ERROR_FILE_NOT_FOUND
*
* -- ERROR_INVALID_NAME
*
* -- ERROR_WPH_CORRUPT_HANDLES_DATA
*
* -- ERROR_WPH_CANNOT_FIND_HANDLE: no handle exists for the
* given filename.
*
*@@changed V0.9.16 (2001-10-19) [umoeller]: rewritten
*/
APIRET wphSearchBufferForHandle(HHANDLES hHandles,
PCSZ pcszFile, // in: fully qlf'd filename to search for
PUSHORT pusHandle) // out: 16-bit handle
{
APIRET arc = NO_ERROR;
PHANDLESBUF pHandlesBuf;
_Pmpf((__FUNCTION__ ": entering"));
if ( (hHandles)
&& (pHandlesBuf = (PHANDLESBUF)hHandles)
)
{
// rebuild cache
if (!pHandlesBuf->fCacheValid)
arc = wphRebuildNodeHashTable(hHandles,
TRUE); // fail on errors
if (!arc)
{
// We can thus work our way through the buffer by splitting the
// fully qualified filename that we're searching for into the
// different directory names and, each time, searching for the
// corresponding NODE. If we have found that, we go for the next.
// Example for C:\OS2\E.EXE:
// 1) first search for the "C:" NODE
// 2) then find the "OS2" node which has "C" as its parent NODE
// (we do this by comparing the parent object handles)
// 3) then find the "E.EXE" NODE the same way
// The "E.EXE" NODE then has the object handle we're looking for.
// make a copy of the filename so we can play
PSZ pszFilename = strdup(pcszFile),
pEnd = NULL;
strupr(pszFilename);
// 1) OK, find the drive.
// If this is an UNC name, the DRIVE node has the form
// \\SERVER\RESOURCE.
if ( (*pszFilename == '\\')
&& (*(pszFilename + 1) == '\\')
)
{
// UNC:
// @@todo
}
else if (*(pszFilename + 1) == ':')
// extract the drive then (without \)
pEnd = pszFilename + 2;
if (!pEnd)
arc = ERROR_INVALID_NAME;
else
{
PDRIVETREENODE pDrive = NULL;
PNODETREENODE pNode;
// find the DRIVE node
CHAR cOld = *pEnd;
*pEnd = 0;
_Pmpf((" searching for drive \"%s\"", pszFilename));
if (!(pDrive = (PDRIVETREENODE)treeFind(pHandlesBuf->DrivesTree,
(ULONG)pszFilename, // drive name
treeCompareStrings)))
arc = ERROR_WPH_NO_MATCHING_DRIVE_BLOCK;
// find the root dir, which has the same name
else if (!(pNode = (PNODETREENODE)treeFind(pDrive->ChildrenTree,
(ULONG)pszFilename,
treeCompareStrings)))
arc = ERROR_WPH_NO_MATCHING_ROOT_DIR;
else
{
// now we got the root dir... go for next path component
while ( (pEnd)
&& (*pEnd = cOld) // not null char
&& (!arc)
)
{
// got another path component to search:
PSZ pCurrent = pEnd + 1,
pNext;
if (pNext = strchr(pCurrent, '\\'))
{
cOld = *pNext;
*pNext = 0;
}
else
// done:
cOld = 0;
_Pmpf((" searching for node \"%s\"", pCurrent));
// find the next node
if (!(pNode = (PNODETREENODE)treeFind(pNode->ChildrenTree,
(ULONG)pCurrent,
treeCompareStrings)))
arc = ERROR_WPH_CANNOT_FIND_HANDLE;
pEnd = pNext;
}
if (!arc && pNode)
// found everything:
*pusHandle = pNode->pNode->usHandle;
}
} // end while
free(pszFilename);
}
}
else
arc = ERROR_INVALID_PARAMETER;
_Pmpf((__FUNCTION__ ": returning %d", arc));
// not found: end of buffer reached
return arc;
}
/*
*@@ wphQueryHandleFromPath:
* finds the object handle for the given fully qualified
* filename.
* This is a one-shot function, using wphQueryActiveHandles,
* wphReadAllBlocks, and wphSearchBufferForHandle.
*
* Returns:
*
* -- NO_ERROR: *phobj has received the object handle.
*
* -- ERROR_FILE_NOT_FOUND: file does not exist.
*
* plus the error codes of the other wph* functions called.
*
*@@changed V0.9.16 (2001-10-02) [umoeller]: rewritten
*/
APIRET wphQueryHandleFromPath(HINI hiniUser, // in: HINI_USER or other INI handle
HINI hiniSystem, // in: HINI_SYSTEM or other INI handle
const char *pcszName, // in: fully qlf'd filename
HOBJECT *phobj) // out: object handle found if NO_ERROR
{
APIRET arc = NO_ERROR;
PSZ pszActiveHandles = NULL;
HHANDLES hHandles = NULLHANDLE;
TRY_LOUD(excpt1)
{
// not found there: check the handles then
if (arc = wphQueryActiveHandles(hiniSystem, &pszActiveHandles))
_Pmpf((__FUNCTION__ ": wphQueryActiveHandles returned %d", arc));
else
{
if (arc = wphLoadHandles(hiniUser,
hiniSystem,
pszActiveHandles,
&hHandles))
_Pmpf((__FUNCTION__ ": wphLoadHandles returned %d", arc));
else
{
USHORT usObjID;
CHAR szFullPath[2*CCHMAXPATH];
_fullpath(szFullPath, (PSZ)pcszName, sizeof(szFullPath));
// search that buffer
if (!(arc = wphSearchBufferForHandle(hHandles,
szFullPath,
&usObjID)))
// found: OR 0x30000
*phobj = usObjID | (((PHANDLESBUF)hHandles)->usHiwordFileSystem << 16);
else
arc = ERROR_FILE_NOT_FOUND;
}
}
}
CATCH(excpt1)
{
arc = ERROR_PROTECTION_VIOLATION; // V0.9.19 (2002-07-01) [umoeller]
} END_CATCH();
if (pszActiveHandles)
free(pszActiveHandles);
if (hHandles)
wphFreeHandles(&hHandles);
return arc;
}
/* ******************************************************************
*
* Get filename from HOBJECT
*
********************************************************************/
/*
*@@ ComposeThis:
* helper for wphComposePath recursion.
*
*@@added V0.9.16 (2001-10-02) [umoeller]
*@@changed V0.9.19 (2002-04-14) [umoeller]: fixed wrong error for parent handles
*/
static APIRET ComposeThis(PHANDLESBUF pHandlesBuf,
USHORT usHandle, // in: handle to search for
PXSTRING pstrFilename, // in/out: filename
ULONG ulLevel, // in: recursion level (initially 0)
PNODE *ppNode) // out: node found (ptr can be NULL)
{
APIRET arc = NO_ERROR;
PNODETREENODE pTreeNode;
PNODE pNode;
if ( (pTreeNode = pHandlesBuf->NodeHashTable[usHandle])
&& (pNode = pTreeNode->pNode)
)
{
// handle exists:
if (pNode->usParentHandle)
{
// node has parent:
// recurse first
if (!(arc = ComposeThis(pHandlesBuf,
pNode->usParentHandle,
pstrFilename,
ulLevel + 1,
ppNode)))
{
// no error:
xstrcatc(pstrFilename, '\\');
xstrcat(pstrFilename, pNode->szName, pNode->usNameSize);
}
}
else
// no parent:
xstrcpy(pstrFilename, pNode->szName, pNode->usNameSize);
}
else
// handle not found:
if (ulLevel == 0) // V0.9.19 (2002-04-14) [umoeller]
arc = ERROR_INVALID_HANDLE;
else
arc = ERROR_WPH_INVALID_PARENT_HANDLE;
if (!arc)
if (ppNode)
*ppNode = pNode;
return arc;
}
/*
*@@ wphComposePath:
* returns the fully qualified path name for the specified
* file-system handle. This function is very fast because
* it uses a hash table for all the handles internally.
*
* Warning: This calls a helper, which recurses.
*
* This returns:
*
* -- NO_ERROR
*
* -- ERROR_WPH_CORRUPT_HANDLES_DATA: buffer data cannot be parsed.
*
* -- ERROR_WPH_INVALID_HANDLE: usHandle cannot be found.
*
* -- ERROR_WPH_INVALID_PARENT_HANDLE: a handle was found
* that has a broken parent handle.
*
* -- ERROR_BUFFER_OVERFLOW: cbFilename is too small to
* hold the full path that was composed.
*
*@@added V0.9.16 (2001-10-02) [umoeller]
*/
APIRET wphComposePath(HHANDLES hHandles,
USHORT usHandle, // in: loword of handle to search for
PSZ pszFilename,
ULONG cbFilename,
PNODE *ppNode) // out: node found (ptr can be NULL)
{
APIRET arc = NO_ERROR;
PHANDLESBUF pHandlesBuf;
if ( (hHandles)
&& (pHandlesBuf = (PHANDLESBUF)hHandles)
)
{
TRY_LOUD(excpt1)
{
if (!pHandlesBuf->fCacheValid)
arc = wphRebuildNodeHashTable(hHandles,
TRUE); // fail on errors
if (!arc)
{
XSTRING str;
xstrInit(&str, CCHMAXPATH);
if (!(arc = ComposeThis(pHandlesBuf,
usHandle,
&str,
0, // initial recursion level
ppNode)))
if (str.ulLength > cbFilename - 1)
arc = ERROR_BUFFER_OVERFLOW;
else
memcpy(pszFilename,
str.psz,
str.ulLength + 1);
xstrClear(&str);
}
}
CATCH(excpt1)
{
arc = ERROR_PROTECTION_VIOLATION; // V0.9.19 (2002-07-01) [umoeller]
} END_CATCH();
}
return arc;
}
/*
*@@ wphQueryPathFromHandle:
* reverse to wphQueryHandleFromPath, this gets the
* filename for hObject.
* This is a one-shot function, using wphQueryActiveHandles,
* wphLoadHandles, and wphComposePath.
* As a result, this function is _very_ expensive.
*
* Returns:
*
* -- NO_ERROR
*
* -- ERROR_INVALID_HANDLE: hObject is invalid.
*
* -- ERROR_WPH_NOT_FILESYSTEM_HANDLE: hObject's hiword is wrong.
*
*@@changed V0.9.16 (2001-10-02) [umoeller]: rewritten
*/
APIRET wphQueryPathFromHandle(HINI hiniUser, // in: HINI_USER or other INI handle
HINI hiniSystem, // in: HINI_SYSTEM or other INI handle
HOBJECT hObject, // in: 32-bit object handle
PSZ pszFilename, // out: filename, if found
ULONG cbFilename) // in: sizeof(*pszFilename)
{
APIRET arc = NO_ERROR;
TRY_LOUD(excpt1)
{
PSZ pszActiveHandles;
if (arc = wphQueryActiveHandles(hiniSystem, &pszActiveHandles))
_Pmpf((__FUNCTION__ ": wphQueryActiveHandles returned %d", arc));
else
{
HHANDLES hHandles;
if (arc = wphLoadHandles(hiniUser,
hiniSystem,
pszActiveHandles,
&hHandles))
_Pmpf((__FUNCTION__ ": wphLoadHandles returned %d", arc));
else
{
USHORT usHiwordFileSystem = ((PHANDLESBUF)hHandles)->usHiwordFileSystem;
// is this really a file-system object?
if (HIUSHORT(hObject) == usHiwordFileSystem)
{
// use loword only
USHORT usObjID = LOUSHORT(hObject);
memset(pszFilename, 0, cbFilename);
arc = wphComposePath(hHandles,
usObjID,
pszFilename,
cbFilename,
NULL);
// _Pmpf((__FUNCTION__ ": wphFindPartName returned %d", arc));
}
else
arc = ERROR_WPH_NOT_FILESYSTEM_HANDLE;
wphFreeHandles(&hHandles);
}
free(pszActiveHandles);
}
}
CATCH(excpt1)
{
arc = ERROR_PROTECTION_VIOLATION; // V0.9.19 (2002-07-01) [umoeller]
} END_CATCH();
return arc;
}
/*
*@@ wphDescribeError:
* returns an error description for one of the handles
* engine errors, or NULL if the error code is not
* recognized.
*
*@@added V0.9.19 (2002-07-01) [umoeller]
*/
PCSZ wphDescribeError(APIRET arc)
{
switch (arc)
{
case ERROR_WPH_NO_BASECLASS_DATA:
return "Cannot find PM_Workplace:BaseClass in OS2.INI";
case ERROR_WPH_NO_ACTIVEHANDLES_DATA:
return "Cannot find PM_Workplace:ActiveHandles in OS2SYS.INI";
case ERROR_WPH_INCOMPLETE_BASECLASS_DATA:
return "PM_Workplace:ActiveHandles in OS2SYS.INI is incomplete";
case ERROR_WPH_NO_HANDLES_DATA:
return "Active handles block in OS2SYS.INI is empty";
case ERROR_WPH_CORRUPT_HANDLES_DATA:
return "Cannot parse data in active handles block in OS2SYS.INI";
case ERROR_WPH_INVALID_PARENT_HANDLE:
return "Handle has invalid parent handle";
case ERROR_WPH_CANNOT_FIND_HANDLE:
return "No handle exists for the given filename";
case ERROR_WPH_DRIV_TREEINSERT_FAILED:
return "Duplicate DRIV node (treeInsert failed)";
case ERROR_WPH_NODE_TREEINSERT_FAILED:
return "Duplicate NODE node (treeInsert failed)";
case ERROR_WPH_NODE_BEFORE_DRIV:
return "NODE node before DRIV node";
case ERROR_WPH_NO_MATCHING_DRIVE_BLOCK:
return "No matching DRIV node";
case ERROR_WPH_NO_MATCHING_ROOT_DIR:
return "No matching root directory";
case ERROR_WPH_NOT_FILESYSTEM_HANDLE:
return "Handle is not a file-system handle";
case ERROR_WPH_PRFQUERYPROFILESIZE_BLOCK:
return "PrfQueryProfileSize failed on reading one BLOCK in OS2SYS.INI";
case ERROR_WPH_PRFQUERYPROFILEDATA_BLOCK:
return "PrfQueryProfileData failed on reading one BLOCK in OS2SYS.INI";
}
return NULL;
}