382 lines
10 KiB
C
382 lines
10 KiB
C
|
#include <nt.h>
|
|||
|
#include <ntrtl.h>
|
|||
|
#include <nturtl.h>
|
|||
|
#include "verpriv.h"
|
|||
|
|
|||
|
#define DWORDUP(x) (((x)+3) & ~3)
|
|||
|
DWORD
|
|||
|
APIENTRY
|
|||
|
VerFindFileA(
|
|||
|
DWORD wFlags,
|
|||
|
LPSTR lpszFileName,
|
|||
|
LPSTR lpszWinDir,
|
|||
|
LPSTR lpszAppDir,
|
|||
|
LPSTR lpszCurDir,
|
|||
|
PUINT puCurDirLen,
|
|||
|
LPSTR lpszDestDir,
|
|||
|
PUINT puDestDirLen
|
|||
|
)
|
|||
|
{
|
|||
|
UNICODE_STRING FileName;
|
|||
|
UNICODE_STRING WinDir;
|
|||
|
UNICODE_STRING AppDir;
|
|||
|
UNICODE_STRING CurDir;
|
|||
|
UNICODE_STRING DestDir;
|
|||
|
ANSI_STRING AnsiString;
|
|||
|
NTSTATUS Status;
|
|||
|
DWORD CurDirLen = (*puCurDirLen) ? (*puCurDirLen) : 1;
|
|||
|
DWORD DestDirLen = (*puDestDirLen) ? (*puDestDirLen) : 1;
|
|||
|
|
|||
|
CurDirLen = min(MAX_PATH, CurDirLen);
|
|||
|
DestDirLen = min(MAX_PATH, DestDirLen);
|
|||
|
|
|||
|
RtlInitAnsiString(&AnsiString, lpszFileName);
|
|||
|
Status = RtlAnsiStringToUnicodeString(&FileName, &AnsiString, TRUE);
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
SetLastError(Status);
|
|||
|
return VFF_BUFFTOOSMALL;
|
|||
|
}
|
|||
|
RtlInitAnsiString(&AnsiString, lpszWinDir);
|
|||
|
Status = RtlAnsiStringToUnicodeString(&WinDir, &AnsiString, TRUE);
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
RtlFreeUnicodeString(&FileName);
|
|||
|
SetLastError(Status);
|
|||
|
return VFF_BUFFTOOSMALL;
|
|||
|
}
|
|||
|
RtlInitAnsiString(&AnsiString, lpszAppDir);
|
|||
|
Status = RtlAnsiStringToUnicodeString(&AppDir, &AnsiString, TRUE);
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
RtlFreeUnicodeString(&FileName);
|
|||
|
RtlFreeUnicodeString(&WinDir);
|
|||
|
SetLastError(Status);
|
|||
|
return VFF_BUFFTOOSMALL;
|
|||
|
}
|
|||
|
CurDir.MaximumLength = (USHORT)CurDirLen * sizeof(WCHAR);
|
|||
|
CurDir.Buffer = RtlAllocateHeap(RtlProcessHeap(), 0, CurDir.MaximumLength);
|
|||
|
if (CurDir.Buffer == NULL) {
|
|||
|
RtlFreeUnicodeString(&FileName);
|
|||
|
RtlFreeUnicodeString(&WinDir);
|
|||
|
RtlFreeUnicodeString(&AppDir);
|
|||
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|||
|
return VFF_BUFFTOOSMALL;
|
|||
|
}
|
|||
|
DestDir.MaximumLength = (USHORT)DestDirLen * sizeof(WCHAR);
|
|||
|
DestDir.Buffer = RtlAllocateHeap(RtlProcessHeap(), 0, DestDir.MaximumLength);
|
|||
|
if (DestDir.Buffer == NULL) {
|
|||
|
RtlFreeUnicodeString(&FileName);
|
|||
|
RtlFreeUnicodeString(&WinDir);
|
|||
|
RtlFreeUnicodeString(&AppDir);
|
|||
|
RtlFreeUnicodeString(&CurDir);
|
|||
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|||
|
return VFF_BUFFTOOSMALL;
|
|||
|
}
|
|||
|
Status = VerFindFileW(wFlags,
|
|||
|
FileName.Buffer,
|
|||
|
WinDir.Buffer,
|
|||
|
AppDir.Buffer,
|
|||
|
CurDir.Buffer, &CurDirLen,
|
|||
|
DestDir.Buffer, &DestDirLen);
|
|||
|
|
|||
|
if (Status & VFF_BUFFTOOSMALL) {
|
|||
|
*lpszCurDir = 0;
|
|||
|
*puCurDirLen = CurDirLen;
|
|||
|
*lpszDestDir = 0;
|
|||
|
*puDestDirLen = DestDirLen;
|
|||
|
} else {
|
|||
|
|
|||
|
CurDir.Length = (USHORT)(sizeof(WCHAR)*CurDirLen);
|
|||
|
DestDir.Length = (USHORT)(sizeof(WCHAR)*DestDirLen);
|
|||
|
|
|||
|
AnsiString.Buffer = lpszCurDir;
|
|||
|
AnsiString.MaximumLength = (USHORT)*puCurDirLen;
|
|||
|
RtlUnicodeStringToAnsiString(&AnsiString, &CurDir, FALSE);
|
|||
|
*puCurDirLen = AnsiString.Length;
|
|||
|
|
|||
|
AnsiString.Buffer = lpszDestDir;
|
|||
|
AnsiString.MaximumLength = (USHORT)*puDestDirLen;
|
|||
|
RtlUnicodeStringToAnsiString(&AnsiString, &DestDir, FALSE);
|
|||
|
*puDestDirLen = AnsiString.Length;
|
|||
|
}
|
|||
|
|
|||
|
RtlFreeUnicodeString(&FileName);
|
|||
|
RtlFreeUnicodeString(&WinDir);
|
|||
|
RtlFreeUnicodeString(&AppDir);
|
|||
|
RtlFreeUnicodeString(&CurDir);
|
|||
|
RtlFreeUnicodeString(&DestDir);
|
|||
|
return Status;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
APIENTRY
|
|||
|
VerInstallFileA(
|
|||
|
DWORD wFlags,
|
|||
|
LPSTR lpszSrcFileName,
|
|||
|
LPSTR lpszDstFileName,
|
|||
|
LPSTR lpszSrcDir,
|
|||
|
LPSTR lpszDstDir,
|
|||
|
LPSTR lpszCurDir,
|
|||
|
LPSTR lpszTmpFile,
|
|||
|
PUINT puTmpFileLen
|
|||
|
)
|
|||
|
{
|
|||
|
UNICODE_STRING SrcFileName;
|
|||
|
UNICODE_STRING DstFileName;
|
|||
|
UNICODE_STRING SrcDir;
|
|||
|
UNICODE_STRING CurDir;
|
|||
|
UNICODE_STRING DstDir;
|
|||
|
UNICODE_STRING TmpFile;
|
|||
|
ANSI_STRING AnsiString;
|
|||
|
NTSTATUS Status;
|
|||
|
DWORD TmpFileLen = (*puTmpFileLen) ? (*puTmpFileLen) : 1;
|
|||
|
|
|||
|
TmpFileLen = min(MAX_PATH, TmpFileLen);
|
|||
|
|
|||
|
RtlInitAnsiString(&AnsiString, lpszSrcFileName);
|
|||
|
Status = RtlAnsiStringToUnicodeString(&SrcFileName, &AnsiString, TRUE);
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
SetLastError(Status);
|
|||
|
return VIF_OUTOFMEMORY;
|
|||
|
}
|
|||
|
RtlInitAnsiString(&AnsiString, lpszDstFileName);
|
|||
|
Status = RtlAnsiStringToUnicodeString(&DstFileName, &AnsiString, TRUE);
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
RtlFreeUnicodeString(&SrcFileName);
|
|||
|
SetLastError(Status);
|
|||
|
return VIF_OUTOFMEMORY;
|
|||
|
}
|
|||
|
RtlInitAnsiString(&AnsiString, lpszSrcDir);
|
|||
|
Status = RtlAnsiStringToUnicodeString(&SrcDir, &AnsiString, TRUE);
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
RtlFreeUnicodeString(&SrcFileName);
|
|||
|
RtlFreeUnicodeString(&DstFileName);
|
|||
|
SetLastError(Status);
|
|||
|
return VIF_OUTOFMEMORY;
|
|||
|
}
|
|||
|
RtlInitAnsiString(&AnsiString, lpszCurDir);
|
|||
|
Status = RtlAnsiStringToUnicodeString(&CurDir, &AnsiString, TRUE);
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
RtlFreeUnicodeString(&SrcFileName);
|
|||
|
RtlFreeUnicodeString(&DstFileName);
|
|||
|
RtlFreeUnicodeString(&SrcDir);
|
|||
|
SetLastError(Status);
|
|||
|
return VIF_OUTOFMEMORY;
|
|||
|
}
|
|||
|
RtlInitAnsiString(&AnsiString, lpszDstDir);
|
|||
|
Status = RtlAnsiStringToUnicodeString(&DstDir, &AnsiString, TRUE);
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
RtlFreeUnicodeString(&SrcFileName);
|
|||
|
RtlFreeUnicodeString(&DstFileName);
|
|||
|
RtlFreeUnicodeString(&SrcDir);
|
|||
|
RtlFreeUnicodeString(&CurDir);
|
|||
|
SetLastError(Status);
|
|||
|
return VIF_OUTOFMEMORY;
|
|||
|
}
|
|||
|
|
|||
|
RtlInitAnsiString(&AnsiString, lpszTmpFile);
|
|||
|
|
|||
|
TmpFile.MaximumLength = (USHORT)(TmpFileLen * sizeof(WCHAR));
|
|||
|
TmpFile.Buffer = RtlAllocateHeap(RtlProcessHeap(), 0, TmpFile.MaximumLength);
|
|||
|
if (TmpFile.Buffer == NULL) {
|
|||
|
RtlFreeUnicodeString(&SrcFileName);
|
|||
|
RtlFreeUnicodeString(&DstFileName);
|
|||
|
RtlFreeUnicodeString(&SrcDir);
|
|||
|
RtlFreeUnicodeString(&CurDir);
|
|||
|
RtlFreeUnicodeString(&DstDir);
|
|||
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|||
|
return VIF_OUTOFMEMORY;
|
|||
|
}
|
|||
|
|
|||
|
Status = RtlAnsiStringToUnicodeString(&TmpFile, &AnsiString, FALSE);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
RtlFreeUnicodeString(&SrcFileName);
|
|||
|
RtlFreeUnicodeString(&DstFileName);
|
|||
|
RtlFreeUnicodeString(&SrcDir);
|
|||
|
RtlFreeUnicodeString(&CurDir);
|
|||
|
RtlFreeUnicodeString(&DstDir);
|
|||
|
RtlFreeUnicodeString(&TmpFile);
|
|||
|
SetLastError(Status);
|
|||
|
return VIF_OUTOFMEMORY;
|
|||
|
}
|
|||
|
|
|||
|
Status = VerInstallFileW(wFlags,
|
|||
|
SrcFileName.Buffer,
|
|||
|
DstFileName.Buffer,
|
|||
|
SrcDir.Buffer,
|
|||
|
DstDir.Buffer,
|
|||
|
CurDir.Buffer,
|
|||
|
TmpFile.Buffer, &TmpFileLen);
|
|||
|
|
|||
|
if (Status & VIF_BUFFTOOSMALL) {
|
|||
|
//
|
|||
|
// The lpszTmpFile buffer was too small,
|
|||
|
// the TmpFileLen field contains the size necessary.
|
|||
|
//
|
|||
|
*lpszTmpFile = 0;
|
|||
|
*puTmpFileLen = TmpFileLen;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
TmpFile.Length = TmpFile.MaximumLength = (USHORT)(TmpFileLen * sizeof(WCHAR));
|
|||
|
|
|||
|
AnsiString.Buffer = lpszTmpFile;
|
|||
|
AnsiString.MaximumLength = (USHORT)*puTmpFileLen;
|
|||
|
RtlUnicodeStringToAnsiString(&AnsiString, &TmpFile, FALSE);
|
|||
|
*puTmpFileLen = AnsiString.Length;
|
|||
|
}
|
|||
|
|
|||
|
RtlFreeUnicodeString(&SrcFileName);
|
|||
|
RtlFreeUnicodeString(&DstFileName);
|
|||
|
RtlFreeUnicodeString(&SrcDir);
|
|||
|
RtlFreeUnicodeString(&DstDir);
|
|||
|
RtlFreeUnicodeString(&CurDir);
|
|||
|
RtlFreeUnicodeString(&TmpFile);
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
APIENTRY
|
|||
|
GetFileVersionInfoSizeA(
|
|||
|
LPSTR lpstrFilename,
|
|||
|
LPDWORD lpdwHandle
|
|||
|
)
|
|||
|
{
|
|||
|
UNICODE_STRING FileName;
|
|||
|
ANSI_STRING AnsiString;
|
|||
|
NTSTATUS Status;
|
|||
|
DWORD dwStatus;
|
|||
|
|
|||
|
RtlInitAnsiString(&AnsiString, lpstrFilename);
|
|||
|
Status = RtlAnsiStringToUnicodeString(&FileName, &AnsiString, TRUE);
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
SetLastError(Status);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
dwStatus = GetFileVersionInfoSizeW(FileName.Buffer, lpdwHandle);
|
|||
|
RtlFreeUnicodeString(&FileName);
|
|||
|
return dwStatus;
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
APIENTRY
|
|||
|
GetFileVersionInfoA(
|
|||
|
LPSTR lpstrFilename,
|
|||
|
DWORD dwHandle,
|
|||
|
DWORD dwLen,
|
|||
|
LPVOID lpData
|
|||
|
)
|
|||
|
{
|
|||
|
UNICODE_STRING FileName;
|
|||
|
ANSI_STRING AnsiString;
|
|||
|
NTSTATUS Status;
|
|||
|
BOOL bStatus;
|
|||
|
|
|||
|
RtlInitAnsiString(&AnsiString, lpstrFilename);
|
|||
|
Status = RtlAnsiStringToUnicodeString(&FileName, &AnsiString, TRUE);
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
SetLastError(Status);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
bStatus = GetFileVersionInfoW(FileName.Buffer, dwHandle, dwLen, lpData);
|
|||
|
RtlFreeUnicodeString(&FileName);
|
|||
|
return bStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* DWORD
|
|||
|
* APIENTRY
|
|||
|
* VerLanguageNameA(
|
|||
|
* DWORD wLang,
|
|||
|
* LPSTR szLang,
|
|||
|
* DWORD wSize)
|
|||
|
*
|
|||
|
* This routine was moved to NLSLIB.LIB so that it uses the WINNLS.RC file.
|
|||
|
* NLSLIB.LIB is part of KERNEL32.DLL.
|
|||
|
*/
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
APIENTRY
|
|||
|
VerQueryValueIndexA(
|
|||
|
const LPVOID pb,
|
|||
|
LPSTR lpSubBlock,
|
|||
|
INT nIndex,
|
|||
|
LPVOID *lplpKey,
|
|||
|
LPVOID *lplpBuffer,
|
|||
|
PUINT puLen
|
|||
|
)
|
|||
|
{
|
|||
|
return VerpQueryValue(pb,
|
|||
|
lpSubBlock,
|
|||
|
nIndex,
|
|||
|
lplpKey,
|
|||
|
lplpBuffer,
|
|||
|
puLen,
|
|||
|
FALSE);
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
APIENTRY
|
|||
|
VerQueryValueA(
|
|||
|
const LPVOID pb,
|
|||
|
LPSTR lpSubBlock,
|
|||
|
LPVOID *lplpBuffer,
|
|||
|
PUINT puLen
|
|||
|
)
|
|||
|
{
|
|||
|
return VerpQueryValue(pb,
|
|||
|
lpSubBlock,
|
|||
|
-1,
|
|||
|
NULL,
|
|||
|
lplpBuffer,
|
|||
|
puLen,
|
|||
|
FALSE);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
APIENTRY
|
|||
|
VerQueryValueW(
|
|||
|
const LPVOID pb,
|
|||
|
LPWSTR lpSubBlock,
|
|||
|
LPVOID *lplpBuffer,
|
|||
|
PUINT puLen
|
|||
|
)
|
|||
|
{
|
|||
|
return VerpQueryValue(pb,
|
|||
|
lpSubBlock,
|
|||
|
-1,
|
|||
|
NULL,
|
|||
|
lplpBuffer,
|
|||
|
puLen,
|
|||
|
TRUE);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
APIENTRY
|
|||
|
VerQueryValueIndexW(
|
|||
|
const LPVOID pb,
|
|||
|
LPWSTR lpSubBlock,
|
|||
|
INT nIndex,
|
|||
|
LPVOID *lplpKey,
|
|||
|
LPVOID *lplpBuffer,
|
|||
|
PUINT puLen
|
|||
|
)
|
|||
|
{
|
|||
|
return VerpQueryValue(pb,
|
|||
|
lpSubBlock,
|
|||
|
nIndex,
|
|||
|
lplpKey,
|
|||
|
lplpBuffer,
|
|||
|
puLen,
|
|||
|
TRUE);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|