// apphacks.c : Defines the entry point for the console application.
//
// This little utility is supposed to allow me a way to enter in data into
// Image File Execution Options without doing it by hand all the time.  Used
// specifically for apphack flags and taking version info out of the EXE to see
// if a match exists

#define UNICODE   1

#include <windows.h>
#include <commdlg.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <winver.h>
#include <apcompat.h>





#define MIN_VERSION_RESOURCE	512
#define IMAGE_EXEC_OPTIONS      TEXT("software\\microsoft\\windows NT\\currentversion\\Image File Execution Options\\")

extern TCHAR*  CheckExtension(TCHAR*);
extern VOID    SetRegistryVal(TCHAR* , TCHAR* , PTCHAR,DWORD);
extern VOID    DetailError1  (DWORD );

extern BOOLEAN g_fNotPermanent;
PVOID          g_lpPrevRegSettings;


UINT uVersionInfo[5][8]={  {4,0,1381,VER_PLATFORM_WIN32_NT,3,0,0,0},
                           {4,0,1381,VER_PLATFORM_WIN32_NT,4,0,0,0},
                           {4,0,1381,VER_PLATFORM_WIN32_NT,5,0,0,0},
                           {4,10,1998,VER_PLATFORM_WIN32_WINDOWS,0,0,0,0},
                           {4,0,950,VER_PLATFORM_WIN32_WINDOWS,0,0,0,0}
                           };

PTCHAR  pszVersionInfo[5]={
                           TEXT("Service Pack 3"),
                           TEXT("Service Pack 4"),
                           TEXT("Service Pack 5"),
                           TEXT(""),
                           TEXT("")
                           };

BOOLEAN g_GooAppendFlag;


VOID  SetRegistryValGoo(TCHAR* szTitle, TCHAR* szVal,PUCHAR szBuffer,DWORD dwType,UINT length)
{
  long         lResult;
  TCHAR        szSubKey[MAX_PATH];
  HKEY         hKey;

      wsprintf(szSubKey,
               TEXT("software\\microsoft\\windows NT\\currentversion\\Image File Execution Options\\%s"),
               szTitle);

       lResult = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
                              szSubKey,
                              0,
                              TEXT("\0"),
                              0,
                              KEY_WRITE,
                              NULL,
                              &hKey,
                              NULL);
       if(lResult == ERROR_SUCCESS)
        {

          RegSetValueEx(hKey,
                        szVal,
                        0,
                        dwType,
                        (CONST BYTE*)szBuffer,
                        length);

          RegCloseKey(hKey);
        }
}

VOID DeleteRegistryValueGoo(TCHAR*szTitle)
{
  long         lResult;
  TCHAR        szSubKey[MAX_PATH];
  HKEY         hKey;

      wsprintf(szSubKey,
               TEXT("software\\microsoft\\windows NT\\currentversion\\Image File Execution Options\\%s"),
               szTitle);

       lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
                              szSubKey,
                              0,
                              KEY_WRITE,
                              &hKey
                              );
       if(lResult == ERROR_SUCCESS)
        {
          RegDeleteValue(hKey,TEXT("ApplicationGoo") );
          RegCloseKey(hKey);
        }
}


