Partial implementation of MsiGetFileVersionA/W.
diff --git a/dlls/msi/msi.c b/dlls/msi/msi.c
index 6af95f5..1f67146 100644
--- a/dlls/msi/msi.c
+++ b/dlls/msi/msi.c
@@ -35,6 +35,7 @@
#include "wincrypt.h"
#include "wine/unicode.h"
#include "objbase.h"
+#include "winver.h"
#include "initguid.h"
@@ -1332,6 +1333,103 @@
return INSTALLSTATE_UNKNOWN;
}
+UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf, DWORD* pcchVersionBuf, LPSTR lpLangBuf, DWORD* pcchLangBuf)
+{
+ UINT len;
+ UINT ret;
+ LPWSTR szwFilePath = NULL;
+ LPWSTR lpwVersionBuff = NULL;
+ LPWSTR lpwLangBuff = NULL;
+
+ if(szFilePath) {
+ len = MultiByteToWideChar( CP_ACP, 0, szFilePath, -1, NULL, 0 );
+ szwFilePath = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
+ if( !szwFilePath)
+ return ERROR_OUTOFMEMORY;
+ MultiByteToWideChar( CP_ACP, 0, szFilePath, -1, szwFilePath, len );
+ }
+
+ if(lpVersionBuf && pcchVersionBuf && *pcchVersionBuf) {
+ lpwVersionBuff = HeapAlloc(GetProcessHeap(), 0, *pcchVersionBuf * sizeof(WCHAR));
+ if( !lpwVersionBuff)
+ return ERROR_OUTOFMEMORY;
+ }
+
+ if(lpLangBuf && pcchLangBuf && *pcchLangBuf) {
+ lpwLangBuff = HeapAlloc(GetProcessHeap(), 0, *pcchVersionBuf * sizeof(WCHAR));
+ if( !lpwLangBuff)
+ return ERROR_OUTOFMEMORY;
+ }
+
+ ret = MsiGetFileVersionW(szwFilePath, lpwVersionBuff, pcchVersionBuf, lpwLangBuff, pcchLangBuf);
+
+ if(lpwVersionBuff)
+ WideCharToMultiByte(CP_ACP, 0, lpwVersionBuff, -1, lpVersionBuf, *pcchVersionBuf, NULL, NULL);
+ if(lpwLangBuff)
+ WideCharToMultiByte(CP_ACP, 0, lpwLangBuff, -1, lpLangBuf, *pcchLangBuf, NULL, NULL);
+
+ if(szwFilePath) HeapFree(GetProcessHeap(), 0, szwFilePath);
+ if(lpwVersionBuff) HeapFree(GetProcessHeap(), 0, lpwVersionBuff);
+ if(lpwLangBuff) HeapFree(GetProcessHeap(), 0, lpwLangBuff);
+
+ return ret;
+}
+
+UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf, DWORD* pcchVersionBuf, LPWSTR lpLangBuf, DWORD* pcchLangBuf)
+{
+ static const WCHAR szVersionResource[] = {'\\',0};
+ static const WCHAR szVersionFormat[] = {'%','d','.','%','d','.','%','d','.','%','d',0};
+ static const WCHAR szLangFormat[] = {'%','d',0};
+ UINT ret = 0;
+ DWORD dwVerLen;
+ LPVOID lpVer = NULL;
+ VS_FIXEDFILEINFO *ffi;
+ UINT puLen;
+ WCHAR tmp[32];
+
+ TRACE("(%s,%p,%ld,%p,%ld)\n", debugstr_w(szFilePath),
+ lpVersionBuf, pcchVersionBuf?*pcchVersionBuf:0,
+ lpLangBuf, pcchLangBuf?*pcchLangBuf:0);
+
+ dwVerLen = GetFileVersionInfoSizeW(szFilePath, NULL);
+ if(!dwVerLen)
+ return GetLastError();
+
+ lpVer = HeapAlloc(GetProcessHeap(), 0, dwVerLen);
+ if(!lpVer) {
+ ret = ERROR_OUTOFMEMORY;
+ goto end;
+ }
+
+ if(!GetFileVersionInfoW(szFilePath, 0, dwVerLen, lpVer)) {
+ ret = GetLastError();
+ goto end;
+ }
+ if(lpVersionBuf && pcchVersionBuf && *pcchVersionBuf) {
+ if(VerQueryValueW(lpVer, szVersionResource, (LPVOID*)&ffi, &puLen) && puLen > 0) {
+ wsprintfW(tmp, szVersionFormat, HIWORD(ffi->dwFileVersionMS), LOWORD(ffi->dwFileVersionMS), HIWORD(ffi->dwFileVersionLS), LOWORD(ffi->dwFileVersionLS));
+ lstrcpynW(lpVersionBuf, tmp, *pcchVersionBuf);
+ *pcchVersionBuf = strlenW(lpVersionBuf);
+ }
+ else {
+ *lpVersionBuf = 0;
+ *pcchVersionBuf = 0;
+ }
+ }
+
+ if(lpLangBuf && pcchLangBuf && *pcchLangBuf) {
+ DWORD lang = GetUserDefaultLangID();
+ FIXME("Retrieve language from file\n");
+ wsprintfW(tmp, szLangFormat, lang);
+ lstrcpynW(lpLangBuf, tmp, *pcchLangBuf);
+ *pcchLangBuf = strlenW(lpLangBuf);
+ }
+
+end:
+ if(lpVer) HeapFree(GetProcessHeap(), 0, lpVer);
+ return ret;
+}
+
/******************************************************************
* DllMain
diff --git a/dlls/msi/msi.spec b/dlls/msi/msi.spec
index bd8092d..0310438 100644
--- a/dlls/msi/msi.spec
+++ b/dlls/msi/msi.spec
@@ -191,8 +191,8 @@
191 stub MsiInvalidateFeatureCache
192 stub MsiUseFeatureExA
193 stub MsiUseFeatureExW
-194 stub MsiGetFileVersionA
-195 stub MsiGetFileVersionW
+194 stdcall MsiGetFileVersionA(str str ptr str ptr)
+195 stdcall MsiGetFileVersionW(wstr wstr ptr wstr ptr)
196 stdcall MsiLoadStringA(long long long long long)
197 stdcall MsiLoadStringW(long long long long long)
198 stdcall MsiMessageBoxA(long long long long long long)
diff --git a/dlls/msi/package.c b/dlls/msi/package.c
index d8ea714..03d34e0 100644
--- a/dlls/msi/package.c
+++ b/dlls/msi/package.c
@@ -719,12 +719,12 @@
if (NULL == szName) {
return ERROR_INVALID_PARAMETER;
}
-
- TRACE("%lu %s %lu\n", hInstall, debugstr_a(szName), *pchValueBuf);
-
if (NULL != szValueBuf && NULL == pchValueBuf) {
return ERROR_INVALID_PARAMETER;
}
+
+ TRACE("%lu %s %lu\n", hInstall, debugstr_a(szName), *pchValueBuf);
+
if( szName )
{
UINT len = MultiByteToWideChar( CP_ACP, 0, szName, -1, NULL, 0 );
diff --git a/include/msi.h b/include/msi.h
index f461e99..5d9a17b 100644
--- a/include/msi.h
+++ b/include/msi.h
@@ -246,6 +246,10 @@
INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature);
#define MsiQueryFeatureState WINELIB_NAME_AW(MsiQueryFeatureState)
+UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf, DWORD* pcchVersionBuf, LPSTR lpLangBuf, DWORD* pcchLangBuf);
+UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf, DWORD* pcchVersionBuf, LPWSTR lpLangBuf, DWORD* pcchLangBuf);
+#define MsiGetFileVersion WINELIB_NAME_AW(MsiGetFileVersion)
+
/**
* Non Unicode
*/