/****************************Module*Header******************************\ * Module Name: PROFMAN.C * * Module Descripton: Profile management functions. * * Warnings: * * Issues: * * Public Routines: * * Created: 2 May 1996 * Author: Srinivasan Chandrasekar [srinivac] * * Copyright (c) 1996, 1997 Microsoft Corporation \***********************************************************************/ #include "mscms.h" /* * Local functions */ ULONG InternalHandleColorProfiles(PTSTR, DEVTYPE, PTSTR*, DWORD, PPROFILECALLBACK, PVOID, PROFILEOP); BOOL InternalCreateNewColorProfileSet(PTSTR, DEVTYPE); BOOL GetPrinterModelName(PTSTR, PTSTR); BOOL AddOrRemovePrinterProfile(HKEY, PTSTR, PTSTR, BOOL); ULONG EnumerateProfiles(HKEY, PPROFILECALLBACK, PVOID); void GetManuAndModelIDs(PTSTR, PTSTR, PTSTR); BOOL AddOrRemoveProfileEntry(HKEY, PTSTR, BOOL); BOOL IsMatch(PSEARCHTYPE, PPROFILEHEADER); ULONG InternalSearchColorProfiles(PSEARCHTYPE, PPROFILECALLBACK, PVOID); BOOL InternalGetSystemColorProfile(DWORD, PTSTR, PDWORD); ULONG WINAPI fnCallback(PWSTR, PVOID); /****************************************************************************** * * AddColorProfiles * * Function: * These are the ANSI & Unicode wrappers for InternalAddColorProfiles. * Please see InternalAddColorProfiles for more details on this function. * * Arguments: * pDevicename - name identifying device * devType - type of device * papProfilenames - pointer to array of profiles to add * nCount - number of profiles in array * * Returns: * TRUE if successful, NULL otherwise * ******************************************************************************/ #ifdef UNICODE // Windows NT versions BOOL WINAPI AddColorProfilesA( PSTR pDevicename, DEVTYPE devType, PSTR *papProfilenames, DWORD nCount ) { PWSTR *pwszProfiles; DWORD i; BOOL rc; WCHAR wszDevicename[CCHDEVICENAME]; /* * Validate parameters before we touch them */ if (!papProfilenames || nCount <= 0 || IsBadReadPtr(papProfilenames, sizeof(PTSTR)*nCount)) { WARNING(("ICM: Invalid parameter to AddColorProfiles\n")); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } /* * Convert device name to Unicode */ if (!MultiByteToWideChar(CP_ACP, 0, pDevicename, -1, wszDevicename, CCHDEVICENAME)) { WARNING(("Error converting to Unicode device name\n")); return FALSE; } /* * Allocate memory for an array of pointers to Unicode strings and convert * incoming profile names to Unicode */ pwszProfiles = (PWSTR *)GlobalAllocPtr(GHND, nCount*sizeof(PWSTR)); if (!pwszProfiles) { WARNING(("Error allocating memory for Unicode profile names\n")); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } rc = TRUE; for (i=0; i 0) && (!pBuffer || IsBadWritePtr(pBuffer, *pcbSize) ) ) ) { WARNING(("ICM: Invalid parameter to GetSystemColorProfile\n")); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } /* * Allocate memory for receiving Unicode filename */ cbSize = *pcbSize * sizeof(WCHAR); if (*pcbSize > 0) { pwBuffer = (PWSTR)GlobalAllocPtr(GHND, cbSize); if (!pwBuffer) { WARNING(("ICM: Error allocating memory for Unicode string in GetSystemColorProfileA\n")); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } } rc = InternalGetSystemColorProfile(dwProfileID, pwBuffer, &cbSize); /* * Convert Unicode back to ANSI. It might not work, but this is the best * we can do. */ if (rc && pBuffer) { if (!WideCharToMultiByte(CP_ACP, 0, pwBuffer, -1, pBuffer, *pcbSize, NULL, NULL)) { WARNING(("Error converting from Unicode to ANSI in GetSystemColorProfile\n")); rc = FALSE; } } if (pwBuffer) { GlobalFreePtr(pwBuffer); } return rc; } BOOL WINAPI GetSystemColorProfileW( DWORD dwProfileID, PWSTR pBuffer, PDWORD pcbSize ) { /* * Internal function is Unicode in Windows NT, call it directly. */ return InternalGetSystemColorProfile(dwProfileID, pBuffer, pcbSize); } #else // Windows 95 versions BOOL WINAPI GetSystemColorProfileA( DWORD dwProfileID, PSTR pBuffer, PDWORD pcbSize ) { /* * Internal function is ANSI in Windows 95, call it directly. */ return InternalGetSystemColorProfile(dwProfileID, pBuffer, pcbSize); } BOOL WINAPI GetSystemColorProfileW( DWORD dwProfileID, PWSTR pBuffer, PDWORD pcbSize ) { /* * Unicode version not supported under Windows 95 */ SetLastError(ERROR_NOT_SUPPORTED); return FALSE; } #endif /*========================================================================*/ /****************************************************************************** * * InternalHandleColorProfiles * * Function: * This functions adds, removes or enumerates color profiles in the system * registry for the specified device. * * Arguments: * pDevicename - name identifying device * devType - type of device * papProfilenames - pointer to array of profiles to add/remove * nCount - number of profiles in array * pCallbackFunc - callback function for profile enumeration * pClientData - app supplied data for callback function * mode - specifies if add, remove or enumeration is needed * * Returns: * Non zero value if successful, zero otherwise * ******************************************************************************/ ULONG InternalHandleColorProfiles( PTSTR pDevicename, DEVTYPE devType, PTSTR *papProfilenames, DWORD nCount, PPROFILECALLBACK pCallbackFunc, PVOID pClientData, PROFILEOP mode ) { HKEY hkICM, hkdev, hkManu, hkModel, hkBranch; HANDLE hPrinter; DWORD i, dwType, cbSize; BOOL rc = FALSE; TCHAR szModelname[CCHDEVICENAME], manu[5], model[5], szValue[32]; #ifdef DBG if (mode == ADDPROFILES) { TRACEAPI(("AddColorProfiles\n")); } else if (mode == REMOVEPROFILES) { TRACEAPI(("RemoveColorProfiles\n")); } else { TRACEAPI(("EnumColorProfiles\n")); } #endif /* * Validate parameters */ if (((mode == ENUMPROFILES) && (!pDevicename || !pCallbackFunc ) ) || ((mode != ENUMPROFILES) && (!pDevicename || !papProfilenames || nCount == 0 || IsBadReadPtr(papProfilenames, sizeof(PTSTR)*nCount) ) ) ) { WARNING(("ICM: Invalid parameter to HandleColorProfiles\n")); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } /* * Open the registry */ if (RegCreateKey(HKEY_LOCAL_MACHINE, gszICMRegPath, &hkICM) != ERROR_SUCCESS) { ERR(("ICM: Cannot open ICM branch of registry in HandleColorProfiles\n")); return FALSE; } hkdev = hkManu = hkModel = hkBranch = NULL; switch (devType) { case DEV_SCANNER: break; case DEV_DISPLAY: break; case DEV_PRINTER: /* * Get the printer's model name */ if (!GetPrinterModelName(pDevicename, szModelname)) { WARNING(("ICM: Invalid printer name to HandleColorProfiles\n")); SetLastError(ERROR_INVALID_NAME); goto EndHandleColorProfiles; } /* * Open the registry key for printer */ RegCreateKey(hkICM, gszPrinter, &hkdev); /* * Generate manufacturer & model IDs from the printer device name */ GetManuAndModelIDs(szModelname, manu, model); /* * Create keys for manufacturer and model */ RegCreateKey(hkdev, manu, &hkManu); RegCreateKey(hkManu, model, &hkModel); /* * Check if printer shares profiles or has a unique bucket */ OpenPrinter(pDevicename, &hPrinter, NULL); if (hPrinter) { if (GetPrinterData(hPrinter, gszICMKey, &dwType, (PBYTE)szValue, 32, &cbSize) != ERROR_SUCCESS) { lstrcpy(szValue, gszDefault); // shares profiles } ClosePrinter(hPrinter); } if (RegCreateKey(hkModel, szValue, &hkBranch) != ERROR_SUCCESS) goto EndHandleColorProfiles; if (mode == ENUMPROFILES) { rc = EnumerateProfiles(hkBranch, pCallbackFunc, pClientData); } else { rc = TRUE; for (i=0; i DMMEDIA_TRANSPARENCY) val = 0; pStr = gMediaType[val]; } else { pStr = szValue; } } else { pStr = gMediaType[0]; } RegCreateKey(hkPrtr, pStr, &hkMedia); /* * Get the dither type tag from the profile */ cbSize = 4; if (GetColorProfileElement(hProfile, 'MS02', 0, &cbSize, szValue, &bRef)) { // BUGBUG - debug this val = *((DWORD *)szValue); if (val < DMDITHER_USER) { if (val > DMDITHER_GRAYSCALE) val = 0; pStr = gDitherType[val]; } else { pStr = szValue; } } else { pStr = gDitherType[0]; } RegCreateKey(hkMedia, pStr, &hkDither); /* * Get the resolution tag from the profile */ cbSize = 8; if (GetColorProfileElement(hProfile, 'MS03', 0, &cbSize, szValue, &bRef)) { #if 0 itoa(SwapBytes(pTag[2]), (DWORD *)&NameOfManu[0]); NameOfManu[5] = 'x'; itoa(SwapBytes(pTag[3]), (DWORD *)&NameOfManu[6]); NameOfManu[11] = 0; val = *((DWORD *)szValue; val2 = *((DWORD *)szValue + 1); itoa(val, szValue, 10); szValue[5] = 'x'; itoa(val2, &szValue[6], 10); #endif pStr = szValue; } else pStr = gResolution[0]; RegCreateKey(hkDither, pStr, &hkRes); /* * Get the device color space from profile */ for (i=0; i<4; i++) { // BUGBUG: Fix this for BIG_ENDIAN machines szValue[i] = ((char*)&header.phDataColorSpace)[3-i]; } szValue[4] = 0; RegCreateKey(hkRes, szValue, &hkLast); /* * Add or remove profile */ rc = AddOrRemoveProfileEntry(hkLast, pProfile, bAdd); EndAddOrRemovePrinterProfile: if (hProfile) CloseColorProfile(hProfile); if (hkMedia) RegCloseKey(hkMedia); if (hkDither) RegCloseKey(hkDither); if (hkRes) RegCloseKey(hkRes); if (hkLast) RegCloseKey(hkLast); return rc; } /****************************************************************************** * * GetManuAndModelIDs * * Function: * This functions creates manu and model ID from the model name of * the printer. This algorithm maintains backward compatibility with * Windows 95. * * Arguments: * pDevicename - model name of printer * pManu - buffer to get the manu ID * pModel - buffer to get the model ID * * Returns: * Nothing * ******************************************************************************/ void GetManuAndModelIDs( PTSTR pDevicename, PTSTR pManu, PTSTR pModel ) { DWORD dwCheckSum, dwSize; int i; WORD wCRC16a[16]={ 0000000, 0140301, 0140601, 0000500, 0141401, 0001700, 0001200, 0141101, 0143001, 0003300, 0003600, 0143501, 0002400, 0142701, 0142201, 0002100, }; WORD wCRC16b[16]={ 0000000, 0146001, 0154001, 0012000, 0170001, 0036000, 0024000, 0162001, 0120001, 0066000, 0074000, 0132001, 0050000, 0116001, 0104001, 0043000, }; TCHAR *pByte; TCHAR temp; BYTE bTmp; /* * Define the manufacturer to be the first 4 characters of the * device name. A space or a hypen end the string, and the * remaining part of the string is filled with spaces. We need * this computed ID to be 4 chars so that there is no chance of * collisions with real EISA IDs. */ pByte = pDevicename; for (i=0; i<4; i++, pByte++) { if (*pByte == ' ' || *pByte == '-') { for (; i<4; i++) { pManu[i] = ' '; } } else { temp = *pByte; if (temp >= 'a' && temp <= 'z') temp = temp + 'A' - 'a'; pManu[i] = temp; } } pManu[4] = '\0'; /* * Define the model to be a CRC of the complete DriverDesc * string. We use the same method that the PnP LPT * enumerator uses to create unique ID's. It turns out * that this is really not unique, but it gets us close * enough. */ dwCheckSum = 0; dwSize = lstrlen(pDevicename); for (pByte=pDevicename; dwSize; dwSize--, pByte++) { bTmp = (BYTE)(((WORD)*pByte)^((WORD)dwCheckSum)); // Xor CRC with new char dwCheckSum = (dwCheckSum >> 8) ^ wCRC16a[bTmp & 0x0F] ^ wCRC16b[bTmp >> 4]; } wsprintf(pModel, __TEXT("%X"), dwCheckSum); return; } /****************************************************************************** * * AddOrRemoveProfileEntry * * Function: * This functions adds or removes the given profile into under the * registry key that is given. It searches from profile00 to * profile99. * * Arguments: * hKey - open registry key under which to add the profile * pProfilename - file name of the profile * * Returns: * TRUE if successful, FALSE otherwise * ******************************************************************************/ BOOL AddOrRemoveProfileEntry( HKEY hKey, PTSTR pProfilename, BOOL bAdd ) { DWORD dwType, dwSize; int i, j; TCHAR szName[10], szValue[MAX_PATH]; BOOL rc = TRUE; /* * Go through list of profiles and enter this profile in the * first available spot if adding, else if found remove it */ lstrcpy(szName, __TEXT("profile")); szName[9] = 0; for (i=0 ;i<10 ; i++) { szName[7] = '0' + i; for (j=0 ;j<10 ; j++) { dwSize = MAX_PATH; szName[8] = '0' + j; if (RegQueryValueEx(hKey, szName, 0, &dwType, (BYTE *)szValue, &dwSize) == ERROR_SUCCESS) { if (!lstrcmpi(szValue, pProfilename)) { if (!bAdd) RegDeleteValue(hKey, szName); return TRUE; // profile already exists or we just removed it } } else { if (bAdd) { if (RegSetValueEx(hKey, szName, 0, REG_SZ, (BYTE *)pProfilename, (lstrlen(pProfilename)+1)*sizeof(TCHAR)) != ERROR_SUCCESS) { rc = FALSE; } return rc; } } } } return FALSE; // no more empty slots } /****************************************************************************** * * GetPrinterModelName * * Function: * This functions takes a printer friendly name and returns the model * name. * * Arguments: * pFriendlyName - friendly name of the printer * pModelName - buffer that gets the model name * * Returns: * TRUE if successful, FALSE otherwise * ******************************************************************************/ BOOL GetPrinterModelName( PTSTR pFriendlyName, PTSTR pModelName ) { TCHAR szBuf[MAX_PATH]; HKEY hKey; DWORD dwNeeded, dwType; lstrcpy(szBuf, gszRegPrinter); lstrcat(szBuf, pFriendlyName); if (RegOpenKey(HKEY_LOCAL_MACHINE, szBuf, &hKey) == ERROR_SUCCESS) { dwNeeded = CCHDEVICENAME * sizeof(TCHAR); RegQueryValueEx(hKey, gszPrinterDriver, NULL, &dwType, (BYTE *)pModelName, &dwNeeded); RegCloseKey(hKey); return TRUE; } else return FALSE; } /****************************************************************************** * * InternalCreateNewColorProfileSet * * Function: * This function creates a new name for the profile bucket for the * given device. Future AddColorProfiles() to this device will be added * under this bucket. * * Arguments: * pDevicename - name identifying device * devType - type of device * * Returns: * TRUE if successful, FALSE otherwise * ******************************************************************************/ BOOL InternalCreateNewColorProfileSet( PTSTR pDevicename, DEVTYPE devType ) { HANDLE hPrinter; HKEY hkICM, hkdev, hkmanu, hkmodel, hktemp; BOOL rc = FALSE; TCHAR szModelname[CCHDEVICENAME], szValue[5]; TCHAR manu[5], model[5]; TRACEAPI(("CreateNewColorProfileSet\n")); /* * Validate parameters */ if (!pDevicename) { WARNING(("ICM: Invalid parameter to CreateNewColorProfileSet\n")); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } /* * Open the registry */ if (RegCreateKey(HKEY_LOCAL_MACHINE, gszICMRegPath, &hkICM) != ERROR_SUCCESS) { ERR(("ICM: Cannot open ICM branch of registry in CreateNewColorProfileSet\n")); return FALSE; } switch (devType) { case DEV_SCANNER: break; case DEV_DISPLAY: break; case DEV_PRINTER: /* * Get the printer's model name */ if (!GetPrinterModelName(pDevicename, szModelname)) { WARNING(("ICM: Invalid printer name to AddColorProfiles\n")); SetLastError(ERROR_INVALID_NAME); goto EndCreateNewColorProfileSet; } /* * Open the registry key for printer */ RegCreateKey(hkICM, gszPrinter, &hkdev); /* * Create unique bucket for printer */ OpenPrinter(pDevicename, &hPrinter, NULL); if (hPrinter) { HANDLE hMutex; hkmanu = hkmodel = 0; GetManuAndModelIDs(szModelname, manu, model); RegOpenKey(hkdev, manu, &hkmanu); RegOpenKey(hkmanu, model, &hkmodel); hktemp = 0; /* * Use a named mutex object to prevent multiple threads/processes * from creating the same bucket name */ hMutex = CreateMutex(NULL, TRUE, gszMutexName); // Create and own mutex if (GetLastError() == ERROR_ALREADY_EXISTS) { /* * Mutex already exists, so we have to explicitely ask for ownership */ WaitForSingleObject(hMutex, INFINITE); } do { if (hktemp) RegCloseKey(hktemp); wsprintf(szValue, __TEXT("%X"), GetTickCount()); } while (RegOpenKey(hkmodel, szValue, &hktemp) == ERROR_SUCCESS); /* * Release and close the mutex handle */ ReleaseMutex(hMutex); CloseHandle(hMutex); RegCloseKey(hkmanu); RegCloseKey(hkmodel); if (SetPrinterData(hPrinter, gszICMKey, REG_SZ, (PBYTE)szValue, (lstrlen(szValue) + 1)*sizeof(TCHAR)) == ERROR_SUCCESS) { rc = TRUE; } ClosePrinter(hPrinter); } RegCloseKey(hkdev); break; default: break; } EndCreateNewColorProfileSet: if (hkICM) { RegCloseKey(hkICM); } return rc; } #define SET(ps, bit) (ps->stFields & (bit)) BOOL IsMatch( PSEARCHTYPE pSearch, PPROFILEHEADER pHeader ) { return ((!SET(pSearch, ST_CMMTYPE) || (pSearch->stCMMType == pHeader->phCMMType)) && (!SET(pSearch, ST_CLASS) || (pSearch->stClass == pHeader->phClass)) && (!SET(pSearch, ST_DATACOLORSPACE) || (pSearch->stDataColorSpace == pHeader->phDataColorSpace)) && (!SET(pSearch, ST_CONNECTIONSPACE) || (pSearch->stConnectionSpace == pHeader->phConnectionSpace)) && (!SET(pSearch, ST_SIGNATURE) || (pSearch->stSignature == pHeader->phSignature)) && (!SET(pSearch, ST_PLATFORM) || (pSearch->stPlatform == pHeader->phPlatform)) && (!SET(pSearch, ST_PROFILEFLAGS) || (pSearch->stProfileFlags == pHeader->phProfileFlags)) && (!SET(pSearch, ST_MANUFACTURER) || (pSearch->stManufacturer == pHeader->phManufacturer)) && (!SET(pSearch, ST_MODEL) || (pSearch->stModel == pHeader->phModel)) && (!SET(pSearch, ST_ATTRIBUTES) || (pSearch->stAttributes[0] == pHeader->phAttributes[0] && pSearch->stAttributes[1] == pHeader->phAttributes[1])) && (!SET(pSearch, ST_RENDERINGINTENT) || (pSearch->stRenderingIntent == pHeader->phRenderingIntent)) && (!SET(pSearch, ST_CREATOR) || (pSearch->stCreator == pHeader->phCreator)) ); } /****************************************************************************** * * InternalSearchColorProfiles * * Function: * This function searches through all the profiles in the COLOR * directory, and calls the callback function once for each profile * that satisfies the search criteria * * Arguments: * pSearchType - pointer to structure specifying the search criteria * pCallbackFunc - function that is called for each profile * pClientData - app suplied data for callback function * * Returns: * Last value returned by callback funtion. * ******************************************************************************/ ULONG InternalSearchColorProfiles( PSEARCHTYPE pSearchType, PPROFILECALLBACK pCallbackFunc, PVOID pClientData ) { WIN32_FIND_DATA wfd; PROFILEHEADER header; PROFILE profile; HANDLE hFindFile; HPROFILE hProfile; ULONG rc = 0; DWORD index; TCHAR szPath[MAX_PATH]; TRACEAPI(("SearchColorProfiles\n")); /* * Validate parameters */ if (!pSearchType || IsBadReadPtr(pSearchType, sizeof(SEARCHTYPE)) || !pCallbackFunc) { WARNING(("ICM: Invalid parameter to SearchColorProfiles\n")); SetLastError(ERROR_INVALID_PARAMETER); return 0; } /* * Create a buffer with "%SYSTEMDIR%\COLOR\*.*" to search for profiles */ GetSystemDirectory(szPath, MAX_PATH); if (szPath[lstrlen(szPath)-1] != '\\') lstrcat(szPath, gszBackslash); lstrcat(szPath, gszColorDir); lstrcat(szPath, gszBackslash); index = lstrlen(szPath); lstrcat(szPath, gszStarDotStar); hFindFile = FindFirstFile(szPath, &wfd); if (hFindFile != INVALID_HANDLE_VALUE) { do { szPath[index] = 0; lstrcat(szPath, wfd.cFileName); // append filename to COLOR directory profile.dwType = PROFILE_FILENAME; profile.pProfileData = szPath; profile.cbDataSize = lstrlen(profile.pProfileData) * sizeof(TCHAR); hProfile = OpenColorProfile(&profile, 0, OPEN_EXISTING); if (hProfile) { GetColorProfileHeader(hProfile, &header); CloseColorProfile(hProfile); if (IsMatch(pSearchType, &header)) { rc = (*pCallbackFunc)(profile.pProfileData, pClientData); if (rc == 0) break; } } } while (FindNextFile(hFindFile, &wfd)); FindClose(hFindFile); } return rc; } /****************************************************************************** * * InternalGetSystemColorProfile * * Function: * This function returns the system color profile of the type requested. * Currently only sRGB is registered (it is also hardcoded for efficiency). * Other types can be registered in the registry. We are not giving an * API to do that yet because having multiple color spaces is not * preferred, but the potential exists and a mechanism is provided. * * Arguments: * dwProfileID - specifies the profile identifier eg. 'sRGB' * pBuffer - buffer to recieve the profile filename * pcbSize - pointer to dword that has size of buffer. On return * it has size of filename, * * Returns: * TRUE if successful, FALSE otherwise. * * Comments: * If pBuffer is NULL, or it is not big enough, pcbSize is filled with * size needed, and function returns FALSE. GetLastError() returns * ERROR_MORE_DATA * ******************************************************************************/ BOOL InternalGetSystemColorProfile( DWORD dwProfileID, PTSTR pBuffer, PDWORD pcbSize ) { DWORD cbSize; HKEY hkICM, hkRegProf; BOOL rc = FALSE; TCHAR szPath[MAX_PATH]; TRACEAPI(("GetSystemColorProfile\n")); /* * Validate parameters */ if (!pcbSize || IsBadReadPtr(pcbSize, sizeof(DWORD)) || ((*pcbSize > 0) && (!pBuffer || IsBadWritePtr(pBuffer, *pcbSize) ) ) ) { WARNING(("ICM: Invalid parameter to GetSystemColorProfile\n")); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } /* * Check if sRGB is being requested */ if (dwProfileID == LCS_sRGB) { GetSystemDirectory(szPath, MAX_PATH); if (szPath[lstrlen(szPath)-1] != '\\') lstrcat(szPath, gszBackslash); lstrcat(szPath, gszColorDir); lstrcat(szPath, gszBackslash); lstrcat(szPath, gszsRGBProfile); cbSize = (lstrlen(szPath) + 1)*sizeof(TCHAR); rc = TRUE; if (*pcbSize < cbSize && pBuffer) { WARNING(("ICM: Buffer too small in GetSystemColorProfile\n")); SetLastError(ERROR_MORE_DATA); rc = FALSE; } if (*pcbSize >= cbSize) { lstrcpy(pBuffer, szPath); } *pcbSize = cbSize; } else { DWORD i; TCHAR szProfileID[5]; /* * Look in the registry to check if this type is registered */ RegCreateKey(HKEY_LOCAL_MACHINE, gszICMRegPath, &hkICM); if (RegOpenKey(hkICM, gszRegisteredProfiles, &hkRegProf) == ERROR_SUCCESS) { for (i=0; i<4; i++) { szProfileID[i] = ((char*)&dwProfileID)[3-i]; } if (RegQueryValueEx(hkRegProf, szProfileID, NULL, NULL, (PBYTE)pBuffer, pcbSize) == ERROR_SUCCESS) { rc = TRUE; } RegCloseKey(hkRegProf); } RegCloseKey(hkICM); } return rc; } /****************************************************************************** * * fnCallback * * Function: * This function is used to by the Unicode DLL to call an app supplied * ANSI callback function. It converts Unicode strings to ANSI. * * Arguments: * pwProfile - Unicode profile string that needs to be converted * pData - private data that has app callback and data * * Returns: * Value returned by app callback funtion. * ******************************************************************************/ ULONG WINAPI fnCallback( PWSTR pwProfile, PVOID pData ) { PPROFILECALLBACK pTemp; char szProfile[MAX_PATH]; /* * Convert Unicode back to ANSI. It might not work, but this is the best * we can do. */ if (!WideCharToMultiByte(CP_ACP, 0, pwProfile, -1, szProfile, MAX_PATH, NULL, NULL)) { WARNING(("Error converting from Unicode to ANSI in fnCallback\n")); return 1; // To continue enumeration } pTemp = (PPROFILECALLBACK)((PCALLBACKDATA)pData)->pCallbackFunc; return (*pTemp)((PTSTR)szProfile, ((PCALLBACKDATA)pData)->pClientData); } /****************************************************************************** * * EnumerateProfiles * * Function: * This functions all profiles registered under the given key * * Arguments: * hKey - key under which to enumerate profile * pCallbackFunc - app supplied funtion to call back for each profile * pClientData - data for callback function * * Returns: * Last value returned by the callback function * ******************************************************************************/ TCHAR szValue[MAX_PATH]; ULONG EnumerateProfiles( HKEY hKey, PPROFILECALLBACK pCallbackFunc, PVOID pClientData ) { HKEY hSubkey; DWORD nSubkeys, nValues, i, cbName, cbValue; ULONG rc; TCHAR szName[32]; if (RegQueryInfoKey(hKey, NULL, NULL, 0, &nSubkeys, NULL, NULL, &nValues, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) { return 0; } if (nSubkeys > 0) { /* * This is not the leaf node, recurse */ for (i=0; i