Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1033 lines
25 KiB

/****************************Module*Header******************************\
* Module Name: OBJECT.C
*
* Module Descripton: Object management functions.
*
* Warnings:
*
* Issues:
*
* Public Routines:
*
* Created: 18 March 1996
* Author: Srinivasan Chandrasekar [srinivac]
*
* Copyright (c) 1996, 1997 Microsoft Corporation
\***********************************************************************/
#include "mscms.h"
//
// Number of required and optional functions for CMMs to export
//
#define NUM_REQ_FNS 10
#define NUM_OPT_FNS 6
#define NUM_PS_FNS 3
/******************************************************************************
*
* AllocateHeapObject
*
* Function:
* This functions allocates requested object on the process's heap,
* and returns a handle to it.
*
* Arguments:
* objType - type of object to allocate
*
* Returns:
* Handle to object if successful, NULL otherwise
*
******************************************************************************/
HANDLE
AllocateHeapObject(
OBJECTTYPE objType
)
{
DWORD dwSize;
POBJHEAD pObject;
switch (objType)
{
case OBJ_PROFILE:
dwSize = sizeof(PROFOBJ);
break;
case OBJ_TRANSFORM:
dwSize = sizeof(TRANSFORMOBJ);
break;
case OBJ_CMM:
dwSize = sizeof(CMMOBJ);
break;
default:
RIP((__TEXT("Allocating invalid object\n")));
dwSize = 0;
break;
}
pObject = (POBJHEAD)MemAlloc(dwSize);
if (!pObject)
{
return NULL;
}
pObject->objType = objType;
return(PTRTOHDL(pObject));
}
/******************************************************************************
*
* FreeHeapObject
*
* Function:
* This functions free an object on the process's heap
*
* Arguments:
* hObject - handle to object to free
*
* Returns:
* No return value
*
******************************************************************************/
VOID
FreeHeapObject(
HANDLE hObject
)
{
POBJHEAD pObject;
ASSERT(hObject != NULL);
pObject = (POBJHEAD)HDLTOPTR(hObject);
ASSERT(pObject->dwUseCount == 0);
pObject->objType = 0; // in case the handle gets reused
MemFree((PVOID)pObject);
}
/******************************************************************************
*
* ValidHandle
*
* Function:
* This functions checks if a given handle is a valid handle to
* an object of the specified type
*
* Arguments:
* hObject - handle to an object
* objType - type of object to the handle refers to
*
* Returns:
* TRUE is the handle is valid, FALSE otherwise.
*
******************************************************************************/
BOOL
ValidHandle(
HANDLE hObject,
OBJECTTYPE objType
)
{
POBJHEAD pObject;
BOOL rc;
if (!hObject)
{
return FALSE;
}
pObject = (POBJHEAD)HDLTOPTR(hObject);
rc = !IsBadReadPtr(pObject, sizeof(DWORD)) &&
(pObject->objType == objType);
return rc;
}
/******************************************************************************
*
* ValidProfile
*
* Function:
* This function checks if a given profile is valid by doing some
* sanity checks on it. It is not a fool prof check.
*
* Arguments:
* pProfObj - pointer to profile object
*
* Returns:
* TRUE if it is a valid profile, FALSE otherwise
*
******************************************************************************/
BOOL ValidProfile(
PPROFOBJ pProfObj
)
{
DWORD dwSize = FIX_ENDIAN(HEADER(pProfObj)->phSize);
return ((dwSize <= pProfObj->dwMapSize) &&
(HEADER(pProfObj)->phSignature == PROFILE_SIGNATURE) &&
(dwSize >= (sizeof(PROFILEHEADER) + sizeof(DWORD))));
}
/******************************************************************************
*
* MemAlloc
*
* Function:
* This functions allocates requested amount of zero initialized memory
* from the process's heap and returns a pointer to it
*
* Arguments:
* dwSize - amount of memory to allocate in bytes
*
* Returns:
* Pointer to memory if successful, NULL otherwise
*
******************************************************************************/
PVOID
MemAlloc(
DWORD dwSize
)
{
if (dwSize > 0)
return (PVOID)GlobalAllocPtr(GHND | GMEM_ZEROINIT, dwSize);
else
return NULL;
}
/******************************************************************************
*
* MemReAlloc
*
* Function:
* This functions reallocates a block of memory from the process's
* heap and returns a pointer to it
*
* Arguments:
* pMemory - pointer to original memory
* dwNewSize - new size to reallocate
*
* Returns:
* Pointer to memory if successful, NULL otherwise
*
******************************************************************************/
PVOID
MemReAlloc(
PVOID pMemory,
DWORD dwNewSize
)
{
return (PVOID)GlobalReAllocPtr(pMemory, dwNewSize, GMEM_ZEROINIT);
}
/******************************************************************************
*
* MemFree
*
* Function:
* This functions frees memory from the process's heap
* and returns a handle to it.
*
* Arguments:
* pMemory - pointer to memory to free
*
* Returns:
* No return value
*
******************************************************************************/
VOID
MemFree(
PVOID pMemory
)
{
DWORD dwErr;
//
// GlobalFree() resets last error, we get and set around it so we don't
// lose anything we have set.
//
dwErr = GetLastError();
GlobalFreePtr(pMemory);
if (dwErr)
{
SetLastError(dwErr);
}
}
/******************************************************************************
*
* MyCopyMemory
*
* Function:
* This functions copies data from one place to another. It takes care
* of overlapping cases. The reason we have our own function and not use
* MoveMemory is that MoveMemory uses memmove which pulls in msvcrt.dll
*
* Arguments:
* pDest - pointer to destination of copy
* pSrc - pointer to source
* dwCount - number of bytes to copy
*
* Returns:
* No return value
*
******************************************************************************/
VOID
MyCopyMemory(
PBYTE pDest,
PBYTE pSrc,
DWORD dwCount
)
{
//
// Make sure overlapping cases are handled
//
if ((pSrc < pDest) && ((pSrc + dwCount) >= pDest))
{
//
// Overlapping case, copy in reverse
//
pSrc += dwCount - 1;
pDest += dwCount - 1;
while (dwCount--)
{
*pDest-- = *pSrc--;
}
}
else
{
while (dwCount--)
{
*pDest++ = *pSrc++;
}
}
return;
}
/******************************************************************************
*
* ConvertToUnicode
*
* Function:
* This function converts a given Ansi string to Unicode. It optionally
* allocates memory for the Unicode string which the calling program
* needs to free.
*
* Arguments:
* pszAnsiStr - pointer to Ansi string to convert
* ppwszUnicodeStr - pointer to pointer to Unicode string
* bAllocate - If TRUE, allocate memory for Unicode string
*
* Returns:
* TRUE if successful, FALSE otherwise
*
******************************************************************************/
BOOL
ConvertToUnicode(
PCSTR pszAnsiStr,
PWSTR *ppwszUnicodeStr,
BOOL bAllocate
)
{
DWORD dwLen; // length of Unicode string
dwLen = (lstrlenA(pszAnsiStr) + 1) * sizeof(WCHAR);
//
// Allocate memory for Unicode string
//
if (bAllocate)
{
*ppwszUnicodeStr = (PWSTR)MemAlloc(dwLen);
if (! (*ppwszUnicodeStr))
{
WARNING((__TEXT("Error allocating memory for Unicode name\n")));
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
}
//
// Convert Ansi string to Unicode
//
if (! MultiByteToWideChar(CP_ACP, 0, pszAnsiStr, -1,
*ppwszUnicodeStr, dwLen))
{
WARNING((__TEXT("Error converting to Unicode name\n")));
MemFree(*ppwszUnicodeStr);
*ppwszUnicodeStr = NULL;
return FALSE;
}
return TRUE;
}
/******************************************************************************
*
* ConvertToAnsi
*
* Function:
* This function converts a given Unicode string to Ansi. It optionally
* allocates memory for the Ansi string which the calling program needs
* to free.
*
* Arguments:
* pwszUnicodeStr - pointer to Unicode string to convert
* ppszAnsiStr - pointer to pointer to Ansi string.
* bAllocate - If TRUE, allocate memory for Ansi string
*
* Returns:
* TRUE if successful, FALSE otherwise
*
******************************************************************************/
BOOL
ConvertToAnsi(
PCWSTR pwszUnicodeStr,
PSTR *ppszAnsiStr,
BOOL bAllocate
)
{
DWORD dwLen; // length of Ansi string
BOOL bUsedDefaultChar; // if default characters were used in
// converting Unicode to Ansi
dwLen = (lstrlenW(pwszUnicodeStr) + 1) * sizeof(char);
//
// Allocate memory for Ansi string
//
if (bAllocate)
{
*ppszAnsiStr = (PSTR)MemAlloc(dwLen);
if (! (*ppszAnsiStr))
{
WARNING((__TEXT("Error allocating memory for ANSI name\n")));
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
}
//
// Convert Unicode string to Ansi
//
if (! WideCharToMultiByte(CP_ACP, 0, pwszUnicodeStr, -1, *ppszAnsiStr,
dwLen, NULL, &bUsedDefaultChar) || bUsedDefaultChar)
{
WARNING((__TEXT("Error converting to Ansi name\n")));
if (bAllocate)
{
MemFree(*ppszAnsiStr);
*ppszAnsiStr = NULL;
}
return FALSE;
}
return TRUE;
}
/******************************************************************************
*
* ValidColorMatchingModule
*
* Function:
*
* Arguments:
* cmmID - ID identifing the CMM
* pCMMDll - pointer to CMM module path and file name
*
* Returns:
*
******************************************************************************/
BOOL
ValidColorMatchingModule(
DWORD cmmID,
PTSTR pCMMDll
)
{
HINSTANCE hInstance = NULL;
DWORD (WINAPI *pfnCMGetInfo)(DWORD);
FARPROC pfnCMRequired;
DWORD i;
BOOL rc = FALSE; // Assume failure
//
// Load the CMM
//
hInstance = LoadLibrary(pCMMDll);
if (!hInstance)
{
WARNING((__TEXT("Could not load CMM %s\n"), pCMMDll));
goto EndValidColorMatchingModule;
}
(PVOID) pfnCMGetInfo = (PVOID) GetProcAddress(hInstance, gszCMMReqFns[0]);
if (!pfnCMGetInfo)
{
ERR((__TEXT("CMM does not export CMGetInfo\n")));
goto EndValidColorMatchingModule;
}
//
// Check if the CMM is the right version and reports the same ID
//
if ((pfnCMGetInfo(CMM_VERSION) < 0x00050000) ||
(pfnCMGetInfo(CMM_IDENT) != cmmID))
{
ERR((__TEXT("CMM %s not correct version or reports incorrect ID\n"), pCMMDll));
goto EndValidColorMatchingModule;
}
//
// Check the remaining required functions is presented
//
for (i=1; i<NUM_REQ_FNS; i++)
{
pfnCMRequired = GetProcAddress(hInstance, gszCMMReqFns[i]);
if (!pfnCMRequired)
{
ERR((__TEXT("CMM %s does not export %s\n"), pCMMDll, gszCMMReqFns[i]));
goto EndValidColorMatchingModule;
}
}
rc = TRUE;
EndValidColorMatchingModule:
if (hInstance)
{
FreeLibrary(hInstance);
}
return rc;
}
/******************************************************************************
*
* GetColorMatchingModule
*
* Function:
* This functions returns a pointer to a CMMObject corresponding to
* the ID given. It first looks a the list of CMM objects loaded
* into memory, and if it doesn't find the right one, loads it.
*
* Arguments:
* cmmID - ID identifing the CMM
*
* Returns:
* Pointer to the CMM object if successful, NULL otherwise
*
******************************************************************************/
PCMMOBJ
GetColorMatchingModule(
DWORD cmmID
)
{
HANDLE hCMMObj;
PCMMOBJ pCMMObj = NULL;
FARPROC *ppTemp;
HINSTANCE hInstance = NULL;
HKEY hkCMM = NULL;
DWORD dwTaskID;
TCHAR szCMMID[5];
DWORD dwType, bufSize, i;
TCHAR szBuffer[MAX_PATH];
BOOL rc = FALSE; // Assume failure
dwTaskID = GetCurrentProcessId();
do {
// Attempt CMM discovery till we find a valid CMM or exhaust the
// valid possibilities.
// First search the already loaded modules for the requested CMM
EnterCriticalSection(&critsec); // Critical section
pCMMObj = gpCMMChain;
while (pCMMObj)
{
if ((pCMMObj->dwCMMID == cmmID) && (pCMMObj->dwTaskID == dwTaskID))
{
pCMMObj->objHdr.dwUseCount++;
break;
}
pCMMObj = pCMMObj->pNext;
}
LeaveCriticalSection(&critsec); // Critical section
if (pCMMObj)
{
// Exit point - we need to clean up anything we allocated
// in this loop.
if (hkCMM)
{
RegCloseKey(hkCMM);
}
// note: we don't cleanup hInstance here because there's no way
// to loop back with a loaded CMM
ASSERT(hInstance==NULL);
return pCMMObj;
}
// The CMM was not already loaded.
// Try load the registry CMM before attempting to load the default
// CMM. This will allow 3rd party vendors to add their own CMMs that
// redefine the system default CMM without having to circumvent SFP.
// To redefine the system default CMM, define 'Win ' in the registry.
// See gszICMatcher for the key to add.
// If we're iterating the discovery process and we've already opened
// the key, avoid leaking by opening it again.
if ((NULL == hkCMM) &&
(ERROR_SUCCESS !=
RegOpenKey(HKEY_LOCAL_MACHINE, gszICMatcher, &hkCMM)))
{
goto OpenDefaultCMM;
}
// Make a string with the CMM ID
#ifdef UNICODE
{
DWORD temp = FIX_ENDIAN(cmmID);
if (!MultiByteToWideChar(CP_ACP, 0, (PSTR)&temp, 4, szCMMID, 5))
{
WARNING((__TEXT("Could not convert cmmID %x to Unicode\n"), temp));
goto OpenDefaultCMM;
}
}
#else
for (i=0; i<4; i++)
{
szCMMID[i] = ((PSTR)&cmmID)[3-i];
}
#endif
szCMMID[4] = '\0';
// Get the file name of the CMM dll if registered.
bufSize = MAX_PATH;
if (ERROR_SUCCESS !=
RegQueryValueEx(
hkCMM, (PTSTR)szCMMID, 0,
&dwType, (BYTE *)szBuffer, &bufSize
))
{
WARNING((__TEXT("CMM %s not registered\n"), szCMMID));
goto OpenDefaultCMM;
}
// Attempt to load the CMM referenced in the registry.
hInstance = LoadLibrary(szBuffer);
OpenDefaultCMM:
if(!hInstance)
{
// If we failed to load the registry version, or the registry
// entry was not present, try load the default CMM. Note that
// the default CMM could be remapped in the registry.
if(CMM_WINDOWS_DEFAULT != cmmID)
{
// Try again with the default CMM
// It's possible that the default CMM was remapped, so we
// re-attempt the discovery process with the new cmmID.
cmmID = CMM_WINDOWS_DEFAULT;
}
else
{
// We're loading the default cmmID and the it was not remapped
// or we failed to load a remapped default properly using the
// registry name.
// Fall back to the system default CMM.
hInstance = LoadLibrary(gszDefaultCMM);
// There is no fallback for this case. If we can't get the
// system default CMM we must bail.
break;
}
}
} while(!hInstance);
if (!hInstance)
{
// There were no valid possibilities for the CMM.
// Note that we will only hit this case if we failed to load the
// preferred CMM _and_ failed to fall back to the system CMM.
WARNING((__TEXT("Could not load CMM %x\n"), cmmID));
goto EndGetColorMatchingModule;
}
//
// Allocate a CMM object
//
hCMMObj = AllocateHeapObject(OBJ_CMM);
if (!hCMMObj)
{
ERR((__TEXT("Could not allocate CMM object\n")));
goto EndGetColorMatchingModule;
}
pCMMObj = (PCMMOBJ)HDLTOPTR(hCMMObj);
ASSERT(pCMMObj != NULL);
//
// Fill in the CMM object
//
pCMMObj->objHdr.dwUseCount = 1;
pCMMObj->dwCMMID = cmmID;
pCMMObj->dwTaskID = dwTaskID;
pCMMObj->hCMM = hInstance;
ppTemp = (FARPROC *)&pCMMObj->fns.pCMGetInfo;
*ppTemp = GetProcAddress(hInstance, gszCMMReqFns[0]);
ppTemp++;
if (!pCMMObj->fns.pCMGetInfo)
{
ERR((__TEXT("CMM does not export CMGetInfo\n")));
goto EndGetColorMatchingModule;
}
//
// Check if the CMM is the right version and reports the same ID
//
if (pCMMObj->fns.pCMGetInfo(CMM_VERSION) < 0x00050000 ||
pCMMObj->fns.pCMGetInfo(CMM_IDENT) != cmmID)
{
ERR((__TEXT("CMM not correct version or reports incorrect ID\n")));
goto EndGetColorMatchingModule;
}
//
// Load the remaining required functions
//
for (i=1; i<NUM_REQ_FNS; i++)
{
*ppTemp = GetProcAddress(hInstance, gszCMMReqFns[i]);
if (!*ppTemp)
{
ERR((__TEXT("CMM %s does not export %s\n"), szCMMID, gszCMMReqFns[i]));
goto EndGetColorMatchingModule;
}
ppTemp++;
}
//
// Load the optional functions
//
for (i=0; i<NUM_OPT_FNS; i++)
{
*ppTemp = GetProcAddress(hInstance, gszCMMOptFns[i]);
//
// Even these functions are required for Windows default CMM
//
if (cmmID == CMM_WINDOWS_DEFAULT && !*ppTemp)
{
ERR((__TEXT("Windows default CMM does not export %s\n"), gszCMMOptFns[i]));
goto EndGetColorMatchingModule;
}
ppTemp++;
}
//
// Load the PS functions - these are optional even for the default CMM
//
for (i=0; i<NUM_PS_FNS; i++)
{
*ppTemp = GetProcAddress(hInstance, gszPSFns[i]);
ppTemp++;
}
//
// If any of the PS Level2 fns is not exported, do not use this CMM
// for any of the PS Level 2 functionality
//
if (!pCMMObj->fns.pCMGetPS2ColorSpaceArray ||
!pCMMObj->fns.pCMGetPS2ColorRenderingIntent ||
!pCMMObj->fns.pCMGetPS2ColorRenderingDictionary)
{
pCMMObj->fns.pCMGetPS2ColorSpaceArray = NULL;
pCMMObj->fns.pCMGetPS2ColorRenderingIntent = NULL;
pCMMObj->fns.pCMGetPS2ColorRenderingDictionary = NULL;
pCMMObj->dwFlags |= CMM_DONT_USE_PS2_FNS;
}
//
// Add the CMM object to the chain at the beginning
//
EnterCriticalSection(&critsec); // Critical section
pCMMObj->pNext = gpCMMChain;
gpCMMChain = pCMMObj;
LeaveCriticalSection(&critsec); // Critical section
rc = TRUE; // Success!
EndGetColorMatchingModule:
if (!rc)
{
if (pCMMObj)
{
pCMMObj->objHdr.dwUseCount--; // decrement before freeing
FreeHeapObject(hCMMObj);
pCMMObj = NULL;
}
if (hInstance)
{
FreeLibrary(hInstance);
}
}
if (hkCMM)
{
RegCloseKey(hkCMM);
}
return pCMMObj;
}
/******************************************************************************
*
* GetPreferredCMM
*
* Function:
* This functions returns a pointer to the app specified CMM to use
*
* Arguments:
* None
*
* Returns:
* Pointer to app specified CMM object on success, NULL otherwise
*
******************************************************************************/
PCMMOBJ GetPreferredCMM(
)
{
PCMMOBJ pCMMObj;
EnterCriticalSection(&critsec); // Critical section
pCMMObj = gpPreferredCMM;
if (pCMMObj)
{
//
// Increment use count
//
pCMMObj->objHdr.dwUseCount++;
}
LeaveCriticalSection(&critsec); // Critical section
return pCMMObj;
}
/******************************************************************************
*
* ReleaseColorMatchingModule
*
* Function:
* This functions releases a CMM object. If the ref count goes to
* zero, it unloads the CMM and frees all memory associated with it.
*
* Arguments:
* pCMMObj - pointer to CMM object to release
*
* Returns:
* No return value
*
******************************************************************************/
VOID
ReleaseColorMatchingModule(
PCMMOBJ pCMMObj
)
{
EnterCriticalSection(&critsec); // Critical section
ASSERT(pCMMObj->objHdr.dwUseCount > 0);
pCMMObj->objHdr.dwUseCount--;
if (pCMMObj->objHdr.dwUseCount == 0)
{
//
// Unloading the CMM everytime a transform is freed might not be
// very efficient. So for now, I am not going to unload it. When
// the app terminates, kernel should unload all dll's loaded by
// this app
//
}
LeaveCriticalSection(&critsec); // Critical section
return;
}
#if DBG
/******************************************************************************
*
* MyDebugPrint
*
* Function:
* This function takes a format string and paramters, composes a string
* and sends it out to the debug port. Available only in debug build.
*
* Arguments:
* pFormat - pointer to format string
* ....... - parameters based on the format string like printf()
*
* Returns:
* No return value
*
******************************************************************************/
VOID
MyDebugPrintA(
PSTR pFormat,
...
)
{
char szBuffer[256];
va_list arglist;
va_start(arglist, pFormat);
wvsprintfA(szBuffer, pFormat, arglist);
va_end(arglist);
OutputDebugStringA(szBuffer);
return;
}
VOID
MyDebugPrintW(
PWSTR pFormat,
...
)
{
WCHAR szBuffer[256];
va_list arglist;
va_start(arglist, pFormat);
wvsprintfW(szBuffer, pFormat, arglist);
va_end(arglist);
OutputDebugStringW(szBuffer);
return;
}
/******************************************************************************
*
* StripDirPrefixA
*
* Function:
* This function takes a path name and returns a pointer to the filename
* part. This is availabel only for the debug build.
*
* Arguments:
* pszPathName - path name of file (can be file name alone)
*
* Returns:
* A pointer to the file name
*
******************************************************************************/
PSTR
StripDirPrefixA(
PSTR pszPathName
)
{
DWORD dwLen = lstrlenA(pszPathName);
pszPathName += dwLen - 1; // go to the end
while (*pszPathName != '\\' && dwLen--)
{
pszPathName--;
}
return pszPathName + 1;
}
#endif