home *** CD-ROM | disk | FTP | other *** search
- #define WIN32_LEAN_AND_MEAN // the bare essential Win32 API
- #include <windows.h>
- #include <httpext.h>
-
- #include "keys.h"
-
- //
- // If you want to record errors, modify this macro definition to
- // call your own logging function. This sample does not save
- // error strings.
- //
- #define LOG(errorstring)
-
- //
- // This file contains four externally used functions, and a bunch of
- // helper functions used only in this file.
- //
- // Functions called in other source files:
- //
- // GetKeyList Determines if data was sent, and if it was, the
- // data is extracted by GetPostKeys or GetUrlKeys,
- // two private functions within this file. A
- // pointer to a linked list is returned (as a
- // handle).
- //
- // GetKeyInfo Returns a pointer to the key name, an offset to
- // the start of the data within the content file,
- // the length of the data, a flag indicating if
- // the data has control characters in it, and an
- // instance number for duplicate key names.
- //
- // FindKey Sequentially searches linked list for key name.
- //
- // FreeKeyList Deallocates memory used by the linked list of
- // keys. Also deletes content file.
- //
- // GetContentPath Returns a pointer to the content file's full
- // path name.
- //
- // Helper functions called only in this source file:
- //
- // GetPostedByte Manages buffer fragmentation, an inherent
- // characteristic of ReadClient. Blocks of data
- // sent by a client are retrieved one byte at a
- // time. This works almost like _getch(), except
- // it returns web data, not keyboard data.
- //
- // GetQueryByte Similar to GetPostedByte, this function
- // extracts data from the query string.
- //
- // HexDigitToInt Returns the decimal value of a hex character.
- //
- // GetFirstByte Sets up POSDATA struct and calls GetNextByte.
- // Caller specifies function used to retrieve
- // data, either GetPostedByte or GetQueryByte.
- //
- // GetNextByte Uses GetInboundByte (specified in GetFirstByte)
- // to retrieve inbound data, and decodes it using
- // the URL encoding rules.
- //
- // BKL_Alloc Allocates memory used in GetPostKeys.
- //
- // BKL_Dealloc Deallocates memory used in GetPostKeys.
- //
- // BKL_Abort Cleans up all resources for abnormal exits from
- // GetPostKeys.
- //
- // IsKeySeparator Returns TRUE if character is one of "=\r\n&\0".
- //
- // BuildKeyList Given a data extraction function (i.e.
- // GetPostedByte or GetQueryByte), this function
- // converts all keys into a linked list of POSTKEY
- // structures.
- //
- // GetPostKeys Takes inbound data off the wire by calling
- // BuildKeyList with GetPostedByte as the extraction
- // function.
- //
- // GetUrlKeys Extracts data from the query string by calling
- // BuildKeyList with GetQueryByte as the extraction
- // function.
- //
- // The typedef for the linked list is kept privately in this file,
- // and GetKeyInfo isolates other source files from the implementation
- // details.
- //
-
-
- //
- // Constants for this source file only
- //
-
- #define MAX_KEY_NAME_LENGTH 256 // maximum size of an inbound key name
- #define CONTENT_BUF_LENGTH 8192 // amount of content buffered before WriteFile call
-
- #define GNB_NOTHING_LEFT 0 // GetNextByte return values
- #define GNB_DECODED_CHAR 1
- #define GNB_NORMAL_CHAR 2
-
-
- //
- // POSDATA struct is used with GetInboundByte to keep
- // track of the position within incoming data.
- // GETINBOUNDBYTE is a function pointer type.
- //
-
- typedef struct _tagPOSDATA
- {
- EXTENSION_CONTROL_BLOCK *pECB;
- int nCurrentPos; // overall position
- int nBufferLength; // length of buffer
- int nBufferPos; // position within buffer
- int nAllocLength; // size of buffer as allocated
- LPBYTE pData;
- int (*GetInboundByte)(struct _tagPOSDATA *p);
- } POSDATA, *PPOSDATA;
-
- typedef int(*GETINBOUNDBYTE)(PPOSDATA p);
-
-
-
- //
- // GetPostedByte returns a waiting character that is not
- // decoded yet. We have this function to smooth out the
- // inbound data: the server gives us blocks of data, one at
- // a time, and there can be any number of blocks.
- //
- // For the first call, pPosData->nAllocLength must be zero,
- // and pECB must be set.
- //
-
- int GetPostedByte (PPOSDATA pPosData)
- {
- int nBytesToCopy;
-
- // For readability only...
- EXTENSION_CONTROL_BLOCK *pECB;
- pECB = pPosData->pECB;
-
- //
- // Initialize position struct on first call.
- //
-
- if (!pPosData->nAllocLength)
- {
- // Initialize the members
- pPosData->nCurrentPos = 0;
- pPosData->nBufferPos = 0;
- pPosData->nBufferLength = 0;
- pPosData->nAllocLength = 0x10000; // 65536 bytes
-
- // Allocate the memory
- pPosData->pData = (LPBYTE) GlobalAlloc (GPTR, pPosData->nAllocLength);
- }
-
- //
- // Was memory allocated? Is it still allocated?
- // If not, return right away.
- //
-
- if (!pPosData->pData)
- {
- LOG ("GetPostedByte: Buffer not allocated.");
- return -1;
- }
-
- //
- // Check for end. Deallocate and return if we're done.
- //
-
- if ((DWORD) pPosData->nCurrentPos == pECB->cbTotalBytes)
- {
- GlobalFree ((HGLOBAL) pPosData->pData);
- pPosData->pData = 0;
- return -1;
- }
-
- //
- // Check for buffer not loaded. Load if necessary.
- //
-
- if (pPosData->nBufferPos == pPosData->nBufferLength)
- {
- //
- // Fill the buffer with new inbound data.
- // Request it via ReadClient if necessary.
- //
-
- if (pECB->cbAvailable < 1)
- {
- // Calculate how much we should go and get
- nBytesToCopy = pECB->cbTotalBytes - pPosData->nCurrentPos;
- if (nBytesToCopy > pPosData->nAllocLength)
- nBytesToCopy = pPosData->nAllocLength;
-
- // Let's go get the data
- if (!pECB->ReadClient (pECB->ConnID, pPosData->pData, (LPDWORD) &nBytesToCopy))
- {
- GlobalFree ((HGLOBAL) pPosData->pData);
- pPosData->pData = 0;
-
- LOG ("GetPostedByte: Error reading data via ReadClient");
- return -1;
- }
- }
- else
- {
- // Take at most nAllocLength bytes of data
- if (pECB->cbAvailable > (DWORD) (pPosData->nAllocLength))
- nBytesToCopy = pPosData->nAllocLength;
- else
- nBytesToCopy = pECB->cbAvailable;
-
- // Copy the inbound data to our buffer
- memcpy (pPosData->pData,
- &pECB->lpbData[pPosData->nCurrentPos],
- nBytesToCopy);
-
- // Account for removed data
- pECB->cbAvailable -= nBytesToCopy;
- }
-
- // Our buffer is now full
- pPosData->nBufferLength = nBytesToCopy;
- pPosData->nBufferPos = 0;
-
- // Make sure we have something
- if (!nBytesToCopy)
- {
- GlobalFree ((HGLOBAL) pPosData->pData);
- pPosData->pData = 0;
- return -1;
- }
- }
-
- //
- // Inc current pos, buffer pos, and return a character
- //
-
- pPosData->nCurrentPos++;
- pPosData->nBufferPos++;
- return ((int) pPosData->pData[pPosData->nBufferPos - 1]);
- }
-
-
- //
- // GetQueryByte returns a waiting character that is not
- // decoded yet. We have this function to match GetPostedData.
- //
- // For the first call, pPosData->nAllocLength must be zero,
- // and pECB must be set.
- //
-
- int GetQueryByte (PPOSDATA pPosData)
- {
- // For readability only...
- EXTENSION_CONTROL_BLOCK *pECB;
- pECB = pPosData->pECB;
-
- //
- // Initialize position struct on first call.
- //
-
- if (!pPosData->nAllocLength)
- {
- // Initialize the useful members
- pPosData->nBufferPos = 0;
- pPosData->nBufferLength = lstrlen ((LPCTSTR) pECB->lpszQueryString);
- pPosData->nAllocLength = -1;
- }
-
- //
- // Check for end. Deallocate and return if we're done.
- //
-
- if (pPosData->nBufferPos == pPosData->nBufferLength)
- return -1;
-
- //
- // Inc buffer pos and return a character
- //
-
- pPosData->nBufferPos++;
- return ((int) pECB->lpszQueryString[pPosData->nBufferPos - 1]);
- }
-
-
- //
- // Now that we have GetPostedByte, and GetQueryByte, we can
- // build a more useful function that decodes URL-style
- // encoded characters.
- //
- // Recall that there are two special cases for this encoding:
- //
- // 1. Each plus sign must be converted to a space
- // 2. A percent sign denotes a hex value-encoded character
- //
- // Percents are used to specify characters that are otherwise
- // illegal. This includes percents themselves, ampersands,
- // control characters, and so on.
- //
- // GetNextByte returns the decoded byte, plus a flag indicating
- // normal character, decoded character, or failure. See top of
- // file for return value constants.
- //
-
- //
- // HexDigitToInt simply converts a hex-based character to an int.
- //
-
- int HexDigitToInt (TCHAR tc)
- {
- if (tc >= TEXT('0') && tc <= TEXT('9'))
- return (tc - TEXT('0'));
-
- if (tolower (tc) >= TEXT('a') && tolower (tc) <= TEXT('f'))
- return (tc - TEXT('a') + 10);
-
- return -1;
- }
-
- //
- // GetFirstByte eliminates the guesswork from initialization.
- // We call GetFirstByte with an uninitialized POSDATA structure,
- // and we call GetNextByte from there on.
- //
-
- // forward declaration
- int GetNextByte (PPOSDATA pPosData, TCHAR *ptc);
-
- int GetFirstByte (PPOSDATA pPosData,
- EXTENSION_CONTROL_BLOCK *pECB,
- TCHAR *ptc, GETINBOUNDBYTE GetInboundByte)
- {
- // Initialize struct
- pPosData->nAllocLength = 0;
- pPosData->pECB = pECB;
- pPosData->GetInboundByte = GetInboundByte;
-
- // Make the call as usual
- return GetNextByte (pPosData, ptc);
- }
-
- int GetNextByte (PPOSDATA pPosData, TCHAR *ptc)
- {
- int nChar;
-
- // Initialize character pointer
- *ptc = 0;
-
- // Fetch the next inbound character
- nChar = pPosData->GetInboundByte (pPosData);
- if (nChar == -1)
- return GNB_NOTHING_LEFT;
-
- // Plus signs: convert to spaces
- if (nChar == '+')
- {
- *ptc = TEXT(' ');
- return GNB_DECODED_CHAR;
- }
-
- // Percent signs: convert hex values
- else if (nChar == '%')
- {
- nChar = pPosData->GetInboundByte (pPosData);
- if (nChar == -1 || HexDigitToInt (nChar) == -1)
- return GNB_NOTHING_LEFT;
-
- *ptc = (TCHAR) (HexDigitToInt (nChar) << 4);
-
- nChar = pPosData->GetInboundByte (pPosData);
- if (nChar == -1 || HexDigitToInt (nChar) == -1)
- {
- *ptc = 0; // incomplete
- return GNB_NOTHING_LEFT;
- }
-
- *ptc |= (TCHAR) HexDigitToInt (nChar);
-
- return GNB_DECODED_CHAR;
- }
-
- // Must be normal character then
- *ptc = (TCHAR) nChar;
-
- return GNB_NORMAL_CHAR;
- }
-
-
- //
- // Structure used in data processing - the elements of the
- // key list.
- //
-
- typedef struct _tagPOSTKEY
- {
- int nInstance; // used when key name is the same as another, normally 0
- DWORD dwOffset; // offset into content file
- DWORD dwLength; // length of data
- BOOL bHasCtrlChars; // a character value < 32 is in data
- struct _tagPOSTKEY *pNext; // linked list
- // key string appended to structure
- // for the head key, the content file name is also appended
- } POSTKEY, *PPOSTKEY;
-
-
-
- //
- // These three helper functions isolates the memory allocation,
- // deallocation and abnormal exit code. They are used only to
- // keep BuildKeyList readable.
- //
-
- BOOL BKL_Alloc (LPTSTR *plpszKey, LPBYTE *plpbyBuf)
- {
- // Allocate a buffer for the key name
- *plpszKey = (LPTSTR) GlobalAlloc (GPTR, MAX_KEY_NAME_LENGTH);
-
- if (!*plpszKey)
- return FALSE;
-
- // Allocate a buffer for the content
- *plpbyBuf = (LPBYTE) GlobalAlloc (GPTR, MAX_KEY_NAME_LENGTH);
-
- if (!*plpbyBuf)
- {
- GlobalFree ((HGLOBAL) *plpszKey);
- return FALSE;
- }
-
- return TRUE;
- }
-
- void BKL_Dealloc (LPTSTR *plpsz, LPBYTE *plpby)
- {
- if (*plpsz)
- GlobalFree ((HGLOBAL) *plpsz);
- if (*plpby)
- GlobalFree ((HGLOBAL) *plpby);
- }
-
- void BKL_Abort (PPOSTKEY pHead, HANDLE hFile, LPTSTR lpszKey, LPBYTE lpbyBuf)
- {
- if (pHead)
- FreeKeyList ((HKEYLIST) pHead);
-
- if (hFile != INVALID_HANDLE_VALUE)
- CloseHandle (hFile);
-
- BKL_Dealloc (&lpszKey, &lpbyBuf);
- }
-
- //
- // Function used to identify key separators
- //
-
- BOOL IsKeySeparator (TCHAR tc)
- {
- return (tc == '=' || tc == '\r' || tc == '\n' || tc == '&' || !tc);
- }
-
-
- //
- // Now that we have a way to get a decoded byte from the stream,
- // we can parse POST data. POST data comes in as:
- //
- // key=data&key=data&key=data\r\n
- //
- // A linked list of keys is established, and the head node
- // of the list is returned. A NULL indicates no keys or
- // an error.
- //
-
- PPOSTKEY BuildKeyList (EXTENSION_CONTROL_BLOCK *pECB,
- GETINBOUNDBYTE GetInboundByte)
- {
- PPOSTKEY pHead = NULL; // head of linked list (the return val)
- PPOSTKEY pTail = NULL; // last member in linked list
- PPOSTKEY pNewPostKey; // pointer for unlinked, newly allocated objects
- PPOSTKEY pListWalk; // linked list walking pointer
-
- LPTSTR lpszKeyNameBuf; // pointer to buffer, used in obtaining key name
- int nPos; // position within key name buffer
-
- DWORD dwOffset; // offset from start of content file
- DWORD dwLength; // length of key
-
- TCHAR tc; // general-purpose character
- int nReturn; // general-purpose return code
-
- POSDATA pd; // POSDATA struct needed in GetInboundByte
-
- LPBYTE lpbyContentBuf; // buffer used in writing content to file
- int nContentPos; // position within content buffer
- TCHAR szTempDir[MAX_PATH]; // directory of temporary files
- TCHAR szTempPath[MAX_PATH]; // path of content file
- HANDLE hDataFile; // handle to content file
- DWORD dwBytesWritten; // used with WriteFile
-
- BOOL bHasCtrlChars; // flag to detect ctrl chars
-
- // Call helper to allocate a buffer
- if (!BKL_Alloc (&lpszKeyNameBuf, &lpbyContentBuf))
- {
- LOG ("BuildKeyList: Memory allocation failure");
- return NULL;
- }
-
- nContentPos = dwOffset = 0;
-
- // Get a temp file name
- GetTempPath (MAX_PATH, szTempDir);
- if (!GetTempFileName (szTempDir,
- TEXT("postdata"), 0,
- szTempPath))
- {
- LOG ("BuildKeyList: Error creating temporary file");
- BKL_Dealloc (&lpszKeyNameBuf, &lpbyContentBuf);
- return NULL;
- }
-
- // Create the content file
- hDataFile = CreateFile (szTempPath,
- GENERIC_READ | GENERIC_WRITE,
- 0, // No sharing mode
- NULL, // Default security attribs
- CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
- NULL // No template file
- );
-
- // Return if an error occured
- if (hDataFile == INVALID_HANDLE_VALUE)
- {
- LOG ("BuildKeyList: Error opening temporary file");
- BKL_Abort (pHead, hDataFile, lpszKeyNameBuf, lpbyContentBuf);
- return NULL;
- }
-
- //
- // 'for' statement detects the start of a valid key name.
- //
- // To do inside 'for' loop:
- // Obtain key name
- // Write data to content file
- // Create POSTKEY object
- // Update links
- //
-
- for (nReturn = GetFirstByte (&pd, pECB, &tc, GetInboundByte);
- nReturn != GNB_NOTHING_LEFT;
- nReturn = GetNextByte (&pd, &tc))
- {
- // If \r or \n, ignore and continue
- if (tc == TEXT('\r') || tc == TEXT('\n'))
- continue;
-
- // Get a key name
- nPos = 0;
- while (!IsKeySeparator (tc))
- {
- if (nPos < MAX_KEY_NAME_LENGTH)
- {
- lpszKeyNameBuf[nPos] = tc;
- nPos++;
- }
-
- nReturn = GetNextByte (&pd, &tc);
- if (nReturn == GNB_NOTHING_LEFT) // abrupt end!
- break;
- }
-
- // If no equals sign or name too long,
- // we have a browser formatting error
- if (tc != '=' || nPos == MAX_KEY_NAME_LENGTH)
- {
- LOG ("BuildKeyList: Browser formatting error");
-
- BKL_Abort (pHead, hDataFile, lpszKeyNameBuf, lpbyContentBuf);
- return NULL;
- }
-
- // Truncate the name string, reset data info variables
- lpszKeyNameBuf[nPos] = 0;
- nPos++;
- dwLength = 0;
- bHasCtrlChars = FALSE;
-
- //
- // Write data to the content file.
- //
- for (nReturn = GetNextByte (&pd, &tc);
- !IsKeySeparator (tc) || nReturn == GNB_DECODED_CHAR;
- nReturn = GetNextByte (&pd, &tc))
- {
- // Copy inbound data to a content buffer,
- // include support for UNICODE
-
- #ifdef UNICODE
- *((WORD *) (&lpbyContentBuf[nContentPos])) = tc;
- #else
- lpbyContentBuf[nContentPos] = tc;
- #endif
-
- nContentPos += sizeof (TCHAR);
- dwLength++;
-
- // Check for ctrl chars
- if (tc < 0x20 || tc > 0x7e)
- bHasCtrlChars = TRUE;
-
- // If we have enough data, write buffer to disk
- if (nContentPos == CONTENT_BUF_LENGTH)
- {
- if (!WriteFile (hDataFile, lpbyContentBuf,
- nContentPos, &dwBytesWritten, NULL))
- {
- LOG ("BuildKeyList: Error writing to content file");
- BKL_Abort (pHead, hDataFile, lpszKeyNameBuf, lpbyContentBuf);
- return NULL;
- }
-
- nContentPos = 0;
- }
- }
-
- // Drain buffer
- if (nContentPos)
- {
- if (!WriteFile (hDataFile, lpbyContentBuf,
- nContentPos, &dwBytesWritten, NULL))
- {
- LOG ("BuildKeyList: Error writing to content file");
- BKL_Abort (pHead, hDataFile, lpszKeyNameBuf, lpbyContentBuf);
- return NULL;
- }
-
- nContentPos = 0;
- }
-
- // Allocate a POSTKEY object, allocate extra for first key
- if (pHead)
- pNewPostKey = (PPOSTKEY) GlobalAlloc (GPTR,
- sizeof (POSTKEY) + nPos);
- else
- pNewPostKey = (PPOSTKEY) GlobalAlloc (GPTR,
- sizeof (POSTKEY) + nPos +
- lstrlen (szTempPath) + 1);
-
- // Check for valid pointer
- if (!pNewPostKey)
- {
- LOG ("BuildKeyList: POSTKEY memory allocation failure");
- BKL_Abort (pHead, hDataFile, lpszKeyNameBuf, lpbyContentBuf);
- return NULL;
- }
-
- //
- // Set pNewPostKey members
- //
-
- // Set nInstance
- pNewPostKey->nInstance = 0;
- pListWalk = pHead;
- while (pListWalk)
- {
- // Check for duplicate key names
- if (!lstrcmpi ((LPCTSTR) (&pListWalk[1]), lpszKeyNameBuf))
- pNewPostKey->nInstance++;
- pListWalk = pListWalk->pNext;
- }
-
- // Set dwOffset, dwLength, bHasCtrlChars
- pNewPostKey->dwOffset = dwOffset;
- pNewPostKey->dwLength = dwLength;
- dwOffset += dwLength;
- pNewPostKey->bHasCtrlChars = bHasCtrlChars;
-
- // Copy key name
- lstrcpy ((LPTSTR) (&pNewPostKey[1]), lpszKeyNameBuf);
-
- // Link
- if (pTail)
- pTail->pNext = pNewPostKey;
- else
- {
- // Append content file name to head key
- lstrcpy (((LPTSTR) (&pNewPostKey[1])) +
- lstrlen (lpszKeyNameBuf) + 1,
- szTempPath);
-
- // Set head
- pHead = pNewPostKey;
- }
-
- pNewPostKey->pNext = NULL;
- pTail = pNewPostKey;
- }
-
- CloseHandle (hDataFile);
-
- return pHead;
- }
-
- //
- // We are now pretty much done with anything complex. BuildKeyList
- // will do all our parse work, so now we need a few wrappers to
- // make a nice, clean external interface.
- //
- // GetPostKeys calls BuildKeyList with GetPostedByte.
- //
- // GetUrlKeys calls BuildKeyList with GetQueryByte.
- //
-
- PPOSTKEY GetPostKeys (EXTENSION_CONTROL_BLOCK *pECB)
- {
- return BuildKeyList (pECB, GetPostedByte);
- }
-
- PPOSTKEY GetUrlKeys (EXTENSION_CONTROL_BLOCK *pECB)
- {
- return BuildKeyList (pECB, GetQueryByte);
- }
-
-
- //
- // And now we implement the external interface. GetKeyList
- // examines the method and calls GetPostKeys or GetUrlKeys,
- // which ever is important.
- //
-
- HKEYLIST GetKeyList (EXTENSION_CONTROL_BLOCK *pECB)
- {
- if (!lstrcmpi ((LPCTSTR) pECB->lpszMethod, TEXT("POST")))
- {
- LOG ("Method=POST");
- return (HKEYLIST) GetPostKeys (pECB);
- }
-
- else if (!lstrcmpi ((LPCTSTR) pECB->lpszMethod, TEXT("GET")))
- {
- LOG ("Method=GET");
- return (HKEYLIST) GetUrlKeys (pECB);
- }
-
- LOG ("Unknown method");
- return NULL;
- }
-
-
- //
- // GetKeyInfo is a wrapper for the POSTKEY linked list.
- // It returns the members of the supplied POSTKEY object.
- //
-
- HKEYLIST GetKeyInfo (HKEYLIST hKey, LPCTSTR *plpszKeyName,
- LPDWORD pdwOffset, LPDWORD pdwLength,
- BOOL *pbHasCtrlChars, LPINT pnInstance)
- {
- PPOSTKEY pPostKey;
-
- // Safety
- if (!hKey)
- return NULL;
-
- pPostKey = (PPOSTKEY) hKey;
-
- // Set the data members
- *plpszKeyName = (LPCTSTR) (&pPostKey[1]);
- *pdwOffset = pPostKey->dwOffset;
- *pdwLength = pPostKey->dwLength;
- *pbHasCtrlChars = pPostKey->bHasCtrlChars;
- *pnInstance = pPostKey->nInstance;
-
- // Return a handle to the next object in the list
- return ((HKEYLIST) pPostKey->pNext);
- }
-
-
- //
- // FindKey sequentially searches the linked list for a given key.
- // The return handle points to the element within the linked list.
- // Use it in GetKeyInfo, but not FreeKeyList.
- //
-
- HKEYLIST FindKey (HKEYLIST hKeyList, LPCTSTR lpszSearchName)
- {
- PPOSTKEY pFindKey;
-
- pFindKey = (PPOSTKEY) hKeyList;
- while (pFindKey)
- {
- if (!lstrcmpi (lpszSearchName, (LPCTSTR) (&pFindKey[1])))
- return ((HKEYLIST) pFindKey);
-
- pFindKey = pFindKey->pNext;
- }
-
- return NULL;
- }
-
-
- //
- // FreeKeyList deallocates all the objects in the key list.
- // The content file is also deleted.
- //
-
- void FreeKeyList (HKEYLIST hHeadKey)
- {
- PPOSTKEY pObject;
- PPOSTKEY pDel;
-
- // Safety
- if (!hHeadKey)
- return;
-
- // delete the content file
- DeleteFile (GetContentPath (hHeadKey));
-
- // delete all objects in the list
- pObject = (PPOSTKEY) hHeadKey;
- while (pObject)
- {
- pDel = pObject;
- pObject = pObject->pNext;
-
- GlobalFree ((HGLOBAL) pDel);
- }
- }
-
-
- //
- // GetContentPath returns the name of the content file associated
- // with a key list. The name is a full path, suitable for CreateFile.
- //
-
- LPCTSTR GetContentPath (HKEYLIST hHeadKey)
- {
- LPCTSTR lpszKeyName;
- PPOSTKEY pHead;
-
- // Safety
- if (!hHeadKey)
- return NULL;
-
- // ContentPath follows POSTKEY struct and key name
- pHead = (PPOSTKEY) hHeadKey;
- lpszKeyName = (LPCTSTR) (&pHead[1]);
-
- return (lpszKeyName + lstrlen (lpszKeyName) + 1);
- }
-
-