/*********************************************************************** * TranslateInfStringW (ADVPACK.@) * * Translates the value of a specified key in an inf file into the * current locale by expanding string macros. * * PARAMS * pszInfFilename [I] Filename of the inf file. * pszInstallSection [I] * pszTranslateSection [I] Inf section where the key exists. * pszTranslateKey [I] Key to translate. * pszBuffer [O] Contains the translated string on exit. * dwBufferSize [I] Size on input of pszBuffer. * pdwRequiredSize [O] Length of the translated key. * pvReserved [I] Reserved, must be NULL. * * RETURNS * Success: S_OK. * Failure: An hresult error code. */ HRESULT WINAPI TranslateInfStringW(LPCWSTR pszInfFilename, LPCWSTR pszInstallSection, LPCWSTR pszTranslateSection, LPCWSTR pszTranslateKey, LPWSTR pszBuffer, DWORD dwBufferSize, PDWORD pdwRequiredSize, PVOID pvReserved) { HINF hInf; HRESULT hret = S_OK; TRACE("(%s, %s, %s, %s, %p, %d, %p, %p)\n", debugstr_w(pszInfFilename), debugstr_w(pszInstallSection), debugstr_w(pszTranslateSection), debugstr_w(pszTranslateKey), pszBuffer, dwBufferSize,pdwRequiredSize, pvReserved); if (!pszInfFilename || !pszTranslateSection || !pszTranslateKey || !pdwRequiredSize) return E_INVALIDARG; hInf = SetupOpenInfFileW(pszInfFilename, NULL, INF_STYLE_WIN4, NULL); if (hInf == INVALID_HANDLE_VALUE) return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); set_ldids(hInf, pszInstallSection, NULL); if (!SetupGetLineTextW(NULL, hInf, pszTranslateSection, pszTranslateKey, pszBuffer, dwBufferSize, pdwRequiredSize)) { if (dwBufferSize < *pdwRequiredSize) hret = E_NOT_SUFFICIENT_BUFFER; else hret = SPAPI_E_LINE_NOT_FOUND; } SetupCloseInfFile(hInf); return hret; }
/*********************************************************************** * SetupQueryInfOriginalFileInformationW (SETUPAPI.@) */ BOOL WINAPI SetupQueryInfOriginalFileInformationW( PSP_INF_INFORMATION InfInformation, UINT InfIndex, PSP_ALTPLATFORM_INFO AlternativePlatformInfo, PSP_ORIGINAL_FILE_INFO_W OriginalFileInfo) { LPCWSTR inf_name; LPCWSTR inf_path; HINF hinf; static const WCHAR wszVersion[] = { 'V','e','r','s','i','o','n',0 }; static const WCHAR wszCatalogFile[] = { 'C','a','t','a','l','o','g','F','i','l','e',0 }; FIXME("(%p, %d, %p, %p): semi-stub\n", InfInformation, InfIndex, AlternativePlatformInfo, OriginalFileInfo); if (OriginalFileInfo->cbSize != sizeof(*OriginalFileInfo)) { WARN("incorrect OriginalFileInfo->cbSize of %d\n", OriginalFileInfo->cbSize); SetLastError(ERROR_INVALID_USER_BUFFER); return FALSE; } inf_path = (LPWSTR)InfInformation->VersionData; /* FIXME: we should get OriginalCatalogName from CatalogFile line in * the original inf file and cache it, but that would require building a * .pnf file. */ hinf = SetupOpenInfFileW(inf_path, NULL, INF_STYLE_WIN4, NULL); if (hinf == INVALID_HANDLE_VALUE) return FALSE; if (!SetupGetLineTextW(NULL, hinf, wszVersion, wszCatalogFile, OriginalFileInfo->OriginalCatalogName, sizeof(OriginalFileInfo->OriginalCatalogName)/sizeof(OriginalFileInfo->OriginalCatalogName[0]), NULL)) { OriginalFileInfo->OriginalCatalogName[0] = '\0'; } SetupCloseInfFile(hinf); /* FIXME: not quite correct as we just return the same file name as * destination (copied) inf file, not the source (original) inf file. * to fix it properly would require building a .pnf file */ /* file name is stored in VersionData field of InfInformation */ inf_name = strrchrW(inf_path, '\\'); if (inf_name) inf_name++; else inf_name = inf_path; strcpyW(OriginalFileInfo->OriginalInfName, inf_name); return TRUE; }
/* Advanced INF callbacks */ static HRESULT del_dirs_callback(HINF hinf, PCWSTR field, const void *arg) { INFCONTEXT context; HRESULT hr = S_OK; DWORD size; BOOL ok = SetupFindFirstLineW(hinf, field, NULL, &context); for (; ok; ok = SetupFindNextLine(&context, &context)) { WCHAR directory[MAX_INF_STRING_LENGTH]; if (!SetupGetLineTextW(&context, NULL, NULL, NULL, directory, MAX_INF_STRING_LENGTH, &size)) continue; if (DelNodeW(directory, ADN_DEL_IF_EMPTY) != S_OK) hr = E_FAIL; } return hr; }
static HRESULT run_setup_commands_callback(HINF hinf, PCWSTR field, const void *arg) { const ADVInfo *info = (const ADVInfo *)arg; INFCONTEXT context; HRESULT hr = S_OK; DWORD size; BOOL ok = SetupFindFirstLineW(hinf, field, NULL, &context); for (; ok; ok = SetupFindNextLine(&context, &context)) { WCHAR buffer[MAX_INF_STRING_LENGTH]; if (!SetupGetLineTextW(&context, NULL, NULL, NULL, buffer, MAX_INF_STRING_LENGTH, &size)) continue; if (launch_exe(buffer, info->working_dir, NULL) != S_OK) hr = E_FAIL; } return hr; }
/*********************************************************************** * TranslateInfStringExW (ADVPACK.@) * * Using a handle to an INF file opened with OpenINFEngine, translates * the value of a specified key in an inf file into the current locale * by expanding string macros. * * PARAMS * hInf [I] Handle to the INF file. * pszInfFilename [I] Filename of the INF file. * pszTranslateSection [I] Inf section where the key exists. * pszTranslateKey [I] Key to translate. * pszBuffer [O] Contains the translated string on exit. * dwBufferSize [I] Size on input of pszBuffer. * pdwRequiredSize [O] Length of the translated key. * pvReserved [I] Reserved. Must be NULL. * * RETURNS * Success: S_OK. * Failure: E_FAIL. * * NOTES * To use TranslateInfStringEx to translate an INF file continuously, * open the INF file with OpenINFEngine, call TranslateInfStringEx as * many times as needed, then release the handle with CloseINFEngine. * When translating more than one keys, this method is more efficient * than calling TranslateInfString, because the INF file is only * opened once. */ HRESULT WINAPI TranslateInfStringExW(HINF hInf, LPCWSTR pszInfFilename, LPCWSTR pszTranslateSection, LPCWSTR pszTranslateKey, LPWSTR pszBuffer, DWORD dwBufferSize, PDWORD pdwRequiredSize, PVOID pvReserved) { TRACE("(%p, %s, %s, %s, %p, %d, %p, %p)\n", hInf, debugstr_w(pszInfFilename), debugstr_w(pszTranslateSection), debugstr_w(pszTranslateKey), pszBuffer, dwBufferSize, pdwRequiredSize, pvReserved); if (!hInf || !pszInfFilename || !pszTranslateSection || !pszTranslateKey) return E_INVALIDARG; if (!SetupGetLineTextW(NULL, hInf, pszTranslateSection, pszTranslateKey, pszBuffer, dwBufferSize, pdwRequiredSize)) { if (dwBufferSize < *pdwRequiredSize) return E_NOT_SUFFICIENT_BUFFER; return SPAPI_E_LINE_NOT_FOUND; } return S_OK; }
static HRESULT per_user_install_callback(HINF hinf, PCWSTR field, const void *arg) { PERUSERSECTIONW per_user; INFCONTEXT context; DWORD size; static const WCHAR disp_name[] = {'D','i','s','p','l','a','y','N','a','m','e',0}; static const WCHAR version[] = {'V','e','r','s','i','o','n',0}; static const WCHAR is_installed[] = {'I','s','I','n','s','t','a','l','l','e','d',0}; static const WCHAR comp_id[] = {'C','o','m','p','o','n','e','n','t','I','D',0}; static const WCHAR guid[] = {'G','U','I','D',0}; static const WCHAR locale[] = {'L','o','c','a','l','e',0}; static const WCHAR stub_path[] = {'S','t','u','b','P','a','t','h',0}; per_user.bRollback = FALSE; per_user.dwIsInstalled = 0; SetupGetLineTextW(NULL, hinf, field, disp_name, per_user.szDispName, sizeof(per_user.szDispName) / sizeof(WCHAR), &size); SetupGetLineTextW(NULL, hinf, field, version, per_user.szVersion, sizeof(per_user.szVersion) / sizeof(WCHAR), &size); if (SetupFindFirstLineW(hinf, field, is_installed, &context)) { SetupGetIntField(&context, 1, (PINT)&per_user.dwIsInstalled); } SetupGetLineTextW(NULL, hinf, field, comp_id, per_user.szCompID, sizeof(per_user.szCompID) / sizeof(WCHAR), &size); SetupGetLineTextW(NULL, hinf, field, guid, per_user.szGUID, sizeof(per_user.szGUID) / sizeof(WCHAR), &size); SetupGetLineTextW(NULL, hinf, field, locale, per_user.szLocale, sizeof(per_user.szLocale) / sizeof(WCHAR), &size); SetupGetLineTextW(NULL, hinf, field, stub_path, per_user.szStub, sizeof(per_user.szStub) / sizeof(WCHAR), &size); return SetPerUserSecValuesW(&per_user); }
/*********************************************************************** * SetupCopyOEMInfW (SETUPAPI.@) */ BOOL WINAPI SetupCopyOEMInfW( PCWSTR source, PCWSTR location, DWORD media_type, DWORD style, PWSTR dest, DWORD buffer_size, PDWORD required_size, PWSTR *component ) { BOOL ret = FALSE; WCHAR target[MAX_PATH], catalog_file[MAX_PATH], *p; static const WCHAR inf[] = { '\\','i','n','f','\\',0 }; static const WCHAR wszVersion[] = { 'V','e','r','s','i','o','n',0 }; static const WCHAR wszCatalogFile[] = { 'C','a','t','a','l','o','g','F','i','l','e',0 }; DWORD size; HINF hinf; TRACE("%s, %s, %d, %d, %p, %d, %p, %p\n", debugstr_w(source), debugstr_w(location), media_type, style, dest, buffer_size, required_size, component); if (!source) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } /* check for a relative path */ if (!(*source == '\\' || (*source && source[1] == ':'))) { SetLastError(ERROR_FILE_NOT_FOUND); return FALSE; } if (!GetWindowsDirectoryW( target, sizeof(target)/sizeof(WCHAR) )) return FALSE; strcatW( target, inf ); if ((p = strrchrW( source, '\\' ))) strcatW( target, p + 1 ); /* does the file exist already? */ if ((GetFileAttributesW( target ) != INVALID_FILE_ATTRIBUTES) && !(style & SP_COPY_NOOVERWRITE)) { static const WCHAR oem[] = { 'o','e','m',0 }; unsigned int i; LARGE_INTEGER source_file_size; HANDLE source_file; source_file = CreateFileW( source, FILE_READ_DATA | FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL ); if (source_file == INVALID_HANDLE_VALUE) return FALSE; if (!GetFileSizeEx( source_file, &source_file_size )) { CloseHandle( source_file ); return FALSE; } p = strrchrW( target, '\\' ) + 1; memcpy( p, oem, sizeof(oem) ); p += sizeof(oem)/sizeof(oem[0]) - 1; /* generate OEMnnn.inf ending */ for (i = 0; i < OEM_INDEX_LIMIT; i++) { static const WCHAR format[] = { '%','u','.','i','n','f',0 }; HANDLE dest_file; LARGE_INTEGER dest_file_size; wsprintfW( p, format, i ); dest_file = CreateFileW( target, FILE_READ_DATA | FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL ); /* if we found a file name that doesn't exist then we're done */ if (dest_file == INVALID_HANDLE_VALUE) break; /* now check if the same inf file has already been copied to the inf * directory. if so, use that file and don't create a new one */ if (!GetFileSizeEx( dest_file, &dest_file_size ) || (dest_file_size.QuadPart != source_file_size.QuadPart) || compare_files( source_file, dest_file )) { CloseHandle( dest_file ); continue; } CloseHandle( dest_file ); break; } CloseHandle( source_file ); if (i == OEM_INDEX_LIMIT) { SetLastError( ERROR_FILENAME_EXCED_RANGE ); return FALSE; } } hinf = SetupOpenInfFileW( source, NULL, INF_STYLE_WIN4, NULL ); if (hinf == INVALID_HANDLE_VALUE) return FALSE; if (SetupGetLineTextW( NULL, hinf, wszVersion, wszCatalogFile, catalog_file, sizeof(catalog_file)/sizeof(catalog_file[0]), NULL )) { WCHAR source_cat[MAX_PATH]; strcpyW( source_cat, source ); p = strrchrW( source_cat, '\\' ); if (p) p++; else p = source_cat; strcpyW( p, catalog_file ); FIXME("install catalog file %s\n", debugstr_w( source_cat )); } SetupCloseInfFile( hinf ); if (!(ret = CopyFileW( source, target, (style & SP_COPY_NOOVERWRITE) != 0 ))) return ret; if (style & SP_COPY_DELETESOURCE) DeleteFileW( source ); size = strlenW( target ) + 1; if (dest) { if (buffer_size >= size) { strcpyW( dest, target ); } else { SetLastError( ERROR_INSUFFICIENT_BUFFER ); ret = FALSE; } } if (component) *component = p + 1; if (required_size) *required_size = size; if (ret) SetLastError(ERROR_SUCCESS); return ret; }
/* loads the LDIDs specified in the install section of an INF */ void set_ldids(HINF hInf, LPCWSTR pszInstallSection, LPCWSTR pszWorkingDir) { WCHAR field[MAX_FIELD_LENGTH]; WCHAR line[MAX_FIELD_LENGTH]; WCHAR dest[MAX_PATH]; INFCONTEXT context; DWORD size; int ldid; static const WCHAR source_dir[] = {'S','o','u','r','c','e','D','i','r',0}; static const WCHAR custDestW[] = { 'C','u','s','t','o','m','D','e','s','t','i','n','a','t','i','o','n',0 }; if (!SetupGetLineTextW(NULL, hInf, pszInstallSection, custDestW, field, MAX_FIELD_LENGTH, &size)) return; if (!SetupFindFirstLineW(hInf, field, NULL, &context)) return; do { LPWSTR value, ptr, key, key_copy = NULL; DWORD flags = 0; SetupGetLineTextW(&context, NULL, NULL, NULL, line, MAX_FIELD_LENGTH, &size); /* SetupGetLineTextW returns the value if there is only one key, but * returns the whole line if there is more than one key */ if (!(value = strchrW(line, '='))) { SetupGetStringFieldW(&context, 0, NULL, 0, &size); key = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)); key_copy = key; SetupGetStringFieldW(&context, 0, key, size, &size); value = line; } else { key = line; *(value++) = '\0'; } /* remove leading whitespace from the value */ while (*value == ' ') value++; /* Extract the flags */ ptr = strchrW(value, ','); if (ptr) { *ptr = '\0'; flags = atolW(ptr+1); } /* set dest to pszWorkingDir if key is SourceDir */ if (pszWorkingDir && !lstrcmpiW(value, source_dir)) lstrcpynW(dest, pszWorkingDir, MAX_PATH); else get_dest_dir(hInf, value, dest, MAX_PATH); /* If prompting required, provide dialog to request path */ if (flags & 0x04) FIXME("Need to support changing paths - default will be used\n"); /* set all ldids to dest */ while ((ptr = get_parameter(&key, ',', FALSE))) { ldid = atolW(ptr); SetupSetDirectoryIdW(hInf, ldid, dest); } HeapFree(GetProcessHeap(), 0, key_copy); } while (SetupFindNextLine(&context, &context)); }