/*
 Check whether the registry contains an entry for "applicationgoo" for the given *.exe.
 If it does, check the "resource info." to determine whether they are same.
 If they are the same, don't worry, your work is already done. If not,
 the new one needs to get appended to the old one.
*/
BOOLEAN CheckGooEntry(PVOID pVersionInfo,
                      PAPP_COMPAT_GOO pExistingVersionInfo,
                      BOOL fImageHasResourceInfo,
                      DWORD VersionInfoSize,
                      DWORD dwSize,
                      LARGE_INTEGER *pAppCompatFlag,
                      PAPP_VARIABLE_INFO pOsVersionInfo,
                      ULONG TotalVersionInfoLength,
                      TCHAR* pszPath                             // Executable path.
                      )
{
  BOOLEAN fNeedAppend = FALSE;
  // Added for the addition and deletion from the registry.
  PAPP_COMPAT_GOO       pReplaceAppCompatGoo;
  PPRE_APP_COMPAT_INFO  pAppCompatEntry, pStoredAppCompatEntry = NULL;
  PPRE_APP_COMPAT_INFO  pDestAppCompatEntry, pReplaceAppCompatEntry;
  ULONG                 TotalGooLength, InputCompareLength, ReplaceCopyLength;
  ULONG                 OutputCompareLength, CopyLength, OffSet;
  PVOID                 ResourceInfo;
  UINT                  iLoop = 0;
  BOOL                  fMatchGot = FALSE;
  PVOID                 pExistingAppCompatFlag;
  PVOID                 pExistingOsVersionInfo;
  BOOLEAN               fAppCompatMatch = FALSE, fOsVersionMatch = FALSE;
  TCHAR                 szTitle[MAX_PATH];
  ULONG                 ReplaceGooLength;

  pAppCompatEntry = pExistingVersionInfo ->AppCompatEntry;
  TotalGooLength  = pExistingVersionInfo ->dwTotalGooSize -   \
                    sizeof(pExistingVersionInfo ->dwTotalGooSize);
  //Loop till we get a matching entry in the registry.
  while (TotalGooLength ){
        InputCompareLength = pAppCompatEntry->dwResourceInfoSize;
        ResourceInfo       = pAppCompatEntry + 1;

        if(fImageHasResourceInfo){
           if( InputCompareLength > VersionInfoSize)
              InputCompareLength = VersionInfoSize;

           OutputCompareLength = \
                       (ULONG)RtlCompareMemory(
                                   ResourceInfo,
                                   pVersionInfo,
                                   InputCompareLength
                                   );

        }
        else{
           OutputCompareLength = 0;
        }

        if( InputCompareLength != OutputCompareLength){
          // No match found...Need to continue thru till I find one or exhaust.
           TotalGooLength -= pAppCompatEntry->dwEntryTotalSize;
           (PUCHAR) pAppCompatEntry += pAppCompatEntry->dwEntryTotalSize;
           iLoop++;
           continue;
        }

        // We are a match !!
        pStoredAppCompatEntry = pAppCompatEntry;
        fMatchGot = TRUE;
        // Since we are a match, we won't add the ApplicationGoo but we need to check the
        // ApcompatFlag and the OSVersionInfo.
        if( (!pAppCompatFlag) && (!pOsVersionInfo) )
          break;

        OffSet = sizeof(PRE_APP_COMPAT_INFO) + \
                   pStoredAppCompatEntry->dwResourceInfoSize;
        if(pAppCompatFlag){
           (PUCHAR)pExistingAppCompatFlag = (PUCHAR) ( pStoredAppCompatEntry) + OffSet;
           InputCompareLength = sizeof(LARGE_INTEGER);
           OutputCompareLength = \
                            (ULONG) RtlCompareMemory(
                                       pAppCompatFlag,
                                       pExistingAppCompatFlag,
                                       InputCompareLength
                                       );
           if(OutputCompareLength ==  InputCompareLength)
              fAppCompatMatch = TRUE;
        }


        if(pOsVersionInfo){
           (PUCHAR)pExistingOsVersionInfo = (PUCHAR) (pStoredAppCompatEntry) + OffSet + \
                                                   sizeof(LARGE_INTEGER);
           InputCompareLength = pStoredAppCompatEntry->dwEntryTotalSize - \
                              (sizeof(PRE_APP_COMPAT_INFO) + \
                               pStoredAppCompatEntry->dwResourceInfoSize +\
                               sizeof(LARGE_INTEGER)
                              );
           if(InputCompareLength > TotalVersionInfoLength)
              InputCompareLength = TotalVersionInfoLength;

           OutputCompareLength = \
                            (ULONG) RtlCompareMemory(
                                       pOsVersionInfo,
                                       pExistingOsVersionInfo,
                                       InputCompareLength
                                       );
          if(OutputCompareLength ==  InputCompareLength)
             fOsVersionMatch = TRUE;
        }

        if( ( fOsVersionMatch == TRUE) &&
            ( fAppCompatMatch == TRUE) )
            break;
        else{ // one of these or both are different...
              /*
                The idea here is to replace that part of the AppCompatEntry, which is a
                mis-match. We go ahead and prepare the pReplaceAppCompatEntry
              */
           ReplaceCopyLength = sizeof(PRE_APP_COMPAT_INFO) + \
                        pStoredAppCompatEntry->dwResourceInfoSize + \
                        sizeof(LARGE_INTEGER) + \
                        TotalVersionInfoLength ;
           pReplaceAppCompatEntry = GlobalAlloc(GMEM_FIXED, ReplaceCopyLength);
           RtlCopyMemory((PUCHAR)pReplaceAppCompatEntry, (PUCHAR)pStoredAppCompatEntry, OffSet);
           RtlCopyMemory((PUCHAR)(pReplaceAppCompatEntry) + OffSet,(PUCHAR)pAppCompatFlag,sizeof(LARGE_INTEGER) );
           RtlCopyMemory((PUCHAR)(pReplaceAppCompatEntry)+(OffSet+sizeof(LARGE_INTEGER)),
                                                (PUCHAR)pOsVersionInfo,TotalVersionInfoLength);

           //Now prepare the GOO structure.
           ReplaceGooLength = pExistingVersionInfo ->dwTotalGooSize - \
                              pStoredAppCompatEntry->dwEntryTotalSize + \
                              ReplaceCopyLength;
           pReplaceAppCompatGoo = GlobalAlloc(GMEM_FIXED, ReplaceGooLength);
           pReplaceAppCompatGoo->dwTotalGooSize = ReplaceGooLength;

           pAppCompatEntry = pExistingVersionInfo->AppCompatEntry;
           pDestAppCompatEntry = ((PAPP_COMPAT_GOO)pReplaceAppCompatGoo)->AppCompatEntry;

           ReplaceGooLength -= sizeof(pExistingVersionInfo->dwTotalGooSize);
           while(ReplaceGooLength){
             CopyLength = pAppCompatEntry->dwEntryTotalSize;
             if(pAppCompatEntry != pStoredAppCompatEntry){
                RtlCopyMemory(pDestAppCompatEntry,pAppCompatEntry ,CopyLength);
                (PUCHAR)pDestAppCompatEntry += CopyLength;
             }
             else{
                RtlCopyMemory(pDestAppCompatEntry,pReplaceAppCompatEntry,ReplaceCopyLength);
                pDestAppCompatEntry->dwEntryTotalSize = ReplaceCopyLength;
                (PUCHAR)pDestAppCompatEntry += ReplaceCopyLength;
                (PUCHAR)pAppCompatEntry += pAppCompatEntry->dwEntryTotalSize;
                ReplaceGooLength -= ReplaceCopyLength;
                continue;
             }

             (PUCHAR)pAppCompatEntry += CopyLength;
             ReplaceGooLength -= CopyLength;
            } // End while
           // Delete the key from the registry and add back the updated one.

           GetFileTitle(pszPath,szTitle,MAX_PATH);
           if(CheckExtension(szTitle) == NULL)
             lstrcat(szTitle,TEXT(".exe"));
           DeleteRegistryValueGoo(szTitle);
           SetRegistryValGoo(szTitle,
                             TEXT("ApplicationGoo"),
                             (PUCHAR)pReplaceAppCompatGoo,
                             REG_BINARY,
                             pReplaceAppCompatGoo->dwTotalGooSize
                             );

          GlobalFree(pReplaceAppCompatEntry);
          GlobalFree(pReplaceAppCompatGoo);
        } // Else..

        break;
  } // End while (TotalGooLength )


  if(FALSE == fMatchGot){
    // No match available for this version.
    fNeedAppend = TRUE;
    // Reset the iteration count.
    iLoop  =  0;
  }

  if(g_fNotPermanent){
     // The user has chosen not to make the registry settings permanent and we have the
     // "Append" flag set indicating that there were entries appended to the ApplicationGoo.
     // We need to remove the correct entry for this executable.

     // The idea here is to copy the whole of "ApplicationGoo" to a global buffer leaving just
     // the one that needs to be deleted. Our job is made easier as we have the stored AppCompat
     // entry. We just need to go till there and copy the rest on to the global buffer.

     if(pStoredAppCompatEntry){
        pAppCompatEntry = pExistingVersionInfo->AppCompatEntry;
        TotalGooLength  = pExistingVersionInfo->dwTotalGooSize;
        g_lpPrevRegSettings = (PAPP_COMPAT_GOO)GlobalAlloc(GMEM_FIXED, TotalGooLength );
        ((PAPP_COMPAT_GOO)g_lpPrevRegSettings)->dwTotalGooSize = pExistingVersionInfo->dwTotalGooSize -
                                                                 pStoredAppCompatEntry->dwEntryTotalSize ;
        pDestAppCompatEntry = ((PAPP_COMPAT_GOO)g_lpPrevRegSettings)->AppCompatEntry;
        TotalGooLength -= sizeof(pExistingVersionInfo->dwTotalGooSize);
        while(TotalGooLength){
             CopyLength = pAppCompatEntry->dwEntryTotalSize;
             if(pAppCompatEntry != pStoredAppCompatEntry){
                RtlCopyMemory(pDestAppCompatEntry,pAppCompatEntry ,CopyLength);
                (PUCHAR)pDestAppCompatEntry += CopyLength;
                g_GooAppendFlag = TRUE;
             }

            (PUCHAR)pAppCompatEntry += CopyLength;
            TotalGooLength -= CopyLength;
        } // End while.
     }
     else{ // We do not have a stored AppCompatEntry. This means our target is to remove the
           // the first entry and leave the rest intact. i.e copy the rest onto the global buffer
           // for it to be copied.
           TotalGooLength = pExistingVersionInfo->dwTotalGooSize;
           g_lpPrevRegSettings = (PAPP_COMPAT_GOO)GlobalAlloc(GMEM_FIXED, TotalGooLength );
           RtlCopyMemory(g_lpPrevRegSettings,pExistingVersionInfo, TotalGooLength);
           g_GooAppendFlag = TRUE;
     }
  }

    return fNeedAppend;
  }



