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
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
|
|
|