int MakeAppCompatGoo(TCHAR* TmpBuffer,LARGE_INTEGER* pAppCompatFlag, UINT uOsVer)
{
	BOOLEAN fImageHasVersionInfo = FALSE;
	BOOLEAN fOsVersionLie = FALSE;
	BOOLEAN fEntryPresent = FALSE;
 	TCHAR Buffer[MAX_PATH];
	TCHAR StringBuffer[MAX_PATH];
	TCHAR RegPath[MAX_PATH];
	TCHAR InChar;
	LONG status;
	HKEY hKey;
	PTCHAR pBuf;
	PTCHAR pAppGooBuf;
	PUCHAR pData;
	PTCHAR OutBuffer;
	PWCHAR uniBuffer;
	DWORD VersionInfoSize;
	DWORD dwHandle;
	DWORD dwBytesWritten;
	DWORD dwType;
	DWORD dwSize;
	ULONG i, j;
	ULONG EXELength;
	ULONG AppCompatHigh;
	ULONG AppCompatLow;
	ULONG TotalGooSize;
	ULONG TotalVersionInfoLength=0;
	ULONG OutBufferSize;
	PVOID lpData;
	PVOID ResourceInfo;
	PVOID VersionInfo;
	PAPP_COMPAT_GOO AppCompatGoo;
	PAPP_VARIABLE_INFO VariableInfo=NULL;
	PAPP_VARIABLE_INFO AppVariableInfo=NULL;
	EFFICIENTOSVERSIONINFOEXW OSVersionInfo, *pOsVersionInfo;

	// Remove the trailing and leading " " if PRESENT.
	    if(*TmpBuffer == TEXT('\"') ){
           lstrcpy(Buffer, TmpBuffer+1);
		   *(Buffer + (lstrlen(Buffer) - 1) )= TEXT('\0');
		 }
		 else
		   	lstrcpy(Buffer, TmpBuffer);
		   	
	// Quick check to see if its got any version info in its header
	VersionInfoSize = GetFileVersionInfoSize(&Buffer[0], &dwHandle);
	if (VersionInfoSize) {
		// It does, so alloc space for it to pull it in below
		VersionInfo = LocalAlloc(GMEM_FIXED, VersionInfoSize);
		if (VersionInfo) {
			// Get the version info
			if (GetFileVersionInfo(&Buffer[0], dwHandle, VersionInfoSize, VersionInfo)) {
				// Set global flag to be inspected later
				fImageHasVersionInfo = TRUE;
			}
		}
	}

	// Enter the app compat flags (decimal) - its defined as a LARGE_INTEGER	
    AppCompatHigh = 0x0;
    AppCompatLow  = 0x0;
    AppCompatLow  = pAppCompatFlag->LowPart;
    AppCompatHigh = pAppCompatFlag->HighPart;

	
	// Determine goo size, start with main goo
	TotalGooSize = sizeof(APP_COMPAT_GOO);

	

	// Add sizeof compatibility flags (large integer)
	TotalGooSize += sizeof(LARGE_INTEGER);
	// if we actually got version information add the length of that.  We take the minimum
	// of whatever the EXE has or 0x200 bytes to try and identify the app.  I've found that
	// anything less than 0x200 bytes doesn't supply enough info to be useful.
	if (fImageHasVersionInfo) {
		VersionInfoSize = min(VersionInfoSize, MIN_VERSION_RESOURCE);
		TotalGooSize += VersionInfoSize;
	}

	// See if they requested version lying, if so we got a bunch more horseshit todo
	if (AppCompatLow & KACF_VERSIONLIE) {
       fOsVersionLie  = TRUE;
	
       OSVersionInfo.dwMajorVersion = uVersionInfo[uOsVer][0];
       OSVersionInfo.dwMinorVersion = uVersionInfo[uOsVer][1];
       OSVersionInfo.dwBuildNumber  = uVersionInfo[uOsVer][2];
       OSVersionInfo.dwPlatformId   = uVersionInfo[uOsVer][3];
       OSVersionInfo.wServicePackMajor = (WORD)uVersionInfo[uOsVer][4];
       OSVersionInfo.wServicePackMinor = (WORD)uVersionInfo[uOsVer][5];
       OSVersionInfo.wSuiteMask      = (WORD)uVersionInfo[uOsVer][6];
       OSVersionInfo.wProductType    = (BYTE)uVersionInfo[uOsVer][7];
       lstrcpy( (TCHAR*) OSVersionInfo.szCSDVersion, pszVersionInfo[uOsVer]);


		// Start with the length of the full struct
		TotalVersionInfoLength = sizeof(EFFICIENTOSVERSIONINFOEXW);
		// subtract the size of the szCSDVersion field	
		TotalVersionInfoLength -= sizeof(OSVersionInfo.szCSDVersion);

				// add the strlen amount plus 1 for the NULL wchar
        TotalVersionInfoLength += lstrlen((TCHAR*)OSVersionInfo.szCSDVersion )*sizeof(WCHAR)+sizeof(WCHAR);

        // Add the size of the variable length structure header (since VerInfo is var length)
		TotalVersionInfoLength += sizeof(APP_VARIABLE_INFO);
		// Add the total version info length to the goo size
		TotalGooSize += TotalVersionInfoLength;
		// Allocate space for the variable length version info
		AppVariableInfo = (PAPP_VARIABLE_INFO) LocalAlloc(GMEM_FIXED, sizeof(APP_VARIABLE_INFO) + TotalVersionInfoLength);
		if (!AppVariableInfo) {
			return -1;
		}
		// fill in the pertinent data in the variable length info header
		AppVariableInfo->dwVariableInfoSize = sizeof(APP_VARIABLE_INFO) + TotalVersionInfoLength;
		AppVariableInfo->dwVariableType = AVT_OSVERSIONINFO;
		// Do a pointer +1 operation here to get past the header to the actual data
		VariableInfo = AppVariableInfo + 1;
		// Copy the actual data in
		memcpy(VariableInfo, &OSVersionInfo, TotalVersionInfoLength);
	
	}

	//
	// See if an entry already exists in the registry.  If so, we'll have to glom
	// this entry into the other already existing one.
	//
	// Get the registry path all figured out
	memset(&RegPath[0], 0, sizeof(RegPath));
	lstrcat(&RegPath[0], IMAGE_EXEC_OPTIONS);
	EXELength = lstrlen(&Buffer[0]);
	pBuf = &Buffer[0];
	pBuf += EXELength;
	// work backward in the path til we find the the last backslash
	while ((*pBuf != '\\') && (pBuf != &Buffer[0])) {
		pBuf--;	
	}
	if (*pBuf == '\\') {
		pBuf++;
	}

	if(CheckExtension(pBuf) == NULL)
     lstrcat(pBuf,TEXT(".exe"));

	// cat the image.exe name to the end of the registry path
	lstrcat(&RegPath[0], pBuf);
	// try to open this key
	status = RegOpenKey(HKEY_LOCAL_MACHINE, &RegPath[0], &hKey);
	if (status == ERROR_SUCCESS) {	
		dwSize = 1;
		// do a query once with small size to figure out how big the binary entry is
		status = RegQueryValueEx(hKey, TEXT("ApplicationGoo"), NULL, &dwType, NULL, &dwSize);
		if( status == ERROR_SUCCESS){
			//
			// There's an entry already there.  Take the size of this Goo entry and add it
			// to the TotalGooSize LESS the size of the first dword in the APP_COMPAT_GOO
			// struct (as there already was one there).
			//
			
		//  Added here after checkin
            if(dwSize > 1){
                lpData = LocalAlloc(GMEM_FIXED, dwSize);
                if(lpData){
                  status = RegQueryValueEx(hKey, TEXT("ApplicationGoo"), NULL, &dwType, (PUCHAR) lpData, &dwSize);
                 // if(VersionInfo) ...Remove this as it is not necessary.
              //    if(fOsVersionLie)
                //    pOsVersionInfo = VariableInfo;

        	      fEntryPresent = CheckGooEntry( VersionInfo,
        			                             (PAPP_COMPAT_GOO)lpData,
        			                             fImageHasVersionInfo,
        			                             VersionInfoSize,
        			                             dwSize,
        			                             pAppCompatFlag,
        			                             AppVariableInfo,
        			                             TotalVersionInfoLength,
        			                             Buffer
        			                            );
     			  }
     		    }	

       // End add


            if(fEntryPresent)
			  TotalGooSize += dwSize - sizeof(AppCompatGoo->dwTotalGooSize);
			
			else{  // Nothing to append....return as it is the same.
			  if(fImageHasVersionInfo)
                LocalFree(VersionInfo);
              if(fOsVersionLie)
                LocalFree(AppVariableInfo);

              return 0;
			}
			
			

	  RegCloseKey(hKey);
	}
   }

	// Allocate the memory for the entire app compat goo
	AppCompatGoo = (PAPP_COMPAT_GOO) LocalAlloc(GMEM_FIXED, TotalGooSize);
	if (!AppCompatGoo) {
		return -1;
	}

	// fill in the total size
	AppCompatGoo->dwTotalGooSize = TotalGooSize;
	// if there was version info for this entry we need to fill that in now, else zero
	if (fImageHasVersionInfo) {
		AppCompatGoo->AppCompatEntry[0].dwResourceInfoSize = VersionInfoSize;
	}
	else {
		AppCompatGoo->AppCompatEntry[0].dwResourceInfoSize = 0;
	}
	AppCompatGoo->AppCompatEntry[0].dwEntryTotalSize = \
		sizeof(AppCompatGoo->AppCompatEntry[0].dwEntryTotalSize) +
		sizeof(AppCompatGoo->AppCompatEntry[0].dwResourceInfoSize) +
		TotalVersionInfoLength +						// In case app needed VER lying
		sizeof(LARGE_INTEGER);							// For app compatibility flags

	// Entry size is whatever it was plus any resource info we've got
	AppCompatGoo->AppCompatEntry[0].dwEntryTotalSize += \
		AppCompatGoo->AppCompatEntry[0].dwResourceInfoSize;
	// do the pointer +1 thing so we can be pointing at the data area
	ResourceInfo = AppCompatGoo->AppCompatEntry + 1;
	// copy the data in
	memcpy(ResourceInfo, VersionInfo, VersionInfoSize);

	// filling in the app compat flags here
	pData = (PUCHAR) ResourceInfo + AppCompatGoo->AppCompatEntry[0].dwResourceInfoSize;
	memcpy(pData, &AppCompatLow, sizeof(AppCompatLow));
	pData += sizeof(AppCompatLow);
	memcpy(pData, &AppCompatHigh, sizeof(AppCompatHigh));
	pData += sizeof(AppCompatHigh);
	// if there was any version resource info, copy that in here too
	if (AppVariableInfo) {
		memcpy(pData, AppVariableInfo, TotalVersionInfoLength);
	}
	pData += TotalVersionInfoLength;
	//
	// If an already existing entry was there, we need to ask append what was there to the
	// tail of the entry.   (i.e. what's already there gets auto appended to the tail).  If
	// someone wants to write a 1-N positioning for entries within the Goo - they'll have to
	// add that support here
	//
	if (fEntryPresent) {
		// Start at offset + 4 cuz the previous Total Goo size must be skipped.
		memcpy(pData, (PUCHAR) lpData+4, dwSize - sizeof(AppCompatGoo->dwTotalGooSize));
	}


    pData = (PUCHAR) AppCompatGoo;
    SetRegistryValGoo(pBuf, TEXT("ApplicationGoo"),pData,REG_BINARY,AppCompatGoo->dwTotalGooSize);


    if(fImageHasVersionInfo)
       LocalFree(VersionInfo);
    if(fOsVersionLie)
       LocalFree(AppVariableInfo);
    if(fEntryPresent)
       LocalFree(lpData);
    LocalFree(AppCompatGoo);
  return 0;
}