7414 lines
227 KiB
C++
7414 lines
227 KiB
C++
#include "stdinc.h" // actually from dll\whistler directory
|
|
/*-----------------------------------------------------------------------------
|
|
Side X ("by") Side Test
|
|
-----------------------------------------------------------------------------*/
|
|
#include "nt.h"
|
|
#include "ntrtl.h"
|
|
#include "nturtl.h"
|
|
#include "windows.h"
|
|
#include "fusionlastwin32error.h"
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#pragma warning(push)
|
|
#pragma warning(disable: 4511)
|
|
#pragma warning(disable: 4512)
|
|
#pragma warning(disable: 4663)
|
|
#include <yvals.h>
|
|
#pragma warning(disable: 4663)
|
|
#include <string>
|
|
#include <deque>
|
|
#include <vector>
|
|
#pragma warning(pop)
|
|
#include "FusionBuffer.h"
|
|
#include "fusion.h"
|
|
#include "sxsasmname.h"
|
|
#include "util.h"
|
|
#include "filestream.cpp"
|
|
#include "sxsapi.h"
|
|
#include "fusiontrace.h"
|
|
#include "cresourcestream.cpp"
|
|
#include "cmemorystream.cpp"
|
|
#include "wintrust.h"
|
|
#include "softpub.h"
|
|
#include "perfclocking.h"
|
|
#include "strongname.h"
|
|
#include "fusionversion.h"
|
|
#include <setupapi.h>
|
|
#include <string>
|
|
#include "commctrl.h"
|
|
#include <algorithm>
|
|
#include "fusionsha1.h"
|
|
#include "cguid.h"
|
|
#include "winbasep.h"
|
|
#undef LoadLibraryA
|
|
#undef LoadLibraryW
|
|
#undef LoadLibraryExA
|
|
#undef LoadLibraryExW
|
|
#undef InitCommonControls
|
|
|
|
BOOL IamExe;
|
|
BOOL IamDll;
|
|
extern "C" { void (__cdecl * _aexit_rtn)(int); }
|
|
|
|
void __cdecl Trace(const char* FormatString, ...)
|
|
{
|
|
char buffer[2000];
|
|
va_list args;
|
|
|
|
va_start(args, FormatString);
|
|
_vsnprintf(buffer, RTL_NUMBER_OF(buffer), FormatString, args);
|
|
buffer[RTL_NUMBER_OF(buffer) - 1] = 0;
|
|
for (PSTR s = buffer ; *s != 0 ; )
|
|
{
|
|
PSTR t = strchr(s, '\n');
|
|
|
|
if (t != NULL)
|
|
*t = 0;
|
|
|
|
printf("stdout : %s\n", s);
|
|
OutputDebugStringA("debugger: ");
|
|
OutputDebugStringA(s);
|
|
OutputDebugStringA("\n");
|
|
|
|
if (t != NULL)
|
|
s = t + 1;
|
|
}
|
|
va_end(args);
|
|
}
|
|
|
|
typedef BOOL (WINAPI * PSXSPGENERATEMANIFESTPATHONASSEMBLYIDENTITY)(
|
|
PWSTR str, // input string, must have name, version, langid and processorarchitecture
|
|
PWSTR psz, // output string, like x86_cards_strongname,.......
|
|
SIZE_T * pCch, // IN : length of psz, OUT : used
|
|
PASSEMBLY_IDENTITY *ppAssemblyIdentity // could be NULL
|
|
);
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
work around the fact that SxsHeap doesn't let us use a non debug operator new
|
|
-----------------------------------------------------------------------------*/
|
|
template <typename T>
|
|
class Allocator : public std::allocator<T>
|
|
{
|
|
public:
|
|
pointer allocate(size_type n, const void*)
|
|
{
|
|
return reinterpret_cast<pointer>(malloc(n * sizeof(T)));
|
|
}
|
|
|
|
char* _Charalloc(size_type n)
|
|
{
|
|
return reinterpret_cast<char*>(malloc(n));
|
|
}
|
|
|
|
void deallocate(void* p, size_type)
|
|
{
|
|
free(p);
|
|
}
|
|
};
|
|
|
|
#define SXSTEST_BEGIN_INSTALL (0x4000000000000000i64)
|
|
#define SXSTEST_INSTALL (0x2000000000000000i64)
|
|
#define SXSTEST_END_INSTALL (0x1000000000000000i64)
|
|
#define SXSTEST_INSTALL_MY_QUEUE (0x0800000000000000i64)
|
|
#define SXSTEST_INSTALL_SETUPAPI_QUEUE (0x0400000000000000i64)
|
|
#define SXSTEST_END_OF_FLAGS (0x0200000000000000i64)
|
|
#define SXSTEST_THREADS (0x0100000000000000i64)
|
|
#define SXSTEST_CREATEPROCESS (0x0080000000000000i64)
|
|
|
|
inline int PRINTABLE(int ch) { return isprint(ch) ? ch : '.'; }
|
|
|
|
void PrintIfAnyCriticalSectionsHeld(const char* file, int line, const char* function)
|
|
#define PrintIfAnyCriticalSectionsHeld() PrintIfAnyCriticalSectionsHeld(__FILE__, __LINE__, __FUNCTION__)
|
|
{
|
|
const DWORD dwLastError = ::GetLastError();
|
|
PTEB teb;
|
|
teb = NtCurrentTeb();
|
|
if (teb->CountOfOwnedCriticalSections != 0)
|
|
{
|
|
DbgPrint("%s(%d):%s teb->CountOfOwnedCriticalSections %d\n", file, line, function, teb->CountOfOwnedCriticalSections);
|
|
}
|
|
SetLastError(dwLastError);
|
|
}
|
|
|
|
static
|
|
VOID
|
|
PrintBlob(
|
|
FILE *pf,
|
|
PVOID Data,
|
|
SIZE_T Length,
|
|
PCWSTR PerLinePrefix
|
|
);
|
|
|
|
BOOL TestLeakMemory(DWORD Amount);
|
|
BOOL TestAssemblyProbing(int argc, wchar_t **argv, int *piNext);
|
|
BOOL TestDirectoryChangeWatcher(int argc, wchar_t **argv, int *piNext);
|
|
BOOL TestXMLParsing(int argc, wchar_t **argv, int *piNext);
|
|
BOOL TestMultiAct(int argc, wchar_t **argv);
|
|
BOOL TestManifestSchema(int argc, wchar_t **argv, int *piNext);
|
|
BOOL TestDirect(int argc, wchar_t **argv, int *piNext);
|
|
void TestWin32(wchar_t** argv);
|
|
BOOL TestAct(int argc, wchar_t **argv, int *piNext);
|
|
BOOL TestInstall(PCWSTR manifest, __int64 flags, DWORD beginInstallFlags, DWORD installFlags, DWORD endInstallFlags);
|
|
int TestDiffDir(PCWSTR dir1, PCWSTR dir2);
|
|
BOOL TestSearchPath(int argc, wchar_t** argv, int* piNext);
|
|
BOOL TestMSIInstall(int argc, wchar_t** argv, int* piNext);
|
|
int TestDirWalk(PCWSTR root, PWSTR filter);
|
|
BOOL TestLoadLibrary(int argc, wchar_t** argv, int* piNext);
|
|
int TestAssemblyName(VOID);
|
|
int TestPrecomiledManifest(PCWSTR szFileName);
|
|
int TestPCMTime(PCWSTR manifestFilename);
|
|
int TestCreateProcess(wchar_t** argv);
|
|
int TestCreateProcess2(wchar_t** argv);
|
|
BOOL TestInstallPrivateAssembly(int argc, wchar_t** argv, int* piNext);
|
|
BOOL TestManifestProbing(int argc, wchar_t** argv, int* piNext);
|
|
int TestCreateMultiLevelDirectory(PCWSTR dirs);
|
|
BOOL TestXMLDOM(PCWSTR xmlfilename);
|
|
BOOL TestFusionArray(PCWSTR, PCWSTR);
|
|
BOOL TestGeneratePathFromIdentityAttributeString(PCWSTR str);
|
|
BOOL TestRefreshAssembly(PCWSTR wsAssembly);
|
|
BOOL TestInstallWithInstallInfo(PCWSTR wsAssemblyManifest, PCWSTR wsReference);
|
|
BOOL TestOpeningStuff(PCWSTR wsSourceName, PCWSTR wsType, PCWSTR wsCount);
|
|
BOOL TestVerifyFileSignature(PCWSTR wsFilename);
|
|
BOOL TestInstallLikeWindowsSetup(PCWSTR szDirectory, PCWSTR szCodebase);
|
|
BOOL TestDumpContainedManifests(PCWSTR wsFilename);
|
|
BOOL TestGenerateStringWithIdenticalHash(WCHAR iString[33]);
|
|
BOOL TestAssemblyIdentityHash();
|
|
void TestInherit();
|
|
void TestNoInherit();
|
|
void TestEmpty();
|
|
BOOL TestMessagePerf(int argc, wchar_t **arg, int *piNext);
|
|
LRESULT CALLBACK TestMessagePerfWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
void TestTrickyMultipleAssemblyCacheItems(PCWSTR);
|
|
void TestSfcScanKickoff();
|
|
void GenerateStrongNameAndPublicKey(PCWSTR wsCertificate);
|
|
VOID TestCreateActctxLeakHandles(DWORD num);
|
|
BOOL TestSystemDefaultActivationContextGeneration();
|
|
BOOL TestAsyncIO(int argc, wchar_t **argv, int *piNext);
|
|
void TestRefCount();
|
|
void TestGuidSort();
|
|
void TestStringSort();
|
|
BOOL TestNewCatalogSignerThingy(PCWSTR pcwszCatalog);
|
|
void TestExeDll();
|
|
int TestThreadInheritLeak();
|
|
BOOL TestSxsSfcUI();
|
|
void TestGetModuleHandleEx();
|
|
void TestGetFullPathName(PCWSTR);
|
|
void TestCreateFile(PCWSTR);
|
|
void TestGetPathBaseName(LPCWSTR Path);
|
|
PCSTR PrintPathToString(RTL_PATH_TYPE);
|
|
void TestPathType(PCWSTR*);
|
|
void TestVersion();
|
|
void TestGetProcessImageFileName();
|
|
void TestErrorInfra();
|
|
void TestQueryActCtx();
|
|
void TestQueryActCtx2();
|
|
void Test64k();
|
|
void TestDotLocalSingleInstancing();
|
|
void TestCreateActCtx(int nCreations, wchar_t **rgCreations);
|
|
void TestCreateActctxLikeCreateProcess();
|
|
void TestCreateActctxAdminOverride();
|
|
void TestQueryManifestInformationBasic(PCWSTR pszManifest);
|
|
void TestCreateActctxWindowsShellManifest();
|
|
void TestCreateGlobalEvent();
|
|
void TestHandleLeaks(void);
|
|
void TestCRuntimeAsms(void);
|
|
BOOL TestMfcCreateAndMarshal(void);
|
|
void TestAtlCreate(void);
|
|
void TestAlignment(void);
|
|
BOOL TestPrivateSha1Impl(PCWSTR pcwszDirName);
|
|
BOOL TestNewSxsInstallAPI(PCWSTR pcwszManifest);
|
|
void TestImage(void);
|
|
void TestInterlockedAlignment(void);
|
|
void TestCreateActCtx_PE_flags0(void);
|
|
void TestUninstall(PCWSTR ManifestPath, PCWSTR ReferenceString);
|
|
PCWSTR GetLastErrorMessage();
|
|
BOOL SimpleTestFindAndUseSurrogateInformation(PCWSTR filename, PCWSTR GuidToDisplay);
|
|
BOOL TestSxsExportedSurrogateStuff(PCWSTR pcwszManifest, PCWSTR pcwszWhat, PCWSTR pcwszData);
|
|
|
|
|
|
DWORD LastError;
|
|
|
|
static void LoadSxs();
|
|
static int Main(int argc, wchar_t** argv);
|
|
static void SetLastOperation(const wchar_t* format, ...);
|
|
static const wchar_t* GetLastOperation(const wchar_t* format, ...);
|
|
static int Usage(const char* argv0);
|
|
template <typename PFN> void GetSxsProc(PCSTR name, PFN* ppfn);
|
|
template <typename PFN> void GetSxsProc(int name, PFN* ppfn);
|
|
|
|
SXSP_DEBUG_FUNCTION pfnSxspDebug = NULL;
|
|
|
|
BOOL ParseProcessorArchitecture(int argc, wchar_t** argv, int* piCurrent);
|
|
BOOL ParseLangId(int argc, wchar_t** argv, int* piCurrent);
|
|
|
|
PCWSTR FusionpThreadUnsafeGetLastWin32ErrorMessageW()
|
|
{
|
|
CSxsPreserveLastError ple;
|
|
static WCHAR LastErrorMessage[4096];
|
|
|
|
LastErrorMessage[0] = 0;
|
|
|
|
::FormatMessageW(
|
|
FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL,
|
|
::FusionpGetLastWin32Error(),
|
|
0,
|
|
LastErrorMessage,
|
|
RTL_NUMBER_OF(LastErrorMessage),
|
|
NULL);
|
|
if (LastErrorMessage[0] != 0)
|
|
{
|
|
PWSTR p = LastErrorMessage + ::StringLength(LastErrorMessage) - 1;
|
|
while (p != LastErrorMessage && (*p == '\n' || *p == '\r' || *p == ' ' || *p == '\t'))
|
|
{
|
|
*p-- = 0;
|
|
}
|
|
}
|
|
ple.Restore();
|
|
return LastErrorMessage;
|
|
}
|
|
|
|
|
|
void __stdcall ThrowLastError(DWORD error = ::GetLastError())
|
|
{
|
|
RaiseException(error, 0, 0, NULL);
|
|
//throw HRESULT_FROM_WIN32(error);
|
|
}
|
|
|
|
void __stdcall ThrowWin32(ULONG_PTR error = ::GetLastError())
|
|
{
|
|
ThrowLastError(static_cast<DWORD>(error));
|
|
}
|
|
|
|
void __stdcall CheckHresult(HRESULT hr)
|
|
{
|
|
if (FAILED(hr))
|
|
throw hr;
|
|
}
|
|
|
|
void SetDllBitInPeImage(PCWSTR Path)
|
|
/*++
|
|
.exes and .dlls are the same format except one bit in the headers distinguishes them.
|
|
--*/
|
|
{
|
|
CFusionFile File;
|
|
CFileMapping FileMapping;
|
|
CMappedViewOfFile MappedViewOfFile;
|
|
|
|
if (!File.Win32CreateFile(Path, GENERIC_READ | GENERIC_WRITE, 0, OPEN_EXISTING))
|
|
ThrowLastError();
|
|
if (!FileMapping.Win32CreateFileMapping(File, PAGE_READWRITE))
|
|
ThrowLastError();
|
|
if (!MappedViewOfFile.Win32MapViewOfFile(FileMapping, FILE_MAP_WRITE))
|
|
ThrowLastError();
|
|
|
|
PIMAGE_NT_HEADERS NtHeaders = RtlImageNtHeader(static_cast<PVOID>(MappedViewOfFile));
|
|
if (NtHeaders == NULL)
|
|
ThrowLastError(ERROR_BAD_EXE_FORMAT);
|
|
|
|
// This is correct for PE32 or PE32+.
|
|
NtHeaders->FileHeader.Characteristics |= IMAGE_FILE_DLL;
|
|
|
|
if (!MappedViewOfFile.Win32Close())
|
|
ThrowLastError();
|
|
if (!FileMapping.Win32Close())
|
|
ThrowLastError();
|
|
if (!File.Win32Close())
|
|
ThrowLastError();
|
|
}
|
|
|
|
PCSTR PrintPathToString(RTL_PATH_TYPE PathType)
|
|
{
|
|
switch (PathType)
|
|
{
|
|
#define X(x) case x: return #x;
|
|
X(RtlPathTypeUnknown)
|
|
X(RtlPathTypeUncAbsolute)
|
|
X(RtlPathTypeDriveAbsolute)
|
|
X(RtlPathTypeDriveRelative)
|
|
X(RtlPathTypeRooted)
|
|
X(RtlPathTypeRelative)
|
|
X(RtlPathTypeLocalDevice)
|
|
X(RtlPathTypeRootLocalDevice)
|
|
#undef X
|
|
default:
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
void TestPathType(const PCWSTR* argv)
|
|
{
|
|
if (*argv != NULL)
|
|
{
|
|
while (*argv != NULL)
|
|
{
|
|
RTL_PATH_TYPE PathType = SxspDetermineDosPathNameType(*argv);
|
|
printf("%ls -> %s\n", *argv, PrintPathToString(PathType));
|
|
argv += 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const static PCWSTR args[] =
|
|
{
|
|
L"a",
|
|
L"\\a",
|
|
L"\\\\a",
|
|
L"\\\\\\a",
|
|
L"a:",
|
|
L"a:\\",
|
|
L"\\?",
|
|
L"\\.",
|
|
L"\\\\?",
|
|
L"\\\\.",
|
|
L"\\\\?\\",
|
|
L"\\\\.\\",
|
|
L"\\\\?\\a",
|
|
L"\\\\.\\a",
|
|
L"\\\\?\\a:",
|
|
L"\\\\.\\a:",
|
|
L"\\\\?\\a:\\",
|
|
L"\\\\.\\a:\\",
|
|
L"\\\\?\\unc",
|
|
L"\\\\.\\unc",
|
|
L"\\\\?\\unc\\",
|
|
L"\\\\.\\unc\\",
|
|
NULL
|
|
};
|
|
TestPathType(args);
|
|
}
|
|
}
|
|
|
|
class CUnknown : public IUnknown
|
|
{
|
|
public:
|
|
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv)
|
|
{
|
|
return E_NOINTERFACE;
|
|
}
|
|
virtual ULONG __stdcall AddRef()
|
|
{
|
|
return 1;
|
|
}
|
|
virtual ULONG __stdcall Release()
|
|
{
|
|
return 1;
|
|
}
|
|
};
|
|
|
|
struct G
|
|
{
|
|
HINSTANCE sxsDll;
|
|
USHORT wProcessorArchitecture;
|
|
LANGID wLangId;
|
|
HANDLE MainThread;
|
|
INT NumberOfThreads;
|
|
HANDLE Threads[MAXIMUM_WAIT_OBJECTS];
|
|
HANDLE ThreadExitEvent;
|
|
wchar_t lastOperation[256];
|
|
CUnknown unknown;
|
|
|
|
CSmartRef<IGlobalInterfaceTable> GlobalInterfaceTable;
|
|
|
|
//
|
|
// the start of some automation / record keeping..
|
|
//
|
|
ULONG Failures;
|
|
ULONG Successes;
|
|
} g;
|
|
|
|
const static struct
|
|
{
|
|
DWORD (WINAPI* GetModuleFileNameW)(HMODULE, LPWSTR, DWORD);
|
|
SIZE_T (WINAPI* VirtualQuery)(LPCVOID, PMEMORY_BASIC_INFORMATION, SIZE_T);
|
|
}
|
|
Kernel32 =
|
|
{
|
|
GetModuleFileNameW,
|
|
VirtualQuery
|
|
};
|
|
|
|
const static struct
|
|
{
|
|
HRESULT (WINAPI* IIDFromString)(LPOLESTR, LPIID);
|
|
HRESULT (WINAPI* CLSIDFromString)(LPOLESTR, LPIID);
|
|
HRESULT (WINAPI* CoCreateInstance)(REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID*);
|
|
HRESULT (WINAPI* CoInitialize)(LPVOID);
|
|
void (WINAPI* CoUninitialize)();
|
|
}
|
|
Ole32 =
|
|
{
|
|
IIDFromString,
|
|
CLSIDFromString,
|
|
CoCreateInstance,
|
|
CoInitialize,
|
|
CoUninitialize
|
|
};
|
|
|
|
void
|
|
ManifestStringToTempFile(
|
|
PCWSTR ManifestString,
|
|
CBaseStringBuffer &rTempFilePath
|
|
)
|
|
{
|
|
CFusionFile File;
|
|
WCHAR xTempFilePath[MAX_PATH];
|
|
WCHAR TempDirectory[MAX_PATH];
|
|
const static WCHAR NativeUnicodeByteOrderMark = 0xfeff;
|
|
DWORD BytesWritten;
|
|
|
|
//if (!::GetTempPathW(NUMBER_OF(TempDirectory), TempDirectory))
|
|
// ThrowLastError();
|
|
|
|
::GetModuleFileNameW(NULL, TempDirectory, NUMBER_OF(TempDirectory));
|
|
*wcsrchr(TempDirectory, '\\') = 0;
|
|
::Trace("TempDirectory:%ls\n", TempDirectory);
|
|
|
|
if (!::GetTempFileNameW(TempDirectory, L"", 0, xTempFilePath))
|
|
::ThrowLastError();
|
|
rTempFilePath.Win32Assign(xTempFilePath, wcslen(xTempFilePath));
|
|
|
|
::Trace("xTempFilePath:%ls\n", xTempFilePath);
|
|
::Trace("TempFilePath:%ls\n", static_cast<PCWSTR>(xTempFilePath));
|
|
|
|
if (!File.Win32CreateFile(rTempFilePath, GENERIC_WRITE, 0, CREATE_ALWAYS))
|
|
::ThrowLastError();
|
|
|
|
if (!::WriteFile(File, &NativeUnicodeByteOrderMark, sizeof(NativeUnicodeByteOrderMark), &BytesWritten, NULL))
|
|
::ThrowLastError();
|
|
|
|
if (!::WriteFile(File, ManifestString, static_cast<DWORD>(sizeof(*ManifestString) * StringLength(ManifestString)), &BytesWritten, NULL))
|
|
::ThrowLastError();
|
|
}
|
|
|
|
HANDLE
|
|
CreateActivationContextFromStringW(
|
|
PCWSTR ManifestString
|
|
)
|
|
{
|
|
CStringBuffer TempFilePath;
|
|
|
|
::ManifestStringToTempFile(ManifestString, TempFilePath);
|
|
|
|
ACTCTXW ActivationContextCreate = { sizeof(ActivationContextCreate) };
|
|
ActivationContextCreate.lpSource = TempFilePath;
|
|
HANDLE ActivationContextHandle = ::CreateActCtxW(&ActivationContextCreate);
|
|
DWORD Error = ::GetLastError();
|
|
::DeleteFileW(TempFilePath);
|
|
if (ActivationContextHandle == INVALID_HANDLE_VALUE)
|
|
::ThrowLastError(Error);
|
|
return ActivationContextHandle;
|
|
}
|
|
|
|
int Usage(const wchar_t* argv0)
|
|
{
|
|
std::wstring strargv0 = argv0;
|
|
fprintf(stderr,
|
|
"%ls",
|
|
(
|
|
L"Usage: \n"
|
|
L" " + strargv0 + L" [install-flags] manifest-or-image-with-manifest-resource-path\n"
|
|
L" " + strargv0 + L" [-pa processor-architecture] [-langid langid] -d manifest-path ...\n"
|
|
L" " + strargv0 + L" [-pa processor-architecture] [-langid langid] -p manifest-path ...\n"
|
|
L" " + strargv0 + L" [-pa processor-architecture] [-langid langid] -w32 manifest-path ...\n"
|
|
L" " + strargv0 + L" [-pa processor-architecture] [-langid langid] -msi msi-script...\n"
|
|
L" " + strargv0 + L" -tcreateprocess ...\n"
|
|
L" " + strargv0 + L" -tsearchpath ...\n"
|
|
L" " + strargv0 + L" -tcreateprocess ...\n"
|
|
L" " + strargv0 + L" -tempty test pushing a special empty context ...\n"
|
|
L" " + strargv0 + L" -tinherit test the usual default inheritance ...\n"
|
|
L" " + strargv0 + L" -tnoinherit test the noinherit bit ...\n"
|
|
L" " + strargv0 + L" [-threads n] create n threads for some tests ...\n"
|
|
L" " + strargv0 + L" probably other choices, use the source\n"
|
|
L"\n"
|
|
L"install-flags:\n"
|
|
L" -i\n"
|
|
L" -install\n"
|
|
L" -install-my-queue\n"
|
|
L" -install-setupapi-queue\n"
|
|
L" -install-from-resource\n"
|
|
L" -install-move\n"
|
|
L" -install-my-queue\n"
|
|
L" -install-setupapi-queue [requires debugger]\n"
|
|
L" -install-from-resource\n"
|
|
).c_str()
|
|
);
|
|
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
const wchar_t* GetLastOperation()
|
|
{
|
|
return g.lastOperation;
|
|
}
|
|
|
|
void SetLastOperation(const wchar_t* format, ...)
|
|
{
|
|
va_list args;
|
|
|
|
g.lastOperation[0] = 0;
|
|
g.lastOperation[NUMBER_OF(g.lastOperation) - 1] = 0;
|
|
|
|
va_start(args, format);
|
|
_vsnwprintf(g.lastOperation, NUMBER_OF(g.lastOperation) - 1, format, args);
|
|
va_end(args);
|
|
}
|
|
|
|
HANDLE DuplicateHandle(HANDLE handle)
|
|
{
|
|
HANDLE newHandle = NULL;
|
|
if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(), &newHandle, 0, FALSE, DUPLICATE_SAME_ACCESS))
|
|
{
|
|
ThrowLastError();
|
|
}
|
|
return newHandle;
|
|
}
|
|
|
|
__int64 IsFlag(PCWSTR arg)
|
|
{
|
|
const static struct
|
|
{
|
|
WCHAR name[32];
|
|
__int64 value;
|
|
} flags[] =
|
|
{
|
|
{ L"i", SXSTEST_BEGIN_INSTALL},
|
|
{ L"install", SXSTEST_BEGIN_INSTALL},
|
|
|
|
{ L"install-my-queue", SXSTEST_INSTALL_MY_QUEUE },
|
|
{ L"install-setupapi-queue", SXSTEST_INSTALL_SETUPAPI_QUEUE },
|
|
|
|
{ L"install-from-resource", SXS_INSTALL_ASSEMBLY_FLAG_FROM_RESOURCE | SXSTEST_INSTALL},
|
|
{ L"install-move", SXS_INSTALL_ASSEMBLY_FLAG_MOVE | SXSTEST_INSTALL },
|
|
{ L"install-dir", SXS_INSTALL_ASSEMBLY_FLAG_FROM_DIRECTORY | SXSTEST_INSTALL},
|
|
{ L"install-dir-recursive", SXS_INSTALL_ASSEMBLY_FLAG_FROM_DIRECTORY_RECURSIVE | SXSTEST_INSTALL},
|
|
{ L"install-no-verify", SXS_INSTALL_ASSEMBLY_FLAG_NO_VERIFY | SXSTEST_INSTALL},
|
|
{ L"install-no-transact", SXS_INSTALL_ASSEMBLY_FLAG_NOT_TRANSACTIONAL | SXSTEST_INSTALL},
|
|
{ L"install-replace-existing", SXS_INSTALL_ASSEMBLY_FLAG_REPLACE_EXISTING | SXSTEST_INSTALL},
|
|
|
|
{ L"begin-install-replace-existing", SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_REPLACE_EXISTING | SXSTEST_BEGIN_INSTALL},
|
|
{ L"begin-install-from-resource", SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_FROM_RESOURCE | SXSTEST_BEGIN_INSTALL},
|
|
{ L"begin-install-move", SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_MOVE | SXSTEST_BEGIN_INSTALL },
|
|
{ L"begin-install-dir", SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_FROM_DIRECTORY | SXSTEST_BEGIN_INSTALL},
|
|
{ L"begin-install-dir-recursive", SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_FROM_DIRECTORY_RECURSIVE | SXSTEST_BEGIN_INSTALL},
|
|
{ L"begin-install-no-verify", SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_NO_VERIFY | SXSTEST_BEGIN_INSTALL},
|
|
{ L"begin-install-no-transact", SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_NOT_TRANSACTIONAL | SXSTEST_BEGIN_INSTALL},
|
|
|
|
{ L"end-install-no-verify", SXS_END_ASSEMBLY_INSTALL_FLAG_NO_VERIFY | SXSTEST_END_INSTALL},
|
|
|
|
{ L"threads", SXSTEST_THREADS },
|
|
|
|
{ L"-", SXSTEST_END_OF_FLAGS }
|
|
};
|
|
if (*arg == '-')
|
|
{
|
|
arg += 1;
|
|
for (ULONG i = 0 ; i != NUMBER_OF(flags) ; ++i)
|
|
{
|
|
if (_wcsicmp(flags[i].name, arg) == 0)
|
|
return flags[i].value;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
DWORD __stdcall ThreadMain(PVOID)
|
|
{
|
|
//
|
|
// We run stuff in other threads via QueueUserAPC.
|
|
//
|
|
__try
|
|
{
|
|
WaitForSingleObjectEx(g.ThreadExitEvent, INFINITE, TRUE);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
#if DBG
|
|
if (IsDebuggerPresent())
|
|
{
|
|
FUSION_DEBUG_BREAK();
|
|
}
|
|
#endif
|
|
QueueUserAPC(ThrowWin32, g.MainThread, GetExceptionCode());
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void CreateThreads()
|
|
{
|
|
INT i;
|
|
g.MainThread = DuplicateHandle(GetCurrentThread());
|
|
g.ThreadExitEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
|
|
if (g.ThreadExitEvent == NULL)
|
|
{
|
|
ThrowLastError();
|
|
}
|
|
for (i = 0 ; i < g.NumberOfThreads ; i++)
|
|
{
|
|
g.Threads[i] = CreateThread(NULL, 0, ThreadMain, NULL, 0, NULL);
|
|
if (g.Threads[i] == NULL)
|
|
{
|
|
int error = ::GetLastError();
|
|
if (i > 2)
|
|
{
|
|
fprintf(stderr, "Only able to created %d threads, error=%d, continuing\n", i, error);
|
|
g.NumberOfThreads = i;
|
|
break;
|
|
}
|
|
fprintf(stderr, "Unable to create threads, error=%d, terminating\n", error);
|
|
ThrowWin32(error);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
GetFlags(
|
|
wchar_t**& argv,
|
|
__int64& flags,
|
|
DWORD& beginInstallFlags,
|
|
DWORD& installFlags,
|
|
DWORD& endInstallFlags
|
|
)
|
|
{
|
|
__int64 flag;
|
|
while (flag = IsFlag(argv[1]))
|
|
{
|
|
++argv;
|
|
if (flag & SXSTEST_END_OF_FLAGS)
|
|
{
|
|
break;
|
|
}
|
|
else if (flag & SXSTEST_BEGIN_INSTALL)
|
|
{
|
|
beginInstallFlags |= flag;
|
|
}
|
|
else if (flag & SXSTEST_INSTALL)
|
|
{
|
|
installFlags |= flag;
|
|
}
|
|
else if (flag & SXSTEST_END_INSTALL)
|
|
{
|
|
endInstallFlags |= flag;
|
|
}
|
|
else if (flag & SXSTEST_THREADS)
|
|
{
|
|
g.NumberOfThreads = _wtoi(*++argv);
|
|
if (g.NumberOfThreads > NUMBER_OF(g.Threads))
|
|
{
|
|
g.NumberOfThreads = NUMBER_OF(g.Threads);
|
|
}
|
|
}
|
|
|
|
// always set flags because normal installation is 0 now
|
|
flags |= flag;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
FusionpSetSystemSetupInProgress(bool f)
|
|
{
|
|
CFusionRegKey Regkey;
|
|
CFusionRegKey RegkeyLocalMachine(HKEY_LOCAL_MACHINE);
|
|
|
|
if (!RegkeyLocalMachine.OpenSubKey(Regkey, L"System\\Setup", KEY_ALL_ACCESS))
|
|
return;
|
|
Regkey.SetValue(L"SystemSetupInProgress", f ? 1 : 0);
|
|
}
|
|
|
|
extern "C"
|
|
BOOL
|
|
WINAPI
|
|
SxsDllMain(
|
|
HINSTANCE hInst,
|
|
DWORD dwReason,
|
|
PVOID pvReserved
|
|
);
|
|
|
|
int Main(int argc, wchar_t** argv)
|
|
{
|
|
int i = 0;
|
|
__int64 flags = 0;
|
|
//__int64 flag = 0;
|
|
DWORD beginInstallFlags = 0;
|
|
DWORD installFlags = 0;
|
|
DWORD endInstallFlags = 0;
|
|
wchar_t* argv0 = argv[0];
|
|
|
|
g.wProcessorArchitecture = SxspGetSystemProcessorArchitecture();
|
|
g.wLangId = ::GetUserDefaultLangID();
|
|
if (argc > 1)
|
|
{
|
|
FusionpSetSystemSetupInProgress(false);
|
|
__try
|
|
{
|
|
__try
|
|
{
|
|
if (!SxsDllMain(GetModuleHandle(NULL), DLL_PROCESS_ATTACH, NULL))
|
|
ThrowLastError();
|
|
GetFlags(argv, flags, beginInstallFlags, installFlags, endInstallFlags);
|
|
|
|
i = 1;
|
|
|
|
// consume global flags...
|
|
for (;;)
|
|
{
|
|
if (::FusionpStrCmpI(argv[i], L"-pa") == 0)
|
|
{
|
|
if (!ParseProcessorArchitecture(argc, argv, &i))
|
|
goto Exit;
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-langid") == 0)
|
|
{
|
|
if (!ParseLangId(argc, argv, &i))
|
|
goto Exit;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (false) { }
|
|
else if (::FusionpStrCmpI(argv[i], L"-id") == 0)
|
|
{
|
|
DWORD index = 0;
|
|
if (argv[3]){ // have an index present
|
|
index = argv[3][0] - L'0';
|
|
}
|
|
i = TestGeneratePathFromIdentityAttributeString(argv[2]);
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-tPathType") == 0)
|
|
{
|
|
TestPathType(argv + i + 1);
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-systemdefault") == 0)
|
|
{
|
|
i = TestSystemDefaultActivationContextGeneration();
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-dom") == 0)
|
|
{
|
|
i = TestXMLDOM(argv[2]);
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-hash") == 0)
|
|
{
|
|
i = TestGenerateStringWithIdenticalHash(argv[2]);
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-tasyncio") == 0)
|
|
{
|
|
i++;
|
|
i = TestAsyncIO(argc, argv, &i);
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-assemblyidentityhash") == 0)
|
|
{
|
|
i = TestAssemblyIdentityHash();
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-array") == 0)
|
|
{
|
|
i = TestFusionArray(argv[2], argv[3]);
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-diffdir") == 0)
|
|
{
|
|
i = TestDiffDir(argv[i + 1], argv[i + 2]);
|
|
}
|
|
else if (::FusionpStrCmpI(argv[1], L"-pcm") == 0)
|
|
{
|
|
i = TestPrecomiledManifest(argv[2]);
|
|
}
|
|
else if (::FusionpStrCmpI(argv[1], L"-testpcm") == 0)
|
|
{
|
|
i = TestPCMTime(argv[2]);
|
|
}
|
|
else if (::FusionpStrCmpI(argv[1], L"-cd") == 0)
|
|
{
|
|
i = TestCreateMultiLevelDirectory(argv[2]);
|
|
}
|
|
else if (!::FusionpStrCmpI(argv[i], L"-manifests"))
|
|
{
|
|
TestDumpContainedManifests(argv[++i]);
|
|
}
|
|
else if (::FusionpStrCmpI(argv[1], L"-dirwalk") == 0)
|
|
{
|
|
i = TestDirWalk(argv[i + 1], argv[i + 2]);
|
|
}
|
|
else if (::FusionpStrCmpI(argv[1], L"-tmultiact") == 0)
|
|
{
|
|
i = TestMultiAct(argc, argv);
|
|
}
|
|
else if (flags)
|
|
{
|
|
PrintIfAnyCriticalSectionsHeld();
|
|
i = TestInstall(argv[i], flags, beginInstallFlags, installFlags, endInstallFlags);
|
|
PrintIfAnyCriticalSectionsHeld();
|
|
}
|
|
else if (!::FusionpStrCmpI(argv[i], L"-sfcui"))
|
|
{
|
|
if ( !TestSxsSfcUI() )
|
|
goto Exit;
|
|
i++;
|
|
}
|
|
else if ( !FusionpStrCmpI( argv[i], L"-installwithinfo" ) )
|
|
{
|
|
TestInstallWithInstallInfo(
|
|
( i + 1 < argc ) ? argv[i + 1] : NULL,
|
|
( i + 2 < argc ) ? argv[i+2] : NULL);
|
|
i += 2;
|
|
}
|
|
else if (!::FusionpStrCmpI(argv[i], L"-multicache"))
|
|
{
|
|
TestTrickyMultipleAssemblyCacheItems(argv[i + 1]);
|
|
i++;
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-d") == 0)
|
|
{
|
|
if (!TestDirect(argc, argv, &i))
|
|
goto Exit;
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-probe") == 0)
|
|
{
|
|
i++;
|
|
argv[i] = L"foo,type=\"win32\",processorArchitecture=\"x86\",version=\"6.0.0.0\",publicKeyToken=\"6595b64144ccf1df\"";
|
|
if (!TestAssemblyProbing(argc, argv, &i))
|
|
goto Exit;
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-dirchanges") == 0)
|
|
{
|
|
if (!TestDirectoryChangeWatcher(argc, argv, &i))
|
|
goto Exit;
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-newinstall") == 0)
|
|
{
|
|
if (!TestNewSxsInstallAPI(argv[++i]))
|
|
goto Exit;
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-tuninstall") == 0
|
|
|| ::FusionpStrCmpI(argv[i], L"-uninstall") == 0)
|
|
{
|
|
TestUninstall(argv[i + 1], argv[i + 2]);
|
|
goto Exit;
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-probemanifest") == 0)
|
|
{
|
|
if (!TestManifestProbing(argc, argv, &i))
|
|
goto Exit;
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-p") == 0)
|
|
{
|
|
if (!TestXMLParsing(argc, argv, &i))
|
|
goto Exit;
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-w32") == 0)
|
|
{
|
|
TestWin32(argv + i + 1);
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-msi") == 0)
|
|
{
|
|
if (!TestMSIInstall(argc, argv, &i))
|
|
goto Exit;
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-mp") == 0)
|
|
{
|
|
if (!TestManifestSchema(argc, argv, &i))
|
|
goto Exit;
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-act") == 0)
|
|
{
|
|
if (!TestAct(argc, argv, &i))
|
|
goto Exit;
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-shatest") == 0)
|
|
{
|
|
if (!TestPrivateSha1Impl(argv[++i]))
|
|
goto Exit;
|
|
}
|
|
else if (::FusionpStrCmpI(argv[1], L"-am") == 0)
|
|
{
|
|
i = TestAssemblyName();
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-tsurrogates") == 0)
|
|
{
|
|
if (!SimpleTestFindAndUseSurrogateInformation(argv[i+1], argv[i+2]))
|
|
goto Exit;
|
|
i += 2;
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-clrhelpers") == 0)
|
|
{
|
|
if (!TestSxsExportedSurrogateStuff(argv[i+1], argv[i+2], argv[i+3]))
|
|
goto Exit;
|
|
i += 3;
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-tsearchpath") == 0)
|
|
{
|
|
if (!TestSearchPath(argc, argv, &i))
|
|
goto Exit;
|
|
}
|
|
else if (!::FusionpStrCmpI(argv[i], L"-testmapping"))
|
|
{
|
|
if (!TestOpeningStuff(argv[i+1], argv[i+2], argv[i+3]))
|
|
goto Exit;
|
|
i += 3;
|
|
}
|
|
else if (!::FusionpStrCmpI(argv[i], L"-validatefile"))
|
|
{
|
|
if (!TestVerifyFileSignature(argv[++i]))
|
|
goto Exit;
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-tloadlibrary") == 0)
|
|
{
|
|
if (!TestLoadLibrary(argc, argv, &i))
|
|
goto Exit;
|
|
}
|
|
else if (!::FusionpStrCmpI(argv[i], L"-refresh"))
|
|
{
|
|
if (!TestRefreshAssembly(argv[i+1]))
|
|
goto Exit;
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-leak") == 0)
|
|
{
|
|
//
|
|
// We dump a little bit of memory
|
|
//
|
|
UINT iAmount = 0;
|
|
iAmount = _wtoi(argv[++i]);
|
|
if (!TestLeakMemory(iAmount))
|
|
goto Exit;
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-tcreateprocess") == 0)
|
|
{
|
|
if (!TestCreateProcess(argv + i + 1))
|
|
goto Exit;
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-tcreateprocess2") == 0)
|
|
{
|
|
if (!TestCreateProcess2(argv + i + 1))
|
|
goto Exit;
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-tinherit") == 0)
|
|
{
|
|
TestInherit();
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-tnoinherit") == 0)
|
|
{
|
|
TestNoInherit();
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-tempty") == 0)
|
|
{
|
|
TestEmpty();
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-ttsappcmp") == 0)
|
|
{
|
|
TestCreateGlobalEvent();
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-tmsgperf") == 0)
|
|
{
|
|
i++;
|
|
if (!TestMessagePerf(argc, argv, &i))
|
|
goto Exit;
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-twinsetup") == 0)
|
|
{
|
|
FusionpSetSystemSetupInProgress(true);
|
|
if (!TestInstallLikeWindowsSetup(argv[i + 1], (argv[i + 2] != NULL) ? argv[i + 2] : argv[i + 1]))
|
|
goto Exit;
|
|
i += 3;
|
|
}
|
|
else if (!::FusionpStrCmpI(argv[i], L"-sfcscan"))
|
|
{
|
|
TestSfcScanKickoff();
|
|
}
|
|
else if (!::FusionpStrCmpI(argv[i], L"-certinfo"))
|
|
{
|
|
GenerateStrongNameAndPublicKey(argv[++i]);
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-thandle") == 0)
|
|
{
|
|
DWORD iAmount = 0;
|
|
iAmount = _wtoi(argv[++i]);
|
|
|
|
TestCreateActctxLeakHandles(iAmount);
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-catsigner") == 0)
|
|
{
|
|
TestNewCatalogSignerThingy(argv[++i]);
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-trefcount") == 0)
|
|
{
|
|
TestRefCount();
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-ttileak") == 0)
|
|
{
|
|
TestThreadInheritLeak();
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-tguidsort") == 0)
|
|
{
|
|
TestGuidSort();
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-tstringsort") == 0)
|
|
{
|
|
TestStringSort();
|
|
}
|
|
else if (::FusionpStrCmpI(argv[i], L"-tExeDll") == 0)
|
|
{
|
|
TestExeDll();
|
|
}
|
|
else if (FusionpStrCmpI(argv[i], L"-tExitProcess") == 0)
|
|
{
|
|
LoadSxs();
|
|
GetSxsProc(SXSP_DEBUG_ORDINAL, &pfnSxspDebug);
|
|
pfnSxspDebug(SXS_DEBUG_EXIT_PROCESS, 0, 0, NULL);
|
|
}
|
|
else if (FusionpStrCmpI(argv[i], L"-tTerminateProcess") == 0)
|
|
{
|
|
LoadSxs();
|
|
GetSxsProc(SXSP_DEBUG_ORDINAL, &pfnSxspDebug);
|
|
pfnSxspDebug(SXS_DEBUG_TERMINATE_PROCESS, 0, 0, NULL);
|
|
}
|
|
else if (FusionpStrCmpI(argv[i], L"-tLastError") == 0)
|
|
{
|
|
::SetLastError(123);
|
|
printf("%lu\n", FusionpGetLastWin32Error());
|
|
printf("%lu\n", ::GetLastError());
|
|
::FusionpSetLastWin32Error(456);
|
|
printf("%lu\n", FusionpGetLastWin32Error());
|
|
printf("%lu\n", ::GetLastError());
|
|
}
|
|
else if (FusionpStrCmpI(argv[i], L"-tGetModuleHandleEx") == 0)
|
|
{
|
|
TestGetModuleHandleEx();
|
|
}
|
|
else if (FusionpStrCmpI(argv[i], L"-tGetFullPathName") == 0)
|
|
{
|
|
TestGetFullPathName(argv[i + 1]);
|
|
}
|
|
else if (FusionpStrCmpI(argv[i], L"-tCreateFile") == 0)
|
|
{
|
|
TestCreateFile(argv[i + 1]);
|
|
}
|
|
else if (FusionpStrCmpI(argv[i], L"-tGetPathBaseName") == 0)
|
|
{
|
|
TestGetPathBaseName(argv[i + 1]);
|
|
}
|
|
else if (FusionpStrCmpI(argv[i], L"-tVersion") == 0)
|
|
{
|
|
TestVersion();
|
|
}
|
|
else if (FusionpStrCmpI(argv[i], L"-tGetProcessImageFileName") == 0)
|
|
{
|
|
TestGetProcessImageFileName();
|
|
}
|
|
else if (FusionpStrCmpI(argv[i], L"-tErrorInfra") == 0)
|
|
{
|
|
TestErrorInfra();
|
|
}
|
|
else if (FusionpStrCmpI(argv[i], L"-tQueryActCtx") == 0)
|
|
TestQueryActCtx();
|
|
else if (FusionpStrCmpI(argv[i], L"-tQueryActCtx2") == 0)
|
|
TestQueryActCtx2();
|
|
else if (FusionpStrCmpI(argv[i], L"-tqmib") == 0)
|
|
{
|
|
TestQueryManifestInformationBasic(argv[i+1]);
|
|
}
|
|
else if (FusionpStrCmpI(argv[i], L"-t64k") == 0)
|
|
{
|
|
Test64k();
|
|
}
|
|
else if (FusionpStrCmpI(argv[i], L"-tcreateactctx") == 0)
|
|
{
|
|
TestCreateActCtx(argc - (i + 1), &argv[i+1]);
|
|
}
|
|
else if (FusionpStrCmpI(argv[i], L"-TestCreateActCtx_PE_flags0") == 0)
|
|
{
|
|
TestCreateActCtx_PE_flags0();
|
|
}
|
|
else if (FusionpStrCmpI(argv[i], L"-tDotLocalSingleInstancing") == 0)
|
|
{
|
|
TestDotLocalSingleInstancing();
|
|
}
|
|
else if (FusionpStrCmpI(argv[i], L"-tCreateActctxLikeCreateProcess") == 0)
|
|
{
|
|
TestCreateActctxLikeCreateProcess();
|
|
}
|
|
else if (FusionpStrCmpI(argv[i], L"-tCreateActctxLikeCreateProcess") == 0)
|
|
{
|
|
TestCreateActctxLikeCreateProcess();
|
|
}
|
|
else if (FusionpStrCmpI(argv[i], L"-tCreateActctxAdminOverride") == 0)
|
|
{
|
|
TestCreateActctxAdminOverride();
|
|
}
|
|
else if (FusionpStrCmpI(argv[i], L"-tCreateActctxWindowsShellManifest") == 0)
|
|
{
|
|
TestCreateActctxWindowsShellManifest();
|
|
}
|
|
else if (FusionpStrCmpI(argv[i], L"-tHandleLeak") == 0)
|
|
{
|
|
//for (ULONG i = 0 ; i != 5 ; i += 1)
|
|
TestHandleLeaks();
|
|
}
|
|
else if (FusionpStrCmpI(argv[i], L"-tMfcCreateAndMarshal") == 0)
|
|
{
|
|
TestMfcCreateAndMarshal();
|
|
}
|
|
else if (FusionpStrCmpI(argv[i], L"-tAtlCreate") == 0)
|
|
{
|
|
TestAtlCreate();
|
|
}
|
|
else if (FusionpStrCmpI(argv[i], L"-TestAlignment") == 0)
|
|
{
|
|
TestAlignment();
|
|
}
|
|
else if (FusionpStrCmpI(argv[i], L"-DoNothingJustSeeIfItRuns") == 0)
|
|
{
|
|
printf("%wZ ran successfully\n", &NtCurrentPeb()->ProcessParameters->ImagePathName);
|
|
}
|
|
else if (FusionpStrCmpI(argv[i], L"-TestImage") == 0)
|
|
{
|
|
TestImage();
|
|
}
|
|
else if (FusionpStrCmpI(argv[i], L"-TestInterlockedAlignment") == 0)
|
|
{
|
|
TestInterlockedAlignment();
|
|
}
|
|
else
|
|
{
|
|
i = Usage(argv0);
|
|
}
|
|
if (g.ThreadExitEvent)
|
|
{
|
|
SetEvent(g.ThreadExitEvent);
|
|
WaitForMultipleObjectsEx(g.NumberOfThreads, g.Threads, TRUE, INFINITE, TRUE);
|
|
}
|
|
if (g.sxsDll != NULL)
|
|
{
|
|
FreeLibrary(g.sxsDll);
|
|
}
|
|
}
|
|
__finally
|
|
{
|
|
FusionpSetSystemSetupInProgress(false);
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
#if DBG
|
|
if (IsDebuggerPresent())
|
|
{
|
|
FUSION_DEBUG_BREAK();
|
|
}
|
|
#endif
|
|
i = GetExceptionCode();
|
|
WCHAR message[128];
|
|
DWORD flags = FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM;
|
|
FormatMessageW(flags, NULL, i, 0, message, NUMBER_OF(message), NULL);
|
|
PWSTR end = message + wcslen(message);
|
|
while (end != message && isspace(*(end - 1)))
|
|
{
|
|
--end;
|
|
}
|
|
*end = 0;
|
|
::Trace("%ls failed, %d, %#x, %ls", g.lastOperation, i, i, message);
|
|
}
|
|
PTEB teb;
|
|
teb = NtCurrentTeb();
|
|
if (teb->CountOfOwnedCriticalSections != 0)
|
|
{
|
|
DbgPrint("teb->CountOfOwnedCriticalSections %d\n", teb->CountOfOwnedCriticalSections);
|
|
//ASSERT(teb->CountOfOwnedCriticalSections == 0);
|
|
}
|
|
|
|
return i ? EXIT_SUCCESS : EXIT_FAILURE;
|
|
}
|
|
return Usage(argv[0]);
|
|
|
|
Exit:
|
|
return ::GetLastError();
|
|
}
|
|
|
|
extern "C" int __cdecl wmain(int argc, wchar_t** argv)
|
|
{
|
|
// NtCurrentTeb()->CountOfOwnedCriticalSections = 0;
|
|
PrintIfAnyCriticalSectionsHeld();
|
|
int i = Main(argc, argv);
|
|
PrintIfAnyCriticalSectionsHeld();
|
|
return i;
|
|
}
|
|
|
|
int TestDiffDir(PCWSTR dir1, PCWSTR dir2)
|
|
{
|
|
CFusionDirectoryDifference diff;
|
|
CStringBuffer buf1;
|
|
CStringBuffer buf2;
|
|
BOOL fSuccess = FALSE;
|
|
|
|
if (!buf1.Win32Assign(dir1, ::wcslen(dir1)))
|
|
goto Exit;
|
|
if (!buf2.Win32Assign(dir2, ::wcslen(dir2)))
|
|
goto Exit;
|
|
|
|
if (!::FusionpCompareDirectoriesSizewiseRecursively(&diff, buf1, buf2))
|
|
goto Exit;
|
|
|
|
diff.DbgPrint(buf1, buf2);
|
|
|
|
fSuccess = TRUE;
|
|
Exit:
|
|
return fSuccess ? EXIT_SUCCESS : EXIT_FAILURE;
|
|
}
|
|
|
|
PCWSTR GetUser()
|
|
{
|
|
static bool fInited;
|
|
static WCHAR userName[MAX_PATH];
|
|
if (!fInited)
|
|
{
|
|
DWORD size = NUMBER_OF(userName);
|
|
userName[0] = 0;
|
|
userName[1] = 0;
|
|
GetUserNameW(userName, &size);
|
|
if (userName[1] == '-')
|
|
{
|
|
wmemcpy(userName, 2+userName, 1+wcslen(2+userName));
|
|
}
|
|
fInited = true;
|
|
}
|
|
return userName;
|
|
}
|
|
|
|
void UserBreakPoint(PCWSTR user)
|
|
{
|
|
if (::IsDebuggerPresent() && _wcsicmp(GetUser(), user) == 0)
|
|
{
|
|
ASSERT2_NTC(FALSE, __FUNCTION__);
|
|
}
|
|
}
|
|
|
|
void LoadSxs()
|
|
{
|
|
WCHAR ExePath[MAX_PATH];
|
|
if (g.sxsDll == NULL)
|
|
{
|
|
SetLastOperation(L"LoadLibrary(SXS.DLL)");
|
|
// sxstest is often run from nt\base\win32\fusion\tests\sxstest\whistler\obj\i386\sxstest.exe; try loading sxs.dll
|
|
// via a relative path first
|
|
g.sxsDll = ::LoadLibraryW(L"..\\..\\..\\..\\..\\dll\\whistler\\obj\\i386\\SXS.DLL");
|
|
if (g.sxsDll == NULL)
|
|
{
|
|
GetModuleFileNameW(NULL, ExePath, NUMBER_OF(ExePath));
|
|
wcscpy(1 + wcsrchr(ExePath, '\\'), L"SXS.DLL");
|
|
g.sxsDll = ::LoadLibraryW(ExePath);
|
|
}
|
|
if (g.sxsDll == NULL)
|
|
g.sxsDll = ::LoadLibraryW(L"SXS.DLL");
|
|
if (g.sxsDll == NULL)
|
|
ThrowLastError();
|
|
UserBreakPoint(L"JayKrell");
|
|
}
|
|
}
|
|
|
|
template <typename PFN>
|
|
void GetSxsProc(int name, PFN* ppfn)
|
|
{
|
|
SetLastOperation(L"GetProcAddress(#%d)", name);
|
|
if (!(*ppfn = reinterpret_cast<PFN>(GetProcAddress(g.sxsDll, reinterpret_cast<PCSTR>(IntToPtr(name))))))
|
|
{
|
|
ThrowLastError();
|
|
}
|
|
}
|
|
|
|
template <typename PFN>
|
|
void GetSxsProc(PCSTR name, PFN* ppfn)
|
|
{
|
|
SetLastOperation(L"GetProcAddress(%hs)", name);
|
|
if (!(*ppfn = reinterpret_cast<PFN>(GetProcAddress(g.sxsDll, name))))
|
|
{
|
|
ThrowLastError();
|
|
}
|
|
}
|
|
|
|
class CCopyQueueElement : public std::pair<std::wstring, std::wstring>
|
|
{
|
|
typedef std::pair<std::wstring, std::wstring> Base;
|
|
public:
|
|
CCopyQueueElement() { }
|
|
|
|
CCopyQueueElement(const first_type& source, const second_type& target)
|
|
:
|
|
Base(source, target)
|
|
{
|
|
}
|
|
|
|
first_type& Source() { return first; }
|
|
const first_type& Source() const { return first; }
|
|
second_type& Target() { return second; }
|
|
const second_type& Target() const { return second; }
|
|
};
|
|
|
|
template <typename T> class StdDeque : public std::deque<T, Allocator<T> > { };
|
|
template <typename T> class StdVector : public std::vector<T, Allocator<T> > { };
|
|
|
|
class CCopyQueue : public StdDeque<CCopyQueueElement>
|
|
{
|
|
typedef StdDeque<CCopyQueueElement> Base;
|
|
public:
|
|
BOOL Callback(
|
|
PSXS_INSTALLATION_FILE_COPY_CALLBACK_PARAMETERS parameters
|
|
)
|
|
{
|
|
push_back(value_type(parameters->pSourceFile, parameters->pDestinationFile));
|
|
|
|
parameters->nDisposition = SXS_INSTALLATION_FILE_COPY_DISPOSITION_FILE_QUEUED;
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL WINAPI StaticCallback(
|
|
PSXS_INSTALLATION_FILE_COPY_CALLBACK_PARAMETERS parameters
|
|
)
|
|
{
|
|
CCopyQueue* pThis = reinterpret_cast<CCopyQueue*>(parameters->pvContext);
|
|
BOOL fResult = pThis->Callback(parameters);
|
|
return fResult;
|
|
}
|
|
|
|
BOOL Flush()
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
for (; !empty() ; pop_back())
|
|
{
|
|
const std::wstring& target = back().Target();
|
|
const std::wstring targetDir = target.substr(0, target.find_last_of('\\'));
|
|
FusionpCreateDirectories(targetDir.c_str(), ::wcslen(targetDir.c_str()));
|
|
if (!CopyFileW(back().Source().c_str(), target.c_str(), TRUE))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
fSuccess = TRUE;
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
};
|
|
|
|
int
|
|
TestInstall(
|
|
PCWSTR manifest,
|
|
__int64 flags,
|
|
DWORD beginInstallFlags,
|
|
DWORD installFlags,
|
|
DWORD endInstallFlags
|
|
)
|
|
{
|
|
PrintIfAnyCriticalSectionsHeld();
|
|
|
|
BOOL fSuccess = FALSE;
|
|
PVOID installCookie = NULL;
|
|
PSXS_BEGIN_ASSEMBLY_INSTALL sxsBeginAssemblyInstall = NULL;
|
|
PSXS_INSTALL_ASSEMBLY_W sxsInstallAssemblyW = NULL;
|
|
PSXS_END_ASSEMBLY_INSTALL sxsEndAssemblyInstall = NULL;
|
|
CCopyQueue copyQueue;
|
|
BOOL fCleanup = FALSE;
|
|
SXS_INSTALL_SOURCE_INFO SxsInstallInfo = {0};
|
|
|
|
|
|
PSXS_INSTALLATION_FILE_COPY_CALLBACK callback = NULL;
|
|
PVOID context = NULL;
|
|
HSPFILEQ hSetupCopyQueue = INVALID_HANDLE_VALUE;
|
|
PVOID pDefaultSetupCopyQueueContext = NULL;
|
|
|
|
LoadSxs();
|
|
GetSxsProc("SxsBeginAssemblyInstall", &sxsBeginAssemblyInstall);
|
|
GetSxsProc("SxsInstallAssemblyW", &sxsInstallAssemblyW);
|
|
GetSxsProc("SxsEndAssemblyInstall", &sxsEndAssemblyInstall);
|
|
|
|
if (flags & SXSTEST_INSTALL_MY_QUEUE)
|
|
{
|
|
callback = &CCopyQueue::StaticCallback;
|
|
context = ©Queue;
|
|
}
|
|
else if (flags & SXSTEST_INSTALL_SETUPAPI_QUEUE)
|
|
{
|
|
callback = SXS_INSTALLATION_FILE_COPY_CALLBACK_SETUP_COPY_QUEUE;
|
|
if (INVALID_HANDLE_VALUE == (hSetupCopyQueue = SetupOpenFileQueue()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
context = hSetupCopyQueue; // random non NULL, step through, then stop debugging
|
|
#if DBG
|
|
FUSION_DEBUG_BREAK();
|
|
#endif
|
|
}
|
|
|
|
PrintIfAnyCriticalSectionsHeld();
|
|
|
|
if (!(*sxsBeginAssemblyInstall)(
|
|
beginInstallFlags,
|
|
callback,
|
|
context,
|
|
NULL, // ImpersonationCallback,
|
|
NULL, // ImpersonationContext,
|
|
&installCookie))
|
|
{
|
|
goto Exit;
|
|
}
|
|
fCleanup = TRUE;
|
|
|
|
PrintIfAnyCriticalSectionsHeld();
|
|
|
|
memset(&SxsInstallInfo, 0, sizeof(SxsInstallInfo));
|
|
SxsInstallInfo.cbSize = sizeof(SxsInstallInfo);
|
|
SxsInstallInfo.dwFlags = SXSINSTALLSOURCE_INSTALLING_SETUP | SXSINSTALLSOURCE_HAS_CODEBASE;
|
|
SxsInstallInfo.pcwszCodebaseName = manifest;
|
|
|
|
fSuccess = sxsInstallAssemblyW(
|
|
installCookie,
|
|
installFlags | SXS_INSTALL_ASSEMBLY_FLAG_FROM_DIRECTORY_RECURSIVE | SXS_INSTALL_ASSEMBLY_FLAG_INCLUDE_CODEBASE,
|
|
manifest,
|
|
&SxsInstallInfo);
|
|
|
|
PrintIfAnyCriticalSectionsHeld();
|
|
|
|
fSuccess = copyQueue.Flush();
|
|
Exit:
|
|
if (fCleanup)
|
|
{
|
|
if (flags & SXSTEST_INSTALL_SETUPAPI_QUEUE)
|
|
{
|
|
if (!(pDefaultSetupCopyQueueContext = ::SetupInitDefaultQueueCallback(NULL)))
|
|
{
|
|
fSuccess = FALSE;
|
|
}
|
|
if (fSuccess && !::SetupCommitFileQueue(NULL,
|
|
hSetupCopyQueue,
|
|
SetupDefaultQueueCallback,
|
|
pDefaultSetupCopyQueueContext))
|
|
{
|
|
fSuccess = FALSE;
|
|
}
|
|
if (hSetupCopyQueue != INVALID_HANDLE_VALUE)
|
|
{
|
|
::SetupCloseFileQueue(hSetupCopyQueue);
|
|
hSetupCopyQueue = NULL;
|
|
}
|
|
}
|
|
|
|
sxsEndAssemblyInstall(installCookie, endInstallFlags | (fSuccess ? SXS_END_ASSEMBLY_INSTALL_FLAG_COMMIT : SXS_END_ASSEMBLY_INSTALL_FLAG_ABORT), NULL);
|
|
}
|
|
|
|
PrintIfAnyCriticalSectionsHeld();
|
|
|
|
if (!fSuccess)
|
|
{
|
|
fprintf(stderr, "%s failed!\n", __FUNCTION__);
|
|
return EXIT_FAILURE;
|
|
}
|
|
else
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
BOOL
|
|
TestManifestSchema(
|
|
int argc,
|
|
wchar_t** argv,
|
|
int* piNext
|
|
)
|
|
{
|
|
SXSP_DEBUG_FUNCTION& pfn = pfnSxspDebug;
|
|
BOOL fSuccess = FALSE;
|
|
|
|
int i = (*piNext) + 1;
|
|
|
|
if (i >= argc)
|
|
{
|
|
fprintf(stderr, "%S: Missing parameter after \"%S\"\n", argv[0], argv[i-1]);
|
|
goto Exit;
|
|
}
|
|
|
|
LoadSxs();
|
|
|
|
GetSxsProc(SXSP_DEBUG_ORDINAL, &pfn);
|
|
|
|
fSuccess = (*pfn)(SXS_DEBUG_CHECK_MANIFEST_SCHEMA, 0, argv[i++], NULL);
|
|
|
|
if (!fSuccess)
|
|
{
|
|
fprintf(stderr, "%s failed!\n", __FUNCTION__);
|
|
goto Exit;
|
|
}
|
|
|
|
*piNext = i;
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
BOOL
|
|
TestXMLParsing(
|
|
int argc,
|
|
wchar_t** argv,
|
|
int* piNext)
|
|
{
|
|
SXSP_DEBUG_FUNCTION pfn = NULL;
|
|
BOOL fSuccess = FALSE;
|
|
int i = (*piNext) + 1;
|
|
|
|
if (i >= argc)
|
|
{
|
|
fprintf(stderr, "%S: missing parameter after \"%S\"\n", argv[0], argv[i-1]);
|
|
goto Exit;
|
|
}
|
|
|
|
LoadSxs();
|
|
|
|
GetSxsProc(SXSP_DEBUG_ORDINAL, &pfn);
|
|
|
|
fSuccess = (*pfn)(SXS_DEBUG_XML_PARSER, 0, argv[i], NULL);
|
|
|
|
if (!fSuccess)
|
|
{
|
|
fprintf(stderr, "%s failed!\n", __FUNCTION__);
|
|
goto Exit;
|
|
}
|
|
|
|
*piNext = i + 1;
|
|
fSuccess = TRUE;
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
BOOL
|
|
TestDirect(
|
|
int argc,
|
|
wchar_t** argv,
|
|
int* piNext)
|
|
{
|
|
SXSP_DEBUG_FUNCTION pfn = NULL;
|
|
BOOL fSuccess = FALSE;
|
|
int i = (*piNext) + 1;
|
|
|
|
if (i >= argc)
|
|
{
|
|
fprintf(stderr, "%S: missing parameter after \"%S\"\n", argv[0], argv[i-1]);
|
|
goto Exit;
|
|
}
|
|
|
|
LoadSxs();
|
|
|
|
GetSxsProc(SXSP_DEBUG_ORDINAL, &pfn);
|
|
|
|
fSuccess = (*pfn)(SXS_DEBUG_DLL_REDIRECTION, 0, argv[i], NULL);
|
|
|
|
if (!fSuccess)
|
|
{
|
|
fprintf(stderr, "%s failed!\n", __FUNCTION__);
|
|
goto Exit;
|
|
}
|
|
|
|
*piNext = i + 1;
|
|
fSuccess = TRUE;
|
|
Exit:
|
|
return fSuccess;
|
|
|
|
}
|
|
|
|
VOID
|
|
PrintBlob(
|
|
FILE *pf,
|
|
PVOID Data,
|
|
SIZE_T Length,
|
|
PCWSTR PerLinePrefix
|
|
)
|
|
{
|
|
ULONG Offset = 0;
|
|
|
|
if (PerLinePrefix == NULL)
|
|
PerLinePrefix = L"";
|
|
|
|
// we'll output in 8-byte chunks as shown:
|
|
//
|
|
// [prefix]Binary section %p (%d bytes)
|
|
// [prefix] 00000000: xx-xx-xx-xx-xx-xx-xx-xx (........)
|
|
// [prefix] 00000008: xx-xx-xx-xx-xx-xx-xx-xx (........)
|
|
// [prefix] 00000010: xx-xx-xx-xx-xx-xx-xx-xx (........)
|
|
//
|
|
|
|
while (Length >= 8)
|
|
{
|
|
BYTE *pb = (BYTE *) (((ULONG_PTR) Data) + Offset);
|
|
|
|
fprintf(
|
|
pf,
|
|
"%S %08lx: %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x (%c%c%c%c%c%c%c%c)\n",
|
|
PerLinePrefix,
|
|
Offset,
|
|
pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7],
|
|
PRINTABLE(pb[0]),
|
|
PRINTABLE(pb[1]),
|
|
PRINTABLE(pb[2]),
|
|
PRINTABLE(pb[3]),
|
|
PRINTABLE(pb[4]),
|
|
PRINTABLE(pb[5]),
|
|
PRINTABLE(pb[6]),
|
|
PRINTABLE(pb[7]));
|
|
|
|
Offset += 8;
|
|
Length -= 8;
|
|
}
|
|
|
|
if (Length != 0)
|
|
{
|
|
CStringBuffer buffTemp;
|
|
bool First = true;
|
|
ULONG i;
|
|
BYTE *pb = (BYTE *) (((ULONG_PTR) Data) + Offset);
|
|
|
|
buffTemp.Win32ResizeBuffer(48, eDoNotPreserveBufferContents);
|
|
|
|
buffTemp.Win32Format(L" %08lx: ", Offset);
|
|
|
|
for (i=0; i<8; i++)
|
|
{
|
|
if (Length > 0)
|
|
{
|
|
if (!First)
|
|
buffTemp.Win32Append("-", 1);
|
|
else
|
|
First = false;
|
|
|
|
buffTemp.Win32FormatAppend(L"%02x", pb[i]);
|
|
|
|
Length--;
|
|
}
|
|
else
|
|
{
|
|
buffTemp.Win32Append(" ", 3);
|
|
}
|
|
}
|
|
|
|
buffTemp.Win32Append(" (", 2);
|
|
|
|
i = 0;
|
|
|
|
while (Length != 0)
|
|
{
|
|
CHAR chTemp = static_cast<CHAR>(PRINTABLE(pb[i]));
|
|
i++;
|
|
buffTemp.Win32Append(&chTemp, 1);
|
|
Length--;
|
|
}
|
|
|
|
buffTemp.Win32Append(L")", 1);
|
|
|
|
fprintf(
|
|
pf,
|
|
"%S%S\n",
|
|
PerLinePrefix,
|
|
static_cast<PCWSTR>(buffTemp));
|
|
}
|
|
}
|
|
|
|
void __stdcall TestWin32Apc(ULONG_PTR arg)
|
|
{
|
|
ACTCTXW ac = {sizeof(ac)};
|
|
int error = 0;
|
|
PWSTR source = reinterpret_cast<PWSTR>(arg);
|
|
HANDLE hActCtx = NULL;
|
|
BOOL fSuccess = FALSE;
|
|
|
|
ac.lpSource = source;
|
|
PWSTR pound = wcschr(source, '#');
|
|
if (pound != NULL)
|
|
{
|
|
*pound = 0;
|
|
ac.lpResourceName = pound + 1;
|
|
ac.dwFlags |= ACTCTX_FLAG_RESOURCE_NAME_VALID;
|
|
}
|
|
ac.wProcessorArchitecture = g.wProcessorArchitecture;
|
|
ac.wLangId = g.wLangId;
|
|
hActCtx = ::CreateActCtxW(&ac);
|
|
if (hActCtx == INVALID_HANDLE_VALUE)
|
|
{
|
|
error = ::GetLastError();
|
|
fwprintf(stderr, L"CreateActCtxW(%ls) failed; ::GetLastError() = %d\n", source, error);
|
|
goto Exit;
|
|
}
|
|
//fSuccess = ::ReleaseActCtx(hActCtx);
|
|
fSuccess = TRUE;
|
|
hActCtx = NULL;
|
|
if (!fSuccess)
|
|
{
|
|
error = ::GetLastError();
|
|
goto Exit;
|
|
}
|
|
Exit:
|
|
if (error)
|
|
ThrowWin32(error);
|
|
}
|
|
|
|
void
|
|
TestWin32(
|
|
wchar_t** argv
|
|
)
|
|
{
|
|
CreateThreads();
|
|
int i = 0;
|
|
|
|
for (i = 0 ; argv[i] ; ++i)
|
|
{
|
|
if (g.NumberOfThreads)
|
|
{
|
|
if (!QueueUserAPC(TestWin32Apc, g.Threads[i % g.NumberOfThreads], reinterpret_cast<ULONG_PTR>(argv[i])))
|
|
{
|
|
fprintf(stderr, "QueueUserAPC() failed\n");
|
|
ThrowWin32(((ULONG_PTR) (LONG_PTR) -1));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TestWin32Apc(reinterpret_cast<ULONG_PTR>(argv[i]));
|
|
}
|
|
}
|
|
}
|
|
#if BETA1
|
|
const static WCHAR InheritManifest[] =
|
|
L"<assembly manifestversion=\"1.0\" name=\"InheritManifest\">"
|
|
L"<dependency assemblyname=\"Microsoft-Visual-CPlusPlus-Runtime-Libraries\" version=\"6.0.0.0\" language=\"0000\"/>"
|
|
L"</assembly>"
|
|
;
|
|
#else // suppose to be BETA2 or later
|
|
const static WCHAR InheritManifest[] =
|
|
L"<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
|
|
L"<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.SystemCompatibleAssembly\" version=\"1.0.0.0\" processorArchitecture=\"x86\" />"
|
|
L"<description>System Compatible Default</description> "
|
|
L"<dependency> <dependentAssembly>"
|
|
L"<assemblyIdentity type=\"win32\" name=\"Microsoft.Tools.VisualCPlusPlus.Runtime-Libraries\" version=\"6.0.0.0\" language=\"*\" processorArchitecture=\"x86\" publicKeyToken=\"6595b64144ccf1df\" />"
|
|
L"</dependentAssembly> </dependency></assembly>"
|
|
;
|
|
#endif
|
|
|
|
|
|
const static WCHAR NoInheritManifest[] =
|
|
L"<assembly manifestversion=\"1.0\" name=\"InheritManifest\">"
|
|
L"<dependency assemblyname=\"Microsoft-Visual-CPlusPlus-Runtime-Libraries\" version=\"6.0.0.0\" language=\"0000\"/>"
|
|
L"<noinherit/>"
|
|
L"</assembly>"
|
|
;
|
|
|
|
const static WCHAR RefCountManifest[] =
|
|
L"<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
|
|
L"<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.SxsTest.RefCount\" version=\"1.0.0.0\" processorArchitecture=\"x86\" />"
|
|
L"<description>blah</description> "
|
|
L"<dependency><dependentAssembly>"
|
|
//L"<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.SxsTest1\" version=\"1.0.0.0\" language=\"*\" processorArchitecture=\"x86\" publicKeyToken=\"6595b64144ccf1df\" />"
|
|
L"<assemblyIdentity type=\"win32\" name=\"Microsoft.Tools.VisualCPlusPlus.Runtime-Libraries\" version=\"6.0.0.0\" language=\"*\" processorArchitecture=\"x86\" publicKeyToken=\"6595b64144ccf1df\" />"
|
|
L"</dependentAssembly> </dependency></assembly>"
|
|
;
|
|
|
|
// to test the empty actctx, we push this, probe, push empty, probe
|
|
const static PCWSTR DependentOnMsvc6Manifest = InheritManifest;
|
|
|
|
WCHAR SearchPathResult[MAX_PATH];
|
|
|
|
void ProbeContext(const char* Function, PCWSTR Dll = L"msvcrt.dll")
|
|
{
|
|
SearchPathResult[0] = 0;
|
|
SearchPathW(NULL, Dll, NULL, NUMBER_OF(SearchPathResult), SearchPathResult, NULL);
|
|
|
|
DbgPrint("%s %ls\n", Function, SearchPathResult);
|
|
}
|
|
|
|
DWORD CALLBACK InheritThreadMain(VOID*)
|
|
{
|
|
ProbeContext(__FUNCTION__);
|
|
return 0;
|
|
}
|
|
|
|
DWORD CALLBACK NoinheritThreadMain(VOID*)
|
|
{
|
|
ProbeContext(__FUNCTION__);
|
|
return 0;
|
|
}
|
|
|
|
void TestInherit()
|
|
{
|
|
ProbeContext(__FUNCTION__);
|
|
HANDLE ActivationContextHandle = ::CreateActivationContextFromStringW(InheritManifest);
|
|
ULONG_PTR Cookie;
|
|
ActivateActCtx(ActivationContextHandle, &Cookie);
|
|
ProbeContext(__FUNCTION__);
|
|
DWORD ThreadId;
|
|
WaitForSingleObject(CreateThread(NULL, 0, InheritThreadMain, NULL, 0, &ThreadId), INFINITE);
|
|
}
|
|
|
|
void TestNoInherit()
|
|
{
|
|
ProbeContext(__FUNCTION__);
|
|
HANDLE ActivationContextHandle = ::CreateActivationContextFromStringW(NoInheritManifest);
|
|
ULONG_PTR Cookie;
|
|
ActivateActCtx(ActivationContextHandle, &Cookie);
|
|
ProbeContext(__FUNCTION__);
|
|
DWORD ThreadId;
|
|
WaitForSingleObject(CreateThread(NULL, 0, NoinheritThreadMain, NULL, 0, &ThreadId), INFINITE);
|
|
}
|
|
|
|
void TestEmpty()
|
|
{
|
|
ProbeContext(__FUNCTION__);
|
|
HANDLE ActivationContextHandle = ::CreateActivationContextFromStringW(DependentOnMsvc6Manifest);
|
|
ULONG_PTR Cookie1, Cookie2;
|
|
ActivateActCtx(ActivationContextHandle, &Cookie1);
|
|
ProbeContext(__FUNCTION__);
|
|
ActivateActCtx(ACTCTX_EMPTY, &Cookie2);
|
|
ProbeContext(__FUNCTION__);
|
|
DeactivateActCtx(0, Cookie2);
|
|
ProbeContext(__FUNCTION__);
|
|
DeactivateActCtx(0, Cookie1);
|
|
ProbeContext(__FUNCTION__);
|
|
}
|
|
|
|
#if 0
|
|
|
|
#define SXSTEST_NTOPENFILE_RET NTSTATUS
|
|
#define SXSTEST_NTOPENFILE_CALL NTAPI
|
|
#define SXSTEST_NTOPENFILE_ARG_NAMES_TYPES \
|
|
(\
|
|
OUT PHANDLE FileHandle, \
|
|
IN ACCESS_MASK DesiredAccess, \
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes, \
|
|
OUT PIO_STATUS_BLOCK IoStatusBlock, \
|
|
IN ULONG ShareAccess, \
|
|
IN ULONG OpenOptions \
|
|
)
|
|
|
|
#define SXSTEST_NTCREATEFILE_RET NTSTATUS
|
|
#define SXSTEST_NTCREATEFILE_CALL NTAPI
|
|
#define SXSTEST_NTCREATEFILE_ARG_NAMES_TYPES \
|
|
(\
|
|
OUT PHANDLE FileHandle, \
|
|
IN ACCESS_MASK DesiredAccess, \
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes, \
|
|
OUT PIO_STATUS_BLOCK IoStatusBlock, \
|
|
IN PLARGE_INTEGER AllocationSize OPTIONAL, \
|
|
IN ULONG FileAttributes, \
|
|
IN ULONG ShareAccess, \
|
|
IN ULONG CreateDisposition, \
|
|
IN ULONG CreateOptions, \
|
|
IN PVOID EaBuffer OPTIONAL, \
|
|
IN ULONG EaLength \
|
|
)
|
|
|
|
SXSTEST_NTCREATEFILE_RET (SXSTEST_NTCREATEFILE_CALL* SxsTestDynamicNtCreateFileTrampoline)(...);
|
|
|
|
SXSTEST_NTCREATEFILE_RET
|
|
DETOUR_TRAMPOLINE(
|
|
SXSTEST_NTCREATEFILE_RET SXSTEST_NTCREATEFILE_CALL SxsTestNtCreateFileTrampoline SXSTEST_NTCREATEFILE_ARG_NAMES_TYPES,
|
|
NtCreateFile
|
|
);
|
|
|
|
DETOUR_TRAMPOLINE(
|
|
SXSTEST_NTOPENFILE_RET SXSTEST_NTOPENFILE_CALL SxsTestNtOpenFileTrampoline SXSTEST_NTCREATEFILE_ARG_NAMES_TYPES,
|
|
NtOpenFile
|
|
);
|
|
|
|
#endif
|
|
|
|
void TestRefCount()
|
|
{
|
|
//
|
|
// 1) newly created actctx has refcount==1
|
|
// 2) activated actctx has refcount==1
|
|
// 3) load a library with no deps with actctx, refcount==2
|
|
// 4) freelibrary, refcount==1
|
|
// directory of library is closed
|
|
// 5) release actctx refcount==0
|
|
//
|
|
// First order, just step through the code to look at the refcount.
|
|
// Second order, "detour" like crazy and look at the memory
|
|
// (including detouring away RtlFreeHeap, NtUnmapViewOfSection)
|
|
//
|
|
|
|
HANDLE ActivationContextHandle = ::CreateActivationContextFromStringW(RefCountManifest);
|
|
ULONG_PTR Cookie1;
|
|
ActivateActCtx(ActivationContextHandle, &Cookie1);
|
|
FreeLibrary(LoadLibraryW(L"msvcrt.dll"));
|
|
DeactivateActCtx(0, Cookie1);
|
|
ReleaseActCtx(ActivationContextHandle);
|
|
|
|
#if 0
|
|
WCHAR RenameDirectorySource[MAX_PATH];
|
|
WCHAR RenameDirectoryDestination[MAX_PATH];
|
|
|
|
//
|
|
// Try to rename the directory.
|
|
//
|
|
DbgPrint("dll was loaded from %ls, now see if we can rename that directory\n", SearchPathResult);
|
|
|
|
wcscpy(RenameDirectorySource, SearchPathResult);
|
|
*wcsrchr(SearchPathResult, '\\') = 0;
|
|
wcscpy(RenameDirectoryDestination, RenameDirectorySource);
|
|
wcscpy(wcsrchr(RenameDirectoryDestination, '\\'), L"blah");
|
|
|
|
BOOL Success = MoveFileW(RenameDirectorySource, RenameDirectoryDestination);
|
|
int Error = ::GetLastError();
|
|
DbgPrint("MoveFile(%ls -> %ls) %s, Error=%d\n",
|
|
RenameDirectorySource, RenameDirectoryDestination, Success ? "succeeded" : "failed", Error);
|
|
#endif
|
|
}
|
|
|
|
GUID Guids[100];
|
|
WCHAR GuidStrings[100][64];
|
|
|
|
void FormatGuid(WCHAR* String, const GUID& Guid)
|
|
{
|
|
swprintf(
|
|
String,
|
|
L"%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
|
Guid.Data1,
|
|
Guid.Data2,
|
|
Guid.Data3,
|
|
Guid.Data4[0], Guid.Data4[1], Guid.Data4[2], Guid.Data4[3],
|
|
Guid.Data4[4], Guid.Data4[5], Guid.Data4[6], Guid.Data4[7]);
|
|
}
|
|
|
|
extern "C" HRESULT __stdcall
|
|
DllGetClassObject(
|
|
REFCLSID rclsid, //CLSID for the class object
|
|
REFIID riid, //Reference to the identifier of the interface
|
|
// that communicates with the class object
|
|
LPVOID * ppv //Address of output variable that receives the
|
|
// interface pointer requested in riid
|
|
)
|
|
{
|
|
WCHAR GuidString[64];
|
|
|
|
FormatGuid(GuidString, rclsid);
|
|
printf("%s : {%ls}\n", __FUNCTION__, GuidString);
|
|
|
|
if (riid == IID_IUnknown)
|
|
{
|
|
*ppv = &g.unknown;
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
return E_NOINTERFACE;
|
|
}
|
|
}
|
|
|
|
void TestGuidSort()
|
|
{
|
|
const int MAX = 100;
|
|
FN_TRACE_SMART_TLS();
|
|
|
|
CStringBuffer Manifest;
|
|
int i = 0;
|
|
|
|
Ole32.CoInitialize(NULL);
|
|
|
|
Manifest.Win32ResizeBuffer(1 << 15, eDoNotPreserveBufferContents);
|
|
Manifest.Win32Format(
|
|
L"<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\"> \
|
|
<assemblyIdentity \
|
|
type=\"win32\" \
|
|
name=\"Microsoft.Windows.SxsTest.GuidSort\" \
|
|
version=\"1.0.0.0\" \
|
|
processorArchitecture=\"x86\" \
|
|
publicKeyToken=\"6595b64144ccf1df\" \
|
|
/> \
|
|
<file name=\"sxstest.exe\">");
|
|
|
|
for (i = 0 ; i < MAX ; ++i)
|
|
{
|
|
GUID& Guid = Guids[i];
|
|
CoCreateGuid(&Guid);
|
|
|
|
FormatGuid(GuidStrings[i], Guid);
|
|
if (!Manifest.Win32FormatAppend(
|
|
L"\n<comClass description=\"a%d\" clsid=\"{%ls}\"/>",
|
|
i,
|
|
static_cast<PCWSTR>(GuidStrings[i])))
|
|
ThrowLastError();
|
|
}
|
|
|
|
if (!Manifest.Win32FormatAppend(L"\n</file>\n</assembly>"))
|
|
ThrowLastError();
|
|
|
|
//LoadSxs();
|
|
//GetSxsProc(SXSP_DEBUG_ORDINAL, &pfn);
|
|
//fSuccess = (*pfn)(SXS_DEBUG_DLL_REDIRECTION, 0, argv[i], NULL);
|
|
|
|
printf("%ls\n", static_cast<PCWSTR>(Manifest));
|
|
|
|
HANDLE ActivationContextHandle = ::CreateActivationContextFromStringW(Manifest);
|
|
ULONG_PTR Cookie1;
|
|
ActivateActCtx(ActivationContextHandle, &Cookie1);
|
|
for (i = 0 ; i < MAX ; ++i)
|
|
{
|
|
HRESULT hr;
|
|
PVOID pv = NULL;
|
|
|
|
hr = Ole32.CoCreateInstance(Guids[i], NULL, CLSCTX_INPROC, IID_IUnknown, &pv);
|
|
printf("CoCreateInstance({%ls}): %08lx%s%s%s\n",
|
|
|
|
GuidStrings[i],
|
|
|
|
static_cast<unsigned long>(hr),
|
|
|
|
( (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
|
|
|| hr == REGDB_E_CLASSNOTREG
|
|
|| (hr == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER))
|
|
|| (hr == E_NOINTERFACE)
|
|
) ? "(" : "",
|
|
|
|
(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
|
|
? "ERROR_FILE_NOT_FOUND"
|
|
: (hr == REGDB_E_CLASSNOTREG)
|
|
? "REGDB_E_CLASSNOTREG"
|
|
: (hr == ERROR_INVALID_PARAMETER)
|
|
? "ERROR_INVALID_PARAMETER"
|
|
: (hr == E_NOINTERFACE)
|
|
? "E_NOINTERFACE (ok)"
|
|
: "",
|
|
|
|
( hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
|
|
|| hr == REGDB_E_CLASSNOTREG
|
|
|| hr == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER))
|
|
|| hr == E_NOINTERFACE
|
|
? ")" : "");
|
|
}
|
|
DeactivateActCtx(0, Cookie1);
|
|
ReleaseActCtx(ActivationContextHandle);
|
|
}
|
|
|
|
void TestStringSort()
|
|
{
|
|
/*
|
|
Mike says this takes between 2 and 7 to visit the code.
|
|
*/
|
|
const int MAX = 50;
|
|
FN_TRACE_SMART_TLS();
|
|
WCHAR ExePath[MAX_PATH];
|
|
CStringBuffer DllPaths[MAX];
|
|
|
|
CStringBuffer Manifest;
|
|
int i = 0;
|
|
|
|
if (!Kernel32.GetModuleFileNameW(NULL, ExePath, RTL_NUMBER_OF(ExePath)))
|
|
ThrowLastError();
|
|
|
|
if (!Manifest.Win32ResizeBuffer(1 << 15, eDoNotPreserveBufferContents))
|
|
ThrowLastError();
|
|
if (!Manifest.Win32Format(
|
|
L"<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\"> \
|
|
<assemblyIdentity \
|
|
type=\"win32\" \
|
|
name=\"Microsoft.Windows.SxsTest.StringSort\" \
|
|
version=\"1.0.0.0\" \
|
|
processorArchitecture=\"x86\" \
|
|
publicKeyToken=\"6595b64144ccf1df\" \
|
|
/> \
|
|
<file name=\"sxstest.exe\"/>"))
|
|
ThrowLastError();
|
|
for (i = 0 ; i < MAX ; ++i)
|
|
{
|
|
if (!DllPaths[i].Win32Format(L"%ls.%d.dll", ExePath, i))
|
|
ThrowLastError();
|
|
|
|
if (!::CopyFileW(ExePath, DllPaths[i], FALSE))
|
|
ThrowLastError();
|
|
|
|
SetDllBitInPeImage(DllPaths[i]);
|
|
|
|
if (!Manifest.Win32FormatAppend(L"\n<file name=\"%ls\"/>\n", 1 + wcsrchr(static_cast<PCWSTR>(DllPaths[i]), '\\')))
|
|
ThrowLastError();
|
|
}
|
|
if (!Manifest.Win32FormatAppend(L"\n</assembly>"))
|
|
ThrowLastError();
|
|
|
|
//LoadSxs();
|
|
//GetSxsProc(SXSP_DEBUG_ORDINAL, &pfn);
|
|
//fSuccess = (*pfn)(SXS_DEBUG_DLL_REDIRECTION, 0, argv[i], NULL);
|
|
|
|
printf("%ls\n", static_cast<PCWSTR>(Manifest));
|
|
|
|
HANDLE ActivationContextHandle = ::CreateActivationContextFromStringW(Manifest);
|
|
ULONG_PTR Cookie1;
|
|
ActivateActCtx(ActivationContextHandle, &Cookie1);
|
|
for (i = 0 ; i < MAX ; ++i)
|
|
{
|
|
HMODULE h;
|
|
PCWSTR DllName = 1 + wcsrchr(DllPaths[i], '\\');
|
|
|
|
h = ::LoadLibraryW(DllName);
|
|
printf("LoadLibrary(%ls):%p, LastError=%d\n",
|
|
DllName,
|
|
h,
|
|
::GetLastError());
|
|
//FreeLibrary(h);
|
|
::DeleteFileW(DllPaths[i]);
|
|
}
|
|
DeactivateActCtx(0, Cookie1);
|
|
ReleaseActCtx(ActivationContextHandle);
|
|
}
|
|
|
|
int
|
|
TestSearchPathHelper1(
|
|
PCSTR RunId,
|
|
PCWSTR Path,
|
|
PCWSTR File,
|
|
PCWSTR Extension,
|
|
bool GetFilePart,
|
|
ULONG cch
|
|
)
|
|
{
|
|
WCHAR Buffer[65536]; // we know that the underlying code can never use a buffer this big
|
|
PWSTR FilePart = NULL;
|
|
PWSTR *lpFilePart = (GetFilePart ? &FilePart : NULL);
|
|
SetLastError(ERROR_GEN_FAILURE);
|
|
ULONG Result = ::SearchPathW(
|
|
Path,
|
|
File,
|
|
Extension,
|
|
0,
|
|
NULL,
|
|
lpFilePart);
|
|
|
|
printf("SearchPath() RunId = %s (Path %s; File %s; Extension %s; GetFilePart %s; cch = %lu; buffer=null) result = %lu ::GetLastError() = %u; FilePart = %s %u\n",
|
|
RunId,
|
|
Path ? "present" : "null",
|
|
File ? "present" : "null",
|
|
Extension ? "present" : "null",
|
|
GetFilePart ? "true" : "false",
|
|
0,
|
|
Result,
|
|
::GetLastError(),
|
|
FilePart ? "present" : "null",
|
|
FilePart ? (FilePart - Buffer) : 0);
|
|
|
|
SetLastError(ERROR_GEN_FAILURE);
|
|
FilePart = NULL;
|
|
ULONG NewResult = ::SearchPathW(
|
|
Path,
|
|
File,
|
|
Extension,
|
|
Result,
|
|
Buffer,
|
|
lpFilePart);
|
|
|
|
printf("SearchPath() RunId = %s (Path %s; File %s; Extension %s; GetFilePart %s; cch = %lu) result = %lu ::GetLastError() = %u; FilePart = %s %u\n",
|
|
RunId,
|
|
Path ? "present" : "null",
|
|
File ? "present" : "null",
|
|
Extension ? "present" : "null",
|
|
GetFilePart ? "true" : "false",
|
|
Result,
|
|
NewResult,
|
|
::GetLastError(),
|
|
FilePart ? "present" : "null",
|
|
FilePart ? (FilePart - Buffer) : 0);
|
|
|
|
SetLastError(ERROR_GEN_FAILURE);
|
|
FilePart = NULL;
|
|
Result = ::SearchPathW(
|
|
Path,
|
|
File,
|
|
Extension,
|
|
cch,
|
|
Buffer,
|
|
lpFilePart);
|
|
|
|
printf("SearchPath() RunId = %s (Path %s; File %s; Extension %s; GetFilePart %s; cch = %lu) result = %lu ::GetLastError() = %u; FilePart = %s %u\n",
|
|
RunId,
|
|
Path ? "present" : "null",
|
|
File ? "present" : "null",
|
|
Extension ? "present" : "null",
|
|
GetFilePart ? "true" : "false",
|
|
cch,
|
|
Result,
|
|
::GetLastError(),
|
|
FilePart ? "present" : "null",
|
|
FilePart ? (FilePart - Buffer) : 0);
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
int
|
|
TestSearchPathHelper2(
|
|
PCSTR RunId,
|
|
PCWSTR Path,
|
|
PCWSTR File,
|
|
PCWSTR Extension,
|
|
ULONG cch
|
|
)
|
|
{
|
|
TestSearchPathHelper1(RunId, NULL, File, NULL, true, cch);
|
|
TestSearchPathHelper1(RunId, NULL, File, NULL, false, cch);
|
|
TestSearchPathHelper1(RunId, Path, File, NULL, true, cch);
|
|
TestSearchPathHelper1(RunId, Path, File, NULL, false, cch);
|
|
TestSearchPathHelper1(RunId, NULL, File, Extension, true, cch);
|
|
TestSearchPathHelper1(RunId, NULL, File, Extension, false, cch);
|
|
TestSearchPathHelper1(RunId, Path, File, Extension, true, cch);
|
|
TestSearchPathHelper1(RunId, Path, File, Extension, false, cch);
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
int
|
|
TestSearchPathHelper3(
|
|
PCSTR RunId,
|
|
PCWSTR Path,
|
|
PCWSTR File,
|
|
PCWSTR Extension
|
|
)
|
|
{
|
|
ULONG i;
|
|
|
|
for (i=0; i<5; i++)
|
|
TestSearchPathHelper2(RunId, Path, File, Extension, i);
|
|
|
|
for (i=MAX_PATH-5; i<(MAX_PATH+5); i++)
|
|
TestSearchPathHelper2(RunId, Path, File, Extension, i);
|
|
|
|
for (i=32760; i<32770; i++)
|
|
TestSearchPathHelper2(RunId, Path, File, Extension, i);
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
BOOL
|
|
TestSearchPath(
|
|
int argc,
|
|
wchar_t** argv,
|
|
int* piNext
|
|
)
|
|
{
|
|
ULONG i;
|
|
PWSTR PathToSearch = (PWSTR) malloc(100000* sizeof(WCHAR));
|
|
int iNext = (*piNext) + 1;
|
|
|
|
PathToSearch[0] = L'C';
|
|
PathToSearch[1] = L'\\';
|
|
for (i=2; i<60000; i++)
|
|
PathToSearch[i] = L'X';
|
|
wcscpy(&PathToSearch[i], L";C:\\");
|
|
|
|
TestSearchPathHelper3("1.0", L"C:\\DirectoryDoesNotExist;C:\\", L"boot.ini", L".ini");
|
|
TestSearchPathHelper3("1.1", L"C:\\DirectoryDoesNotExist;C:\\", L"boot.", L".ini");
|
|
TestSearchPathHelper3("1.2", L"C:\\DirectoryDoesNotExist;C:\\", L"boot", L".ini");
|
|
TestSearchPathHelper3("1.3", L"C:\\DirectoryDoesNotExist;C:\\", L"doesnotexist.doesnotexist", L".ini");
|
|
TestSearchPathHelper3("1.4", L"C:\\DirectoryDoesNotExist;C:\\", L"d:\\readme.txt", L".ini");
|
|
TestSearchPathHelper3("1.5", L"C:\\DirectoryDoesNotExist;C:\\", L"kernel32.dll", L".dll");
|
|
TestSearchPathHelper3("1.6", L"C:\\DirectoryDoesNotExist;C:\\", L"kernel32.", L".dll");
|
|
TestSearchPathHelper3("1.7", L"C:\\DirectoryDoesNotExist;C:\\", L"kernel32", L".dll");
|
|
TestSearchPathHelper3("1.8", L"C:\\DirectoryDoesNotExist;C:\\", L"kernel32.dll", L".ini");
|
|
TestSearchPathHelper3("1.9", L"C:\\DirectoryDoesNotExist;C:\\", L"kernel32.", L".ini");
|
|
TestSearchPathHelper3("1.10", L"C:\\DirectoryDoesNotExist;C:\\", L"kernel32", L".ini");
|
|
|
|
TestSearchPathHelper3("2.0", L"C:\\;C:\\DirectoryDoesNotExist", L"boot.ini", L".ini");
|
|
TestSearchPathHelper3("2.1", L"C:\\;C:\\DirectoryDoesNotExist", L"boot.", L".ini");
|
|
TestSearchPathHelper3("2.2", L"C:\\;C:\\DirectoryDoesNotExist", L"boot", L".ini");
|
|
TestSearchPathHelper3("2.3", L"C:\\;C:\\DirectoryDoesNotExist", L"doesnotexist.doesnotexist", L".ini");
|
|
TestSearchPathHelper3("2.4", L"C:\\;C:\\DirectoryDoesNotExist", L"d:\\readme.txt", L".ini");
|
|
TestSearchPathHelper3("2.5", L"C:\\;C:\\DirectoryDoesNotExist", L"kernel32.dll", L".dll");
|
|
TestSearchPathHelper3("2.6", L"C:\\;C:\\DirectoryDoesNotExist", L"kernel32.", L".dll");
|
|
TestSearchPathHelper3("2.7", L"C:\\;C:\\DirectoryDoesNotExist", L"kernel32", L".dll");
|
|
TestSearchPathHelper3("2.8", L"C:\\;C:\\DirectoryDoesNotExist", L"kernel32.dll", L".ini");
|
|
TestSearchPathHelper3("2.9", L"C:\\;C:\\DirectoryDoesNotExist", L"kernel32.", L".ini");
|
|
TestSearchPathHelper3("2.10", L"C:\\;C:\\DirectoryDoesNotExist", L"kernel32", L".ini");
|
|
|
|
TestSearchPathHelper3("3.0", PathToSearch, L"boot.ini", L".ini");
|
|
TestSearchPathHelper3("3.1", PathToSearch, L"boot", L".ini");
|
|
TestSearchPathHelper3("3.1", PathToSearch, L"boot.", L".ini");
|
|
TestSearchPathHelper3("3.2", PathToSearch, L"doesnotexist.doesnotexist", L".ini");
|
|
TestSearchPathHelper3("3.3", PathToSearch, L"d:\\readme.txt", L".ini");
|
|
|
|
*piNext = iNext;
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
BOOL
|
|
TestAct(
|
|
int argc,
|
|
wchar_t** argv,
|
|
int* piNext)
|
|
{
|
|
ULONG i, c;
|
|
ULONG_PTR *prgCookies = NULL;
|
|
HANDLE hActCtx = NULL;
|
|
CHAR buffer[1024];
|
|
int iNext = (*piNext + 1);
|
|
BOOL fSuccess = FALSE;
|
|
|
|
if (iNext >= argc)
|
|
{
|
|
fprintf(stderr, "%S: missing parameter after \"%S\"\n", argv[0], argv[iNext - 1]);
|
|
goto Exit;
|
|
}
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, argv[iNext++], -1, buffer, NUMBER_OF(buffer), NULL, NULL);
|
|
|
|
ACTCTXA ac;
|
|
|
|
ac.cbSize = sizeof(ac);
|
|
ac.dwFlags = 0;
|
|
ac.lpSource = buffer;
|
|
ac.wProcessorArchitecture = g.wProcessorArchitecture;
|
|
ac.wLangId = g.wLangId;
|
|
|
|
hActCtx = ::CreateActCtxA(&ac);
|
|
if (hActCtx == INVALID_HANDLE_VALUE)
|
|
{
|
|
fprintf(stderr, "CreateActCtxA() failed; ::GetLastError() = %d\n", ::GetLastError());
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
c = 0;
|
|
|
|
if (argc > iNext)
|
|
c = _wtoi(argv[iNext++]);
|
|
|
|
if (c == 0)
|
|
c = 100;
|
|
|
|
prgCookies = NEW(ULONG_PTR[c]);
|
|
if (prgCookies == NULL)
|
|
{
|
|
fprintf(stderr, "Unable to allocate %lu cookies.\n", c);
|
|
goto Exit;
|
|
}
|
|
|
|
for (i=0; i<c; i++)
|
|
{
|
|
if (!ActivateActCtx(hActCtx, &prgCookies[i]))
|
|
{
|
|
fprintf(stderr, "Attempt to activate to depth %lu failed; ::GetLastError() = %d\n", i, ::GetLastError());
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
for (i=0; i<c; i++)
|
|
{
|
|
ULONG j = (c - i) - 1;
|
|
DeactivateActCtx(0, prgCookies[j]);
|
|
}
|
|
|
|
ReleaseActCtx(hActCtx);
|
|
|
|
fSuccess = TRUE;
|
|
*piNext = iNext;
|
|
|
|
Exit:
|
|
delete []prgCookies;
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
HRESULT Helper_WriteStream(CBaseStringBuffer * pFileNameBuf,
|
|
IStream *pStream)
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
LPBYTE pBuf[0x4000];
|
|
DWORD cbBuf = 0x4000;
|
|
DWORD dwWritten = 0;
|
|
DWORD cbRead = 0;
|
|
HANDLE hf = INVALID_HANDLE_VALUE;
|
|
|
|
hf = ::CreateFileW(static_cast<PCWSTR>(*pFileNameBuf), GENERIC_READ, FILE_SHARE_READ,
|
|
NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
|
if (hf == INVALID_HANDLE_VALUE){
|
|
hr = HRESULT_FROM_WIN32 (GetLastError());
|
|
goto Exit;
|
|
}
|
|
|
|
while (::ReadFile(hf, pBuf, cbBuf, &cbRead, NULL) && cbRead){
|
|
hr = pStream->Write(pBuf, cbRead, &dwWritten);
|
|
if (FAILED(hr))
|
|
goto Exit;
|
|
}
|
|
|
|
if (! SUCCEEDED(hr =pStream->Commit(0)))
|
|
goto Exit;
|
|
|
|
CloseHandle(hf);
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
BOOL
|
|
TestMSIInstall(
|
|
int argc,
|
|
wchar_t** argv,
|
|
int* piNext
|
|
)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
CSmartRef<IAssemblyCache> pCache;
|
|
CSmartRef<IAssemblyCacheItem> ppCacheItem[4];
|
|
CSmartRef<IStream> pStream;
|
|
PFNCreateAssemblyCache pCreateAssemblyCache = NULL;
|
|
CStringBuffer SourceFilePathBuf;
|
|
CStringBuffer SourceFileNameBuf;
|
|
|
|
CHAR buf[1024];
|
|
FILE* fp = NULL;
|
|
LPSTR p1, pbuf ;
|
|
int i, cAsm;
|
|
|
|
int iArg = (*piNext) + 1;
|
|
if (iArg >= argc)
|
|
{
|
|
fprintf(stderr, "%S: missing parameter after \"%S\"\n", argv[0], argv[iArg-1]);
|
|
goto Exit;
|
|
}
|
|
|
|
LoadSxs();
|
|
GetSxsProc("CreateAssemblyCache", &pCreateAssemblyCache);
|
|
IFCOMFAILED_EXIT(pCreateAssemblyCache(&pCache, 0));
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, argv[iArg], -1, buf, NUMBER_OF(buf), NULL, NULL);
|
|
fp = fopen(buf, "r");
|
|
if (!fp) {
|
|
fprintf(stderr, "%S: Error opening script file \"%S\"\n", argv[0], argv[iArg]);
|
|
goto Exit;
|
|
}
|
|
cAsm = 0;
|
|
while (! feof(fp)) {
|
|
if (! fgets(buf, 80, fp)) { // end of file or error
|
|
if (ferror(fp)){ // error occur
|
|
fprintf(stderr, "%S: Error occur while reading the script file\n", argv[0]);
|
|
goto Exit;
|
|
}
|
|
else{ // end of file
|
|
fprintf(stderr, "%S: end of script file\n", argv[0]);
|
|
break;
|
|
}
|
|
}
|
|
// trim the string
|
|
i = 0 ;
|
|
while (buf[i] == ' ') i++; // skip the whitespace at the beginning of the line
|
|
pbuf = buf + i ; // pointer to the first un-whitespace char in the line
|
|
i = 0 ;
|
|
while (pbuf[i] != '\n') i++;
|
|
pbuf[i] = '\0';
|
|
|
|
p1 = NULL;
|
|
p1 = strchr(pbuf, ' ');
|
|
if (p1 == NULL) { // instruction line
|
|
if (strcmp(pbuf, "BeginAsmCacheItem") == 0) {
|
|
IFCOMFAILED_EXIT(pCache->CreateAssemblyCacheItem(0, NULL, &ppCacheItem[cAsm], NULL));
|
|
}else
|
|
if (strcmp(pbuf, "EndAsmCacheItem") == 0) {
|
|
IFCOMFAILED_EXIT(ppCacheItem[cAsm]->Commit(0, NULL));
|
|
cAsm ++;
|
|
}
|
|
}
|
|
else
|
|
{ // get the first word of the line
|
|
*p1 = '\0';
|
|
p1++; // p1 points to the filename now
|
|
IFW32FALSE_EXIT(SourceFileNameBuf.Win32Assign(p1, ::strlen(p1)));
|
|
if (strcmp(pbuf,"SourceFilePath") == 0) { // fullpath of source files, which would be in a CD
|
|
IFW32FALSE_EXIT(SourceFilePathBuf.Win32Assign(p1, ::strlen(p1)));
|
|
SourceFilePathBuf.Win32EnsureTrailingPathSeparator();
|
|
}else
|
|
if (strcmp(pbuf, "FILE") == 0) {
|
|
IFCOMFAILED_EXIT(ppCacheItem[cAsm]->CreateStream(0, SourceFileNameBuf, STREAM_FORMAT_WIN32_MODULE, 0, &pStream, NULL));
|
|
IFW32FALSE_EXIT(SourceFileNameBuf.Win32Assign(SourceFilePathBuf, ::wcslen(SourceFilePathBuf)));
|
|
IFW32FALSE_EXIT(SourceFileNameBuf.Win32Append(p1, ::strlen(p1))); // containing full-path of the source file
|
|
IFCOMFAILED_EXIT(Helper_WriteStream(&SourceFileNameBuf, pStream));
|
|
pStream.Release(); // stream should be released since writtingfile has been done
|
|
|
|
}else
|
|
if (strcmp(pbuf, "MANIFEST") == 0) {
|
|
IFCOMFAILED_EXIT(ppCacheItem[cAsm]->CreateStream(0, SourceFileNameBuf, STREAM_FORMAT_WIN32_MANIFEST, 0, &pStream, NULL));
|
|
IFW32FALSE_EXIT(SourceFileNameBuf.Win32Assign(SourceFilePathBuf, SourceFilePathBuf.Cch())); // containing full-path of the source file
|
|
IFW32FALSE_EXIT(SourceFileNameBuf.Win32Append(p1, ::strlen(p1)));
|
|
IFCOMFAILED_EXIT(Helper_WriteStream(&SourceFileNameBuf, pStream));
|
|
pStream.Release(); // stream should be released since writtingfile has been done
|
|
}
|
|
} // end of else
|
|
}// end of while
|
|
|
|
fSuccess = TRUE;
|
|
*piNext = iArg;
|
|
Exit:
|
|
fp ? fclose(fp) : 0;
|
|
return fSuccess;
|
|
}
|
|
|
|
CDirWalk::ECallbackResult
|
|
DirWalkCallback(
|
|
CDirWalk::ECallbackReason reason,
|
|
CDirWalk* dirWalk,
|
|
DWORD dwFlags
|
|
)
|
|
{
|
|
PCWSTR parent = dirWalk->m_strParent;
|
|
PCWSTR leaf = dirWalk->m_fileData.cFileName;
|
|
if (reason == CDirWalk::eFile)
|
|
printf("file %lu, %ls, %ls\n", reason, parent, leaf);
|
|
else
|
|
printf("directory %lu, %ls\n", reason, parent);
|
|
return CDirWalk::eKeepWalking;
|
|
}
|
|
|
|
int
|
|
TestDirWalk(
|
|
PCWSTR root,
|
|
PWSTR filter
|
|
)
|
|
{
|
|
CDirWalk dirWalk;
|
|
StdVector<std::wstring> vstrFilter;
|
|
StdVector<PCWSTR> vstrFilter2;
|
|
PWSTR filterTok;
|
|
|
|
if (filterTok = wcstok(filter, L";"))
|
|
{
|
|
do
|
|
{
|
|
vstrFilter.push_back(filterTok);
|
|
vstrFilter2.push_back(vstrFilter.back().c_str());
|
|
} while (filterTok = wcstok(NULL, L";"));
|
|
}
|
|
dirWalk.m_fileFiltersBegin = &*vstrFilter2.begin();
|
|
dirWalk.m_fileFiltersEnd = &*vstrFilter2.end();
|
|
dirWalk.m_strParent.Win32Assign(root, ::wcslen(root));
|
|
dirWalk.m_callback = DirWalkCallback;
|
|
dirWalk.Walk();
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
TestMultiAct(
|
|
int argc,
|
|
wchar_t **argv
|
|
)
|
|
{
|
|
HANDLE h1, h2;
|
|
ACTCTXW acw;
|
|
|
|
memset(&acw, 0, sizeof(acw));
|
|
|
|
acw.cbSize = sizeof(acw);
|
|
acw.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID;
|
|
acw.lpSource = argv[2];
|
|
acw.lpResourceName = MAKEINTRESOURCEW(1);
|
|
|
|
h1 = ::CreateActCtxW(&acw);
|
|
if (h1 == INVALID_HANDLE_VALUE)
|
|
{
|
|
fprintf(stderr, "1st CreateActCtxW() failed; ::GetLastError() = %d\n", ::GetLastError());
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
h2 = ::CreateActCtxW(&acw);
|
|
if (h2 == INVALID_HANDLE_VALUE)
|
|
{
|
|
fprintf(stderr, "2nd CreateActCtxW() failed; ::GetLastError() = %d\n", ::GetLastError());
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
BOOL
|
|
ParseProcessorArchitecture(
|
|
int argc,
|
|
wchar_t** argv,
|
|
int* piCurrent
|
|
)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
int i = *piCurrent;
|
|
|
|
i++;
|
|
|
|
if (i >= argc)
|
|
{
|
|
fprintf(stderr, "%S: missing parameter after %S\n", argv[0], argv[i - 1]);
|
|
goto Exit;
|
|
}
|
|
|
|
if (::FusionpStrCmpI(argv[i], L"x86") == 0)
|
|
g.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL;
|
|
else if (::FusionpStrCmpI(argv[i], L"i386") == 0)
|
|
g.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL;
|
|
else if (::FusionpStrCmpI(argv[i], L"ia64") == 0)
|
|
g.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_IA64;
|
|
else if (::FusionpStrCmpI(argv[i], L"alpha64") == 0)
|
|
g.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_ALPHA64;
|
|
else
|
|
{
|
|
fprintf(stderr, "%S: invalid -pa value \"%S\"\n", argv[0], argv[i]);
|
|
goto Exit;
|
|
}
|
|
|
|
*piCurrent = i + 1;
|
|
|
|
fSuccess = TRUE;
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
BOOL
|
|
ParseLangId(
|
|
int argc,
|
|
wchar_t** argv,
|
|
int* piCurrent
|
|
)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
int i = *piCurrent;
|
|
|
|
i++;
|
|
|
|
if (i >= argc)
|
|
{
|
|
fprintf(stderr, "%S: missing parameter after %S\n", argv[0], argv[i - 1]);
|
|
goto Exit;
|
|
}
|
|
|
|
swscanf(argv[i], L"%hx", &g.wLangId);
|
|
|
|
*piCurrent = i + 1;
|
|
|
|
fSuccess = TRUE;
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
BOOL
|
|
TestLoadLibrary(
|
|
int argc,
|
|
wchar_t** argv,
|
|
int* piNext
|
|
)
|
|
{
|
|
int i = (*piNext) + 1;
|
|
HINSTANCE hInstance = NULL;
|
|
BOOL fExpectedToFail = FALSE;
|
|
BOOL fSuccess = FALSE;
|
|
|
|
while (i < argc)
|
|
{
|
|
if (::FusionpStrCmpI(argv[i], L"-fail-") == 0)
|
|
fExpectedToFail = TRUE;
|
|
else if (::FusionpStrCmpI(argv[i], L"-succeed-") == 0)
|
|
fExpectedToFail = FALSE;
|
|
else
|
|
{
|
|
hInstance = LoadLibraryW(argv[i]);
|
|
if (hInstance == NULL)
|
|
{
|
|
if (!fExpectedToFail)
|
|
{
|
|
fprintf(stderr, "%S: Failed to LoadLibraryW(\"%S\"); ::GetLastError() = %d\n", argv[0], argv[i], ::GetLastError());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (fExpectedToFail)
|
|
{
|
|
WCHAR LibraryPath[4096];
|
|
|
|
Kernel32.GetModuleFileNameW(hInstance, LibraryPath, NUMBER_OF(LibraryPath));
|
|
|
|
fprintf(stderr, "%S: LoadLibraryW(\"%S\") was supposed to fail, but instead we got \"%S\"\n", argv[0], argv[i], LibraryPath);
|
|
}
|
|
|
|
::FreeLibrary(hInstance);
|
|
hInstance = NULL;
|
|
}
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
fSuccess = TRUE;
|
|
// Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
int TestAssemblyName()
|
|
{
|
|
SXSP_DEBUG_FUNCTION pfn = NULL;
|
|
BOOL fSuccess = FALSE;
|
|
|
|
LoadSxs();
|
|
|
|
GetSxsProc(SXSP_DEBUG_ORDINAL, &pfn);
|
|
|
|
fSuccess = (*pfn)(SXS_DEBUG_ASSEMBLYNAME_CONVERSION, 0, NULL, NULL);
|
|
|
|
if (! fSuccess){
|
|
fprintf(stderr, "%s failed!\n", __FUNCTION__);
|
|
return EXIT_FAILURE;
|
|
}
|
|
else
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|
|
|
|
int TestPrecomiledManifest(PCWSTR manifestFileName)
|
|
{
|
|
SXSP_DEBUG_FUNCTION pfn = NULL;
|
|
BOOL fSuccess = FALSE;
|
|
|
|
LoadSxs();
|
|
|
|
GetSxsProc(SXSP_DEBUG_ORDINAL, &pfn);
|
|
|
|
fSuccess = (*pfn)(SXS_DEBUG_PRECOMPILED_MANIFEST, 0, manifestFileName, NULL);
|
|
|
|
if (! fSuccess){
|
|
fprintf(stderr, "%s failed!\n", __FUNCTION__);
|
|
return EXIT_FAILURE;
|
|
}
|
|
else
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
int TestPCMTime(PCWSTR manifestFilename)
|
|
{
|
|
SXSP_DEBUG_FUNCTION pfn = NULL;
|
|
BOOL fSuccess = FALSE;
|
|
|
|
LoadSxs();
|
|
|
|
GetSxsProc(SXSP_DEBUG_ORDINAL, &pfn);
|
|
|
|
fSuccess = (*pfn)(SXS_DEBUG_TIME_PCM, 0, manifestFilename, NULL);
|
|
|
|
if (! fSuccess)
|
|
{
|
|
fprintf(stderr, "%s failed!\n", __FUNCTION__);
|
|
return EXIT_FAILURE;
|
|
}
|
|
else
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
int TestCreateMultiLevelDirectory(PCWSTR dirs)
|
|
{
|
|
SXSP_DEBUG_FUNCTION pfn = NULL;
|
|
BOOL fSuccess = FALSE;
|
|
|
|
LoadSxs();
|
|
|
|
GetSxsProc(SXSP_DEBUG_ORDINAL, &pfn);
|
|
|
|
fSuccess = (*pfn)(SXS_DEBUG_CREAT_MULTILEVEL_DIRECTORY, 0, dirs, NULL);
|
|
|
|
if (! fSuccess)
|
|
{
|
|
fprintf(stderr, "%s failed!\n", __FUNCTION__);
|
|
return EXIT_FAILURE;
|
|
}
|
|
else
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
|
|
BOOL
|
|
TestLeakMemory(
|
|
DWORD dwAmount
|
|
)
|
|
{
|
|
SXSP_DEBUG_FUNCTION pfn = NULL;
|
|
BOOL fSuccess = FALSE;
|
|
|
|
if (dwAmount < 1) {
|
|
fprintf(stderr, "%s got a bad parameter, %d; rectifying to 1.\n", __FUNCTION__, dwAmount);
|
|
dwAmount = 1;
|
|
}
|
|
|
|
LoadSxs();
|
|
|
|
GetSxsProc(SXSP_DEBUG_ORDINAL, &pfn);
|
|
|
|
fSuccess = (*pfn)(SXS_DEBUG_FORCE_LEAK, 0, NULL, (PDWORD)&dwAmount);
|
|
|
|
if (! fSuccess)
|
|
{
|
|
fprintf(stderr, "%s failed to leak %d bytes of memory!\n", __FUNCTION__, dwAmount);
|
|
return EXIT_FAILURE;
|
|
}
|
|
else
|
|
{
|
|
fprintf(stdout, "%s leaked %d bytes of memory.\n", __FUNCTION__, dwAmount);
|
|
return EXIT_SUCCESS;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
TestManifestProbing(
|
|
int argc,
|
|
wchar_t **argv,
|
|
int *piNext
|
|
)
|
|
{
|
|
SXSP_DEBUG_FUNCTION pfn = NULL;
|
|
BOOL fSuccess = FALSE;
|
|
LoadSxs();
|
|
|
|
GetSxsProc(SXSP_DEBUG_ORDINAL, &pfn);
|
|
|
|
fSuccess = (*pfn)(SXS_DEBUG_PROBE_MANIFST, 0, NULL, NULL);
|
|
|
|
if (! fSuccess){
|
|
fprintf(stderr, "%s failed!\n", __FUNCTION__);
|
|
return EXIT_FAILURE;
|
|
}
|
|
else
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|
|
|
|
BOOL
|
|
TestAssemblyProbing(
|
|
int argc,
|
|
wchar_t **argv,
|
|
int *piNext
|
|
)
|
|
{
|
|
PSXS_PROBE_ASSEMBLY_INSTALLATION pfn;
|
|
BOOL fSuccess = FALSE;
|
|
DWORD dwDisposition = 0;
|
|
|
|
LoadSxs();
|
|
GetSxsProc(SXS_PROBE_ASSEMBLY_INSTALLATION, &pfn);
|
|
|
|
fSuccess = (*pfn)(0, argv[*piNext], &dwDisposition);
|
|
|
|
return (fSuccess ? EXIT_SUCCESS : EXIT_FAILURE);
|
|
}
|
|
|
|
int TestCreateProcess2(wchar_t** argv)
|
|
{
|
|
STARTUPINFOW StartupInfo = { sizeof(StartupInfo) };
|
|
PROCESS_INFORMATION ProcessInformation = {0};
|
|
|
|
*argv += wcsspn(*argv, L" \t\r\n");
|
|
|
|
BOOL f = ::CreateProcessW(
|
|
*argv,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&StartupInfo,
|
|
&ProcessInformation);
|
|
printf("CreateProcess(%S) returned %s\n", *argv, f ? "True" : "False");
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
|
|
int TestCreateProcess(wchar_t** argv)
|
|
{
|
|
CUnicodeStringBuffer CommandLine;
|
|
STARTUPINFOW StartupInfo = { sizeof(StartupInfo) };
|
|
PROCESS_INFORMATION ProcessInformation = {0};
|
|
|
|
while (*argv)
|
|
{
|
|
CommandLine.Win32Append(L" ", 1);
|
|
CommandLine.Win32Append(*argv, ::wcslen(*argv));
|
|
argv++;
|
|
}
|
|
|
|
CUnicodeStringBufferAccessor MutableCommandLine(&CommandLine);
|
|
BOOL f = ::CreateProcessW(
|
|
NULL,
|
|
MutableCommandLine,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&StartupInfo,
|
|
&ProcessInformation);
|
|
printf("CreateProcess(%S) returned %s\n", static_cast<PCWSTR>(MutableCommandLine), f ? "True" : "False");
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// XMLDOM Helper function:
|
|
////////////////////////////////////////////////////////////////////////////
|
|
HRESULT XMLDOMHelper_WalkTree(IXMLDOMNode* node, int level)
|
|
{
|
|
IXMLDOMNode* pChild, *pNext;
|
|
BSTR nodeName;
|
|
IXMLDOMNamedNodeMap* pattrs;
|
|
|
|
node->get_nodeName(&nodeName);
|
|
for (int i = 0; i < level; i++)
|
|
printf(" ");
|
|
printf("%S",nodeName);
|
|
SysFreeString(nodeName);
|
|
|
|
|
|
if (SUCCEEDED(node->get_attributes(&pattrs)) && pattrs != NULL)
|
|
{
|
|
pattrs->nextNode(&pChild);
|
|
while (pChild)
|
|
{
|
|
BSTR name;
|
|
pChild->get_nodeName(&name);
|
|
printf(" %S='", name);
|
|
::SysFreeString(name);
|
|
|
|
VARIANT value;
|
|
pChild->get_nodeValue(&value);
|
|
if (value.vt == VT_BSTR)
|
|
{
|
|
printf("%S", V_BSTR(&value));
|
|
}
|
|
printf("'");
|
|
VariantClear(&value);
|
|
pChild->Release();
|
|
pattrs->nextNode(&pChild);
|
|
}
|
|
pattrs->Release();
|
|
}
|
|
printf("\n");
|
|
|
|
node->get_firstChild(&pChild);
|
|
while (pChild)
|
|
{
|
|
XMLDOMHelper_WalkTree(pChild, level+1);
|
|
pChild->get_nextSibling(&pNext);
|
|
pChild->Release();
|
|
pChild = pNext;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// XMLDOM Helper function:
|
|
////////////////////////////////////////////////////////////////////////////
|
|
HRESULT XMLDOMHelper_ReportError(IXMLDOMParseError *pXMLError)
|
|
{
|
|
long line, linePos;
|
|
LONG errorCode;
|
|
BSTR pBURL = NULL, pBReason = NULL;
|
|
HRESULT hr;
|
|
|
|
hr = pXMLError->get_line(&line);
|
|
if (FAILED(hr))
|
|
goto Exit;
|
|
|
|
hr = pXMLError->get_linepos(&linePos);
|
|
if (FAILED(hr))
|
|
goto Exit;
|
|
|
|
hr = pXMLError->get_errorCode(&errorCode);
|
|
if (FAILED(hr))
|
|
goto Exit;
|
|
|
|
hr = pXMLError->get_url(&pBURL);
|
|
if (FAILED(hr))
|
|
goto Exit;
|
|
|
|
hr = pXMLError->get_reason(&pBReason);
|
|
if (FAILED(hr))
|
|
goto Exit;
|
|
|
|
|
|
fprintf(stderr, "%S", pBReason);
|
|
if (line > 0)
|
|
{
|
|
fprintf(stderr, "Error on line %d, position %d in \"%S\".\n",
|
|
line, linePos, pBURL);
|
|
}
|
|
hr= E_FAIL;
|
|
|
|
Exit:
|
|
SysFreeString(pBURL);
|
|
SysFreeString(pBReason);
|
|
|
|
return hr;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// XMLDOM Helper function: Check load results
|
|
////////////////////////////////////////////////////////////////////////////
|
|
HRESULT XMLDOMHelper_CheckLoad(IXMLDOMDocument* pDoc)
|
|
{
|
|
// And since we don't have the VARIANT_BOOL from load we
|
|
// need to check the parse Error errorCode property to see
|
|
// if everything went ok.
|
|
IXMLDOMParseError *pXMLError = NULL;
|
|
LONG errorCode;
|
|
HRESULT hr = NOERROR;
|
|
|
|
hr = pDoc->get_parseError(&pXMLError);
|
|
if (FAILED(hr))
|
|
goto Exit;
|
|
|
|
hr = pXMLError->get_errorCode(&errorCode);
|
|
if (FAILED(hr))
|
|
goto Exit;
|
|
|
|
if (errorCode != 0){
|
|
hr = XMLDOMHelper_ReportError(pXMLError);
|
|
goto Exit;
|
|
}
|
|
|
|
hr = NOERROR;
|
|
Exit:
|
|
if (pXMLError)
|
|
pXMLError->Release();
|
|
|
|
return hr;
|
|
}
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// XMLDOM Helper function:
|
|
////////////////////////////////////////////////////////////////////////////
|
|
HRESULT XMLDOMHelper_LoadDocumentSync(IXMLDOMDocument *pDoc, BSTR pBURL)
|
|
{
|
|
IXMLDOMParseError *pXMLError = NULL;
|
|
VARIANT vURL;
|
|
VARIANT_BOOL vb;
|
|
HRESULT hr;
|
|
|
|
hr = pDoc->put_async(VARIANT_FALSE);
|
|
if (FAILED(hr))
|
|
goto Exit;
|
|
|
|
// Load xml document from the given URL or file path
|
|
VariantInit(&vURL);
|
|
vURL.vt = VT_BSTR;
|
|
V_BSTR(&vURL) = pBURL;
|
|
hr = pDoc->load(vURL, &vb);
|
|
if (FAILED(hr))
|
|
goto Exit;
|
|
|
|
hr = XMLDOMHelper_CheckLoad(pDoc);
|
|
if (FAILED(hr))
|
|
goto Exit;
|
|
|
|
hr = NOERROR;
|
|
|
|
Exit:
|
|
if (pXMLError)
|
|
pXMLError->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
BOOL TestXMLDOM(PCWSTR pswzXMLFileName)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IXMLDOMDocument *pDoc = NULL;
|
|
IXMLDOMNode* pNode = NULL;
|
|
BSTR pBURL = NULL;
|
|
|
|
Ole32.CoInitialize(NULL);
|
|
|
|
// Create an empty XML document
|
|
hr = Ole32.CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IXMLDOMDocument, (void**)&pDoc);
|
|
if (FAILED(hr))
|
|
goto Exit;
|
|
|
|
pBURL = SysAllocString(pswzXMLFileName);
|
|
hr = XMLDOMHelper_LoadDocumentSync(pDoc, pBURL);
|
|
if (FAILED(hr))
|
|
goto Exit;
|
|
|
|
// Now walk the loaded XML document dumping the node names to stdout.
|
|
hr = pDoc->QueryInterface(IID_IXMLDOMNode,(void**)&pNode);
|
|
if (FAILED(hr))
|
|
goto Exit;
|
|
|
|
hr = XMLDOMHelper_WalkTree(pNode,0);
|
|
if (FAILED(hr))
|
|
goto Exit;
|
|
|
|
hr = NOERROR;
|
|
|
|
Exit:
|
|
if (pDoc) pDoc->Release();
|
|
SysFreeString(pBURL);
|
|
if (pNode) pNode->Release();
|
|
|
|
Ole32.CoUninitialize();
|
|
|
|
return hr == 0 ? 0 : 1;
|
|
|
|
}
|
|
|
|
BOOL TestFusionArray(PCWSTR dir1, PCWSTR dir2)
|
|
{
|
|
SXSP_DEBUG_FUNCTION pfn = NULL;
|
|
BOOL fSuccess = FALSE;
|
|
LoadSxs();
|
|
|
|
GetSxsProc(SXSP_DEBUG_ORDINAL, &pfn);
|
|
|
|
fSuccess = (*pfn)(SXS_DEBUG_FUSION_ARRAY, 0, dir1, (PVOID)dir2);
|
|
|
|
if (! fSuccess){
|
|
fprintf(stderr, "%s failed!\n", __FUNCTION__);
|
|
return EXIT_FAILURE;
|
|
}
|
|
else
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
BOOL TestGeneratePathFromIdentityAttributeString(PCWSTR str)
|
|
{
|
|
PSXSPGENERATEMANIFESTPATHONASSEMBLYIDENTITY pfn = NULL;
|
|
|
|
BOOL fSuccess = FALSE;
|
|
WCHAR folderName[5000];
|
|
SIZE_T cch = NUMBER_OF(folderName);
|
|
|
|
LoadSxs();
|
|
|
|
GetSxsProc("SxspGenerateManifestPathOnAssemblyIdentity", &pfn);
|
|
|
|
fSuccess = (*pfn)((PWSTR) str, folderName, &cch, NULL);
|
|
|
|
if (! fSuccess)
|
|
{
|
|
fprintf(stderr, "%s failed!\n", __FUNCTION__);
|
|
return EXIT_FAILURE;
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"Folder name returned is %s\n", folderName);
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
}
|
|
|
|
BOOL
|
|
TestDirectoryChangeWatcher(
|
|
int argc,
|
|
wchar_t **argv,
|
|
int *piNext
|
|
)
|
|
{
|
|
SXSP_DEBUG_FUNCTION pfn;
|
|
BOOL fSuccess;
|
|
|
|
LoadSxs();
|
|
GetSxsProc(SXSP_DEBUG_ORDINAL, &pfn);
|
|
fSuccess = (*pfn)(SXS_DEBUG_DIRECTORY_WATCHER, 0, NULL, NULL);
|
|
return (fSuccess ? EXIT_SUCCESS : EXIT_FAILURE);
|
|
}
|
|
|
|
|
|
BOOL
|
|
TestRefreshAssembly(
|
|
PCWSTR wsAssemblyManifest
|
|
)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
PSXS_INSTALL_ASSEMBLY_W sxsInstallAssemblyW = NULL;
|
|
|
|
LoadSxs();
|
|
GetSxsProc("SxsInstallAssemblyW", &sxsInstallAssemblyW);
|
|
|
|
if (!sxsInstallAssemblyW(
|
|
NULL,
|
|
SXS_INSTALL_ASSEMBLY_FLAG_REPLACE_EXISTING,
|
|
wsAssemblyManifest,
|
|
NULL))
|
|
{
|
|
fwprintf(
|
|
stderr,
|
|
L"Failed reinstalling assembly '%ls', 0x%08X\n",
|
|
wsAssemblyManifest,
|
|
::GetLastError());
|
|
}
|
|
else
|
|
{
|
|
fSuccess = TRUE;
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
BOOL
|
|
TestInstallWithInstallInfo(
|
|
PCWSTR wsAssemblyManifest,
|
|
PCWSTR wsReferenceString
|
|
)
|
|
{
|
|
#define SXS_TEST
|
|
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
PSXS_INSTALL_W_ROUTINE sxsInstallW = NULL;
|
|
SXS_INSTALLW InstallParameters = {sizeof(InstallParameters)};
|
|
SXS_INSTALL_REFERENCEW InstallReference = {sizeof(InstallReference)};
|
|
|
|
LoadSxs();
|
|
GetSxsProc("SxsInstallW", &sxsInstallW);
|
|
|
|
InstallParameters.dwFlags =
|
|
//SXS_INSTALL_FLAG_MOVE |
|
|
SXS_INSTALL_FLAG_REPLACE_EXISTING |
|
|
SXS_INSTALL_FLAG_CODEBASE_URL_VALID |
|
|
SXS_INSTALL_FLAG_REFERENCE_VALID |
|
|
SXS_INSTALL_FLAG_REFRESH_PROMPT_VALID;
|
|
InstallParameters.lpCodebaseURL = wsAssemblyManifest;
|
|
InstallParameters.lpManifestPath = wsAssemblyManifest;
|
|
InstallParameters.lpReference = &InstallReference;
|
|
InstallParameters.lpRefreshPrompt = L"boop";
|
|
|
|
InstallReference.guidScheme = SXS_INSTALL_REFERENCE_SCHEME_OPAQUESTRING;
|
|
InstallReference.lpIdentifier = wsReferenceString ? wsReferenceString : L"TempRef";
|
|
|
|
if (!(*sxsInstallW)(&InstallParameters))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
fSuccess = TRUE;
|
|
Exit:
|
|
if (!fSuccess)
|
|
{
|
|
fprintf(stderr, "%s failed!\n", __FUNCTION__);
|
|
return EXIT_FAILURE;
|
|
}
|
|
else
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
BOOL
|
|
TestInstallLikeWindowsSetup(
|
|
PCWSTR wsAssemblyManifest,
|
|
PCWSTR wsCodebase
|
|
)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
PSXS_BEGIN_ASSEMBLY_INSTALL sxsBeginAssemblyInstall = NULL;
|
|
PSXS_INSTALL_W_ROUTINE sxsInstallW = NULL;
|
|
PSXS_END_ASSEMBLY_INSTALL sxsEndAssemblyInstall = NULL;
|
|
SXS_INSTALLW InstallParameters = {sizeof(InstallParameters)};
|
|
SXS_INSTALL_REFERENCEW InstallReference = {sizeof(InstallReference)};
|
|
|
|
LoadSxs();
|
|
GetSxsProc("SxsBeginAssemblyInstall", &sxsBeginAssemblyInstall);
|
|
GetSxsProc("SxsInstallW", &sxsInstallW);
|
|
GetSxsProc("SxsEndAssemblyInstall", &sxsEndAssemblyInstall);
|
|
|
|
IFW32FALSE_EXIT(
|
|
(*sxsBeginAssemblyInstall)(
|
|
SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_NOT_TRANSACTIONAL
|
|
| SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_NO_VERIFY
|
|
| SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_REPLACE_EXISTING,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&InstallParameters.pvInstallCookie));
|
|
|
|
InstallReference.guidScheme = SXS_INSTALL_REFERENCE_SCHEME_OSINSTALL;
|
|
InstallReference.lpNonCanonicalData = L"Foom";
|
|
|
|
InstallParameters.dwFlags |= SXS_INSTALL_FLAG_CODEBASE_URL_VALID
|
|
| SXS_INSTALL_FLAG_FROM_DIRECTORY
|
|
| SXS_INSTALL_FLAG_FROM_DIRECTORY_RECURSIVE
|
|
| SXS_INSTALL_FLAG_REFRESH_PROMPT_VALID
|
|
| SXS_INSTALL_FLAG_INSTALL_COOKIE_VALID
|
|
| SXS_INSTALL_FLAG_REFERENCE_VALID
|
|
;
|
|
InstallParameters.lpCodebaseURL = wsCodebase;
|
|
InstallParameters.lpRefreshPrompt = L"like..Windows CD..";
|
|
InstallParameters.lpManifestPath = wsAssemblyManifest;
|
|
InstallParameters.lpReference = &InstallReference;
|
|
|
|
IFW32FALSE_EXIT((*sxsInstallW)(&InstallParameters));
|
|
|
|
IFW32FALSE_EXIT(
|
|
(*sxsEndAssemblyInstall)(
|
|
InstallParameters.pvInstallCookie,
|
|
SXS_END_ASSEMBLY_INSTALL_FLAG_COMMIT,
|
|
NULL));
|
|
InstallParameters.pvInstallCookie = NULL;
|
|
|
|
fSuccess = TRUE;
|
|
Exit:
|
|
|
|
if (InstallParameters.pvInstallCookie != NULL)
|
|
{
|
|
CSxsPreserveLastError ple;
|
|
(void) (*sxsEndAssemblyInstall)(InstallParameters.pvInstallCookie, SXS_END_ASSEMBLY_INSTALL_FLAG_ABORT, NULL);
|
|
ple.Restore();
|
|
}
|
|
|
|
if (!fSuccess)
|
|
{
|
|
fprintf(stderr, "%s failed!\n", __FUNCTION__);
|
|
return EXIT_FAILURE;
|
|
}
|
|
else
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
//#define ASM_CPUID { __asm __emit 0fh __asm __emit 0a2h }
|
|
#define ASM_CPUID { __asm cpuid }
|
|
#define ASM_RDTSC { __asm rdtsc }
|
|
|
|
inline VOID GetCpuIdLag(LARGE_INTEGER *ref)
|
|
{
|
|
#if !defined(_WIN64)
|
|
LARGE_INTEGER temp, temp2;
|
|
_asm
|
|
{
|
|
cpuid
|
|
cpuid
|
|
cpuid
|
|
cpuid
|
|
cpuid
|
|
rdtsc
|
|
mov temp.LowPart, eax
|
|
mov temp.HighPart, edx
|
|
cpuid
|
|
rdtsc
|
|
mov temp2.LowPart, eax
|
|
mov temp2.HighPart, edx
|
|
}
|
|
|
|
ref->QuadPart = temp2.QuadPart - temp.QuadPart;
|
|
#else
|
|
ref->QuadPart = 0;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
TestOpeningStuff(PCWSTR wsSourceName, PCWSTR wsType, PCWSTR wsCount)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
LARGE_INTEGER llStartCount, llEndCount, llCountsPerSec, llTotalSizeSoFar;
|
|
LARGE_INTEGER CpuIdLag;
|
|
BYTE bBuffer[65536];
|
|
SIZE_T cNumTries = _wtol(wsCount);
|
|
double dCountsPerSecond, dSeconds, dCountsPerIteration, dSecondsPerIteration;
|
|
int iFinalIterationsPerSecond;
|
|
|
|
GetCpuIdLag(&CpuIdLag);
|
|
|
|
llTotalSizeSoFar.QuadPart = 0;
|
|
|
|
{
|
|
FUSION_PERF_INFO PerfInfo[2];
|
|
HANDLE hFile;
|
|
|
|
for (int i = 0; i < 5000; i++)
|
|
{
|
|
PERFINFOTIME(&PerfInfo[0], hFile = ::CreateFileW(wsSourceName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL));
|
|
PERFINFOTIME(&PerfInfo[1], ::CloseHandle(hFile));
|
|
}
|
|
|
|
FusionpReportPerfInfo(
|
|
FUSIONPERF_DUMP_TO_STDOUT |
|
|
FUSIONPERF_DUMP_ALL_STATISTICS |
|
|
FUSIONPERF_DUMP_ALL_SOURCEINFO,
|
|
PerfInfo,
|
|
NUMBER_OF(PerfInfo));
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Map the DLL as a resource a few thousand times.
|
|
//
|
|
if ((wsType[0] == L'd') || (wsType[0] == L's'))
|
|
{
|
|
FUSION_PERF_INFO PerfInfo[7];
|
|
|
|
HMODULE hDllModule;
|
|
HRSRC hManifestResource;
|
|
HGLOBAL hResource;
|
|
PVOID pvResourceData;
|
|
SIZE_T cbResourceSize;
|
|
|
|
for (SIZE_T i = 0; i < cNumTries; i++)
|
|
{
|
|
PERFINFOTIME(&PerfInfo[0], hDllModule = ::LoadLibraryExW(wsSourceName, NULL, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE));
|
|
PERFINFOTIME(&PerfInfo[1], hManifestResource = ::FindResourceW(hDllModule, L"#1", MAKEINTRESOURCEW(RT_MANIFEST)));
|
|
PERFINFOTIME(&PerfInfo[2], hResource = ::LoadResource(hDllModule, hManifestResource));
|
|
PERFINFOTIME(&PerfInfo[3], pvResourceData = ::LockResource(hResource));
|
|
PERFINFOTIME(&PerfInfo[4], cbResourceSize = ::SizeofResource(hDllModule, hManifestResource));
|
|
|
|
PERFINFOTIME(&PerfInfo[5],
|
|
{ for (SIZE_T i2 = 0; i2 < cbResourceSize; i2++)
|
|
bBuffer[i2] = ((PBYTE)pvResourceData)[i2]; }
|
|
);
|
|
|
|
PERFINFOTIME(&PerfInfo[6], FreeLibrary(hDllModule))
|
|
}
|
|
|
|
FusionpReportPerfInfo(
|
|
FUSIONPERF_DUMP_TO_STDOUT |
|
|
FUSIONPERF_DUMP_ALL_STATISTICS |
|
|
FUSIONPERF_DUMP_ALL_SOURCEINFO,
|
|
PerfInfo,
|
|
NUMBER_OF(PerfInfo));
|
|
}
|
|
else if (wsType[0] == L'x')
|
|
{
|
|
HANDLE hFile;
|
|
HANDLE hFileMapping;
|
|
PVOID pvFileData;
|
|
SIZE_T cbFileSize;
|
|
|
|
FUSION_PERF_INFO PerfInfo[9];
|
|
|
|
for (SIZE_T i = 0; i < cNumTries; i++)
|
|
{
|
|
PERFINFOTIME(&PerfInfo[0], hFile = ::CreateFileW(wsSourceName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL));
|
|
PERFINFOTIME(&PerfInfo[1], cbFileSize = ::GetFileSize(hFile, 0));
|
|
PERFINFOTIME(&PerfInfo[2], hFileMapping = ::CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL));
|
|
PERFINFOTIME(&PerfInfo[3], pvFileData = ::MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0));
|
|
|
|
PERFINFOTIME(&PerfInfo[4], { for (SIZE_T i2 = 0; i2 < cbFileSize; i2++)
|
|
PERFINFOTIME(&PerfInfo[8], bBuffer[i2] = ((PBYTE)pvFileData)[i2]); });
|
|
|
|
PERFINFOTIME(&PerfInfo[5], ::UnmapViewOfFile(pvFileData));
|
|
PERFINFOTIME(&PerfInfo[6], ::CloseHandle(hFileMapping));
|
|
PERFINFOTIME(&PerfInfo[7], ::CloseHandle(hFile));
|
|
}
|
|
|
|
FusionpReportPerfInfo(
|
|
FUSIONPERF_DUMP_TO_STDOUT |
|
|
FUSIONPERF_DUMP_ALL_STATISTICS |
|
|
FUSIONPERF_DUMP_ALL_SOURCEINFO,
|
|
PerfInfo,
|
|
NUMBER_OF(PerfInfo));
|
|
}
|
|
else if (wsType[0] == L'r')
|
|
{
|
|
BYTE bTempBlock[8192];
|
|
ULONG cbReadCount;
|
|
FUSION_PERF_INFO PerfInfo[3];
|
|
|
|
for (SIZE_T i = 0; i < cNumTries; i++)
|
|
{
|
|
CResourceStream RStream;
|
|
|
|
QueryPerformanceCounter(&llStartCount);
|
|
|
|
PERFINFOTIME(&PerfInfo[0], RStream.Initialize(wsSourceName, MAKEINTRESOURCEW(RT_MANIFEST)));
|
|
PERFINFOTIME(&PerfInfo[1], RStream.Read(bTempBlock, sizeof(bTempBlock), &cbReadCount));
|
|
|
|
PERFINFOTIME(&PerfInfo[2],
|
|
for (SIZE_T i2 = 0; i2 < cbReadCount; i2++)
|
|
{
|
|
bBuffer[i2] = bTempBlock[i2];
|
|
}
|
|
);
|
|
|
|
wprintf(L"%s", bBuffer);
|
|
|
|
QueryPerformanceCounter(&llEndCount);
|
|
llTotalSizeSoFar.QuadPart += llEndCount.QuadPart - llStartCount.QuadPart;
|
|
}
|
|
|
|
for (int i = 0; i < NUMBER_OF(PerfInfo); i++)
|
|
{
|
|
FusionpDumpPerfInfo(FUSIONPERF_DUMP_TO_STDOUT, PerfInfo + i);
|
|
}
|
|
}
|
|
else if (wsType[0] == L'f')
|
|
{
|
|
BYTE bTempBlock[8192];
|
|
ULONG cbReadCount;
|
|
|
|
for (SIZE_T i = 0; i < cNumTries; i++)
|
|
{
|
|
CFileStream RStream;
|
|
|
|
QueryPerformanceCounter(&llStartCount);
|
|
|
|
RStream.OpenForRead(
|
|
wsSourceName,
|
|
CImpersonationData(),
|
|
FILE_SHARE_READ,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_SEQUENTIAL_SCAN);
|
|
|
|
RStream.Read(bTempBlock, sizeof(bTempBlock), &cbReadCount);
|
|
|
|
for (SIZE_T i2 = 0; i2 < cbReadCount; i2++)
|
|
{
|
|
bBuffer[i2] = bTempBlock[i2];
|
|
}
|
|
|
|
QueryPerformanceCounter(&llEndCount);
|
|
llTotalSizeSoFar.QuadPart += llEndCount.QuadPart - llStartCount.QuadPart;
|
|
}
|
|
}
|
|
|
|
QueryPerformanceFrequency(&llCountsPerSec);
|
|
|
|
dCountsPerIteration = (double)llTotalSizeSoFar.QuadPart / cNumTries;
|
|
dCountsPerSecond = (double)llCountsPerSec.QuadPart;
|
|
dSeconds = (double)llTotalSizeSoFar.QuadPart / dCountsPerSecond;
|
|
dSecondsPerIteration = dCountsPerIteration / dCountsPerSecond;
|
|
|
|
iFinalIterationsPerSecond = static_cast<int>(1.0 / dSecondsPerIteration);
|
|
|
|
fwprintf(
|
|
stdout,
|
|
L"Completed %d runs: %d attempts per second available\n",
|
|
cNumTries,
|
|
iFinalIterationsPerSecond);
|
|
|
|
fSuccess = TRUE;
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
|
|
BOOL
|
|
TestVerifyFileSignature(PCWSTR wsFilename)
|
|
{
|
|
WINTRUST_FILE_INFO fInfo;
|
|
WINTRUST_DATA wtData;
|
|
GUID guidTrustType = WINTRUST_ACTION_GENERIC_VERIFY_V2;
|
|
HRESULT hResult = E_FAIL;
|
|
PWSTR pwszMessageText = NULL;
|
|
|
|
ZeroMemory(&wtData, sizeof(wtData));
|
|
ZeroMemory(&fInfo, sizeof(fInfo));
|
|
|
|
fInfo.cbStruct = sizeof(fInfo);
|
|
fInfo.pcwszFilePath = wsFilename;
|
|
fInfo.hFile = NULL;
|
|
|
|
wtData.cbStruct = sizeof(wtData);
|
|
wtData.dwUIChoice = WTD_UI_ALL;
|
|
wtData.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN;
|
|
wtData.dwUnionChoice = WTD_CHOICE_FILE;
|
|
wtData.pFile = &fInfo;
|
|
|
|
hResult = WinVerifyTrust(0, &guidTrustType, &wtData);
|
|
|
|
if (FAILED(hResult))
|
|
{
|
|
::FormatMessageW(
|
|
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
|
NULL,
|
|
hResult,
|
|
0,
|
|
(PWSTR)&pwszMessageText,
|
|
500,
|
|
NULL);
|
|
|
|
fwprintf(stdout, L"Error: %ls (code 0x%08x)\n", pwszMessageText, hResult);
|
|
LocalFree(pwszMessageText);
|
|
}
|
|
else
|
|
{
|
|
fwprintf(stdout, L"File signature(s) are valid.");
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
__inline
|
|
ULONGLONG
|
|
GetCycleCount(void)
|
|
{
|
|
#if defined(_X86_)
|
|
__asm {
|
|
RDTSC
|
|
}
|
|
#else
|
|
return 0;
|
|
#endif // defined(_X86_)
|
|
}
|
|
|
|
BOOL TestMessagePerf(int argc, wchar_t **argv, int *piNext)
|
|
{
|
|
ATOM a;
|
|
WNDCLASSEXW wc;
|
|
ULONGLONG cc1, cc2, cc3, cc4;
|
|
ULONG i, t;
|
|
HWND hwnd;
|
|
MSG m;
|
|
ULONG mcount;
|
|
HANDLE hActCtx = NULL;
|
|
ULONG_PTR ulCookie;
|
|
|
|
wc.cbSize = sizeof(wc);
|
|
wc.style = 0;
|
|
wc.lpfnWndProc = &TestMessagePerfWndProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = NULL;
|
|
wc.hIcon = NULL;
|
|
wc.hCursor = NULL;
|
|
wc.hbrBackground = NULL;
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = L"SxsMsgPerfTest";
|
|
wc.hIconSm = NULL;
|
|
|
|
printf("Beginning message perf test...\n");
|
|
|
|
a = ::RegisterClassExW(&wc);
|
|
if (a == NULL)
|
|
{
|
|
printf("RegisterClassExW() failed; ::GetLastError = %d\n", ::GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
if (argv[*piNext][0] != L'*')
|
|
{
|
|
ACTCTXW ac;
|
|
|
|
ac.cbSize = sizeof(ac);
|
|
ac.dwFlags = 0;
|
|
ac.lpSource = argv[*piNext];
|
|
hActCtx = ::CreateActCtxW(&ac);
|
|
if (hActCtx == INVALID_HANDLE_VALUE)
|
|
{
|
|
printf("CreateActCtxW() failed; ::GetLastError() = %d\n", ::GetLastError());
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
if (!ActivateActCtx(hActCtx, &ulCookie))
|
|
{
|
|
printf("ActivateActCtx() failed; ::GetLastError() = %d\n", ::GetLastError());
|
|
goto ErrorExit;
|
|
}
|
|
|
|
(*piNext)++;
|
|
|
|
hwnd = ::CreateWindowW(
|
|
(LPCWSTR) a,
|
|
L"PerfTestWindow",
|
|
WS_VISIBLE,
|
|
0, // x
|
|
0, // y
|
|
100, // width
|
|
100, // height
|
|
NULL, // hwndParent
|
|
NULL, // hMenu
|
|
NULL, // hInstance
|
|
NULL); // lpParam
|
|
if (hwnd == NULL)
|
|
return FALSE;
|
|
|
|
t = _wtoi(argv[*piNext]);
|
|
(*piNext)++;
|
|
|
|
mcount = 0;
|
|
cc3 = 0;
|
|
cc4 = 0;
|
|
|
|
for (i=0; i<t; i++)
|
|
{
|
|
if (!PostMessageW(hwnd, WM_USER, 0, 0))
|
|
{
|
|
printf("PostMessageW() failed; ::GetLastError() = %d\n", ::GetLastError());
|
|
goto ErrorExit;
|
|
}
|
|
|
|
cc1 = GetCycleCount();
|
|
|
|
while (::PeekMessage(&m, hwnd, 0, 0, PM_REMOVE))
|
|
{
|
|
mcount++;
|
|
::TranslateMessage(&m);
|
|
::DispatchMessage(&m);
|
|
}
|
|
|
|
cc2 = GetCycleCount();
|
|
|
|
// accumulate the time spend just processing the message...
|
|
cc3 = cc3 + (cc2 - cc1);
|
|
}
|
|
|
|
printf("%lu messages in %I64u cycles\n", mcount, cc3);
|
|
printf(" avg cycles/msg: %I64u\n", static_cast<ULONGLONG>((cc3 / static_cast<ULONGLONG>(mcount))));
|
|
|
|
return TRUE;
|
|
|
|
ErrorExit:
|
|
return FALSE;
|
|
}
|
|
|
|
LRESULT CALLBACK TestMessagePerfWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
void
|
|
TestTrickyMultipleAssemblyCacheItems(PCWSTR pvManifest)
|
|
{
|
|
PFNCreateAssemblyCacheItem pCreateAssemblyCacheItem;
|
|
PFNCreateAssemblyCache pCreateAssemblyCache;
|
|
CSmartRef<IAssemblyCache> AssemblyCache;
|
|
CSmartRef<IAssemblyCacheItem> AssemblyCacheItems[2];
|
|
CStringBuffer sbManifestName;
|
|
HRESULT hr;
|
|
|
|
LoadSxs();
|
|
GetSxsProc("CreateAssemblyCache", &pCreateAssemblyCache);
|
|
GetSxsProc("CreateAssemblyCacheItem", &pCreateAssemblyCacheItem);
|
|
|
|
sbManifestName.Win32Assign(pvManifest, wcslen(pvManifest));
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
CSmartRef<IStream> pStream;
|
|
CSmartRef<IAssemblyCacheItem> AssemblyItemTemp;
|
|
CStringBuffer TempStreamName;
|
|
|
|
hr = pCreateAssemblyCacheItem(
|
|
&AssemblyItemTemp,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
0);
|
|
|
|
//
|
|
// Manifest
|
|
//
|
|
hr = AssemblyItemTemp->CreateStream(0, pvManifest, STREAM_FORMAT_WIN32_MANIFEST, 0, &pStream, NULL);
|
|
TempStreamName.Win32Assign(sbManifestName);
|
|
hr = Helper_WriteStream(&TempStreamName, pStream);
|
|
pStream.Release();
|
|
|
|
//
|
|
// Dll
|
|
//
|
|
sbManifestName.Win32ChangePathExtension(L".dll", 4, eAddIfNoExtension);
|
|
hr = AssemblyItemTemp->CreateStream(0, static_cast<PCWSTR>(TempStreamName), STREAM_FORMAT_WIN32_MODULE, 0, &pStream, NULL);
|
|
hr = Helper_WriteStream(&TempStreamName, pStream);
|
|
pStream.Release();
|
|
|
|
hr = AssemblyItemTemp->Commit(0, NULL);
|
|
AssemblyCacheItems[i] = AssemblyItemTemp;
|
|
}
|
|
/*
|
|
hr = pCreateAssemblyCache(&AssemblyCache, 0);
|
|
hr = AssemblyCache->MarkAssembliesVisible((IUnknown**)AssemblyCacheItems, 2, 0);
|
|
*/
|
|
}
|
|
|
|
|
|
void
|
|
TestSfcScanKickoff()
|
|
{
|
|
SXSP_DEBUG_FUNCTION pfn;
|
|
BOOL fSuccess = FALSE;
|
|
|
|
LoadSxs();
|
|
GetSxsProc(SXSP_DEBUG_ORDINAL, &pfn);
|
|
|
|
fSuccess = (*pfn)(SXS_DEBUG_SFC_SCANNER, 0, NULL, NULL);
|
|
}
|
|
|
|
|
|
void
|
|
GenerateStrongNameAndPublicKey(PCWSTR wsCertificate)
|
|
{
|
|
BOOL bSuccess = FALSE;
|
|
|
|
CStringBuffer sbStrings[3];
|
|
PCCERT_CONTEXT pContext = NULL;
|
|
SXSP_DEBUG_FUNCTION pfn;
|
|
HCERTSTORE hCertStore = NULL;
|
|
|
|
hCertStore = CertOpenStore(
|
|
CERT_STORE_PROV_FILENAME,
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
NULL,
|
|
CERT_STORE_OPEN_EXISTING_FLAG,
|
|
(void*)wsCertificate);
|
|
|
|
LoadSxs();
|
|
GetSxsProc(SXSP_DEBUG_ORDINAL, &pfn);
|
|
|
|
while (pContext = CertEnumCertificatesInStore(hCertStore, pContext))
|
|
{
|
|
bSuccess = (*pfn)(SXS_DEBUG_GET_STRONGNAME, 0, (PCWSTR)pContext, (PVOID)sbStrings);
|
|
|
|
wprintf(L"Signer display name: %ls\n\tPublic Key: %ls\n\tPublic Key Token: %ls\n",
|
|
static_cast<PCWSTR>(sbStrings[0]),
|
|
static_cast<PCWSTR>(sbStrings[1]),
|
|
static_cast<PCWSTR>(sbStrings[2]));
|
|
|
|
}
|
|
|
|
bSuccess = TRUE;
|
|
|
|
if (pContext) CertFreeCertificateContext(pContext);
|
|
if (hCertStore) CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
|
|
}
|
|
|
|
BOOL CALLBACK
|
|
DumpResourceWorker(
|
|
HMODULE hModule,
|
|
PCWSTR lpszType,
|
|
PWSTR lpszName,
|
|
LONG_PTR lParam
|
|
)
|
|
{
|
|
HGLOBAL hGlobal;
|
|
HRSRC hResource;
|
|
PVOID pvData;
|
|
SIZE_T cbResource;
|
|
|
|
hResource = ::FindResourceW(hModule, lpszName, lpszType);
|
|
hGlobal = ::LoadResource(hModule, hResource);
|
|
pvData = ::LockResource(hGlobal);
|
|
|
|
if (lpszName < (PCWSTR)0xFFFF)
|
|
{
|
|
wprintf(L"----\nResource id: %p\n", lpszName);
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"----\nResource name: %ls\n", lpszName);
|
|
}
|
|
|
|
cbResource = ::SizeofResource(hModule, hResource);
|
|
|
|
for (SIZE_T i = 0; i < cbResource; i++)
|
|
{
|
|
wprintf(L"%c", ((char*)pvData)[i]);
|
|
}
|
|
wprintf(L"\n");
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
TestDumpContainedManifests(PCWSTR wsFilename)
|
|
{
|
|
HMODULE hThing;
|
|
|
|
hThing = ::LoadLibraryExW(wsFilename, NULL, LOAD_LIBRARY_AS_DATAFILE);
|
|
|
|
if ((hThing == NULL) || (hThing == INVALID_HANDLE_VALUE))
|
|
{
|
|
wprintf(L"Bad mojo: can't open %ls for enumeration.\n", wsFilename);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!::EnumResourceNamesW(hThing, MAKEINTRESOURCEW(RT_MANIFEST), DumpResourceWorker, NULL))
|
|
{
|
|
if (GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND)
|
|
{
|
|
wprintf(L"No manifests found in %ls\n", wsFilename);
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"Bad mojo: can't enumerate resources from %ls, error=0x%08x\n",
|
|
wsFilename,
|
|
::GetLastError());
|
|
}
|
|
}
|
|
::FreeLibrary(hThing);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL TestGenerateStringWithIdenticalHash(WCHAR iString[33])
|
|
{
|
|
#define START_VALUE 1
|
|
#define STR_LEN 32
|
|
#define HASH_SEED 65599
|
|
#define MAGIC_ARRAY {1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1,-1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1} ;
|
|
|
|
#define UPPER(ch) if (ch >=L'a' && ch <= L'z') ch = ch- L'a' + L'A';
|
|
|
|
WCHAR oString[STR_LEN + 1];
|
|
DWORD i, nLen, a[STR_LEN];
|
|
ULONG hash1, hash2;
|
|
WCHAR ch;
|
|
|
|
a[0] = a[1] = START_VALUE;
|
|
nLen = 2;
|
|
while(nLen < STR_LEN) {
|
|
for(i = nLen; i < nLen*2; i++)
|
|
a[i] = static_cast<ULONG>(-static_cast<LONG>(a[i-nLen]));
|
|
nLen *= 2;
|
|
}
|
|
|
|
oString[32] = iString[32] = L'\0';
|
|
|
|
// generate the new string
|
|
for (i = 0; i< 32; i++)
|
|
oString[i] = static_cast<WCHAR>(iString[i] + a[i]);
|
|
|
|
// verify that these two string have the same hash
|
|
hash1 = 0 ;
|
|
for (i = 0 ; i<STR_LEN; i++) {
|
|
ch = iString[i];
|
|
UPPER(ch);
|
|
hash1 = hash1*HASH_SEED + ch;
|
|
}
|
|
|
|
hash2 = 0 ;
|
|
for (i = 0 ; i<STR_LEN; i++){
|
|
ch = oString[i];
|
|
UPPER(ch);
|
|
hash2 = hash2*HASH_SEED + ch;
|
|
}
|
|
|
|
return (hash1 == hash2)? TRUE : FALSE;
|
|
|
|
#undef START_VALUE
|
|
#undef STR_LEN
|
|
#undef HASH_SEED
|
|
}
|
|
|
|
BOOL TestAssemblyIdentityHash()
|
|
{
|
|
SXSP_DEBUG_FUNCTION pfn = NULL;
|
|
BOOL fSuccess = FALSE;
|
|
LoadSxs();
|
|
|
|
GetSxsProc(SXSP_DEBUG_ORDINAL, &pfn);
|
|
|
|
fSuccess = (*pfn)(SXS_DEBUG_ASSEMBLY_IDENTITY_HASH, 0, 0, NULL);
|
|
|
|
if (! fSuccess){
|
|
fprintf(stderr, "%s failed!\n", __FUNCTION__);
|
|
return EXIT_FAILURE;
|
|
}
|
|
else
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
const static WCHAR Beta2Manifest[] =
|
|
L"<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
|
|
L" <assemblyIdentity type=\"win32\" name=\"cards\" version=\"2.0.0.0\" processorArchitecture=\"X86\" language=\"en-us\" />"
|
|
L" <file name=\"cards.dll\"/>"
|
|
L"</assembly>;"
|
|
;
|
|
|
|
// check whether the handle counter of csrss has changed dramatically after running this code.....
|
|
VOID TestCreateActctxLeakHandles(DWORD dwCallCounter)
|
|
{
|
|
int result = -1;
|
|
BOOL fSuccess;
|
|
|
|
for (DWORD i =0 ; i < dwCallCounter ; i ++)
|
|
{
|
|
HANDLE ActivationContextHandle = ::CreateActivationContextFromStringW(InheritManifest);
|
|
if (ActivationContextHandle == INVALID_HANDLE_VALUE) {
|
|
result = i ;
|
|
break;
|
|
}
|
|
|
|
ULONG_PTR Cookie;
|
|
ActivateActCtx(ActivationContextHandle, &Cookie);
|
|
|
|
HINSTANCE hInstanceKernel32 = ::GetModuleHandleW(L"KERNEL32.DLL");
|
|
PQUERYACTCTXW_FUNC pQueryActCtxW = (PQUERYACTCTXW_FUNC) ::GetProcAddress(hInstanceKernel32, "QueryActCtxW");
|
|
|
|
SIZE_T CbWritten;
|
|
|
|
if (pQueryActCtxW != NULL)
|
|
{
|
|
for ( ULONG ulInfoClass = ActivationContextBasicInformation; ulInfoClass <= FileInformationInAssemblyOfAssemblyInActivationContext; ulInfoClass ++)
|
|
{
|
|
switch (ulInfoClass) {
|
|
case ActivationContextBasicInformation :
|
|
break;
|
|
|
|
case ActivationContextDetailedInformation :
|
|
{
|
|
struct
|
|
{
|
|
ACTIVATION_CONTEXT_DETAILED_INFORMATION acdi;
|
|
WCHAR Buffer[_MAX_PATH * 3]; // manifest, policy and appdir
|
|
} Data;
|
|
ULONG index = 0 ;
|
|
fSuccess = (*pQueryActCtxW)(0, ActivationContextHandle, &index, ulInfoClass, &Data, sizeof(Data), &CbWritten);
|
|
fprintf(stderr, "\ncall QueryActCtxW with ActivationContextDetailedInformation\n" );
|
|
if (fSuccess)
|
|
{
|
|
fprintf(stderr, "1st string: %ls\n", Data.acdi.lpAppDirPath);
|
|
fprintf(stderr, "2nd string: %ls\n", Data.acdi.lpRootManifestPath);
|
|
}
|
|
else
|
|
fprintf(stderr, "QueryActCtxW() failed; ::GetLastError() = %d\n", ::GetLastError());
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case AssemblyDetailedInformationInActivationContext:
|
|
{
|
|
struct
|
|
{
|
|
ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION acdi;
|
|
WCHAR Buffer[_MAX_PATH * 4];
|
|
} Data;
|
|
ULONG AssemblyIndex = 1;
|
|
fSuccess = (*pQueryActCtxW)(0, ActivationContextHandle, &AssemblyIndex, ulInfoClass, &Data, sizeof(Data), &CbWritten);
|
|
|
|
fprintf(stderr, "\ncall QueryActCtxW with AssemblyDetailedInformationInActivationContext\n" );
|
|
if (fSuccess)
|
|
{
|
|
fprintf(stderr, "Encoded assembly Identity: %ls\n", Data.acdi.lpAssemblyEncodedAssemblyIdentity);
|
|
fprintf(stderr, "manifest path: %ls\n", Data.acdi.lpAssemblyManifestPath);
|
|
fprintf(stderr, "policy path: %ls\n", Data.acdi.lpAssemblyPolicyPath);
|
|
fprintf(stderr, "Assembly Directory: %ls\n", Data.acdi.lpAssemblyDirectoryName);
|
|
}
|
|
else
|
|
fprintf(stderr, "QueryActCtxW() failed; ::GetLastError() = %d\n", ::GetLastError());
|
|
}
|
|
break;
|
|
|
|
case FileInformationInAssemblyOfAssemblyInActivationContext:
|
|
{
|
|
struct
|
|
{
|
|
ASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION acdi;
|
|
WCHAR Buffer[_MAX_PATH * 2];
|
|
} Data;
|
|
ACTIVATION_CONTEXT_QUERY_INDEX index;
|
|
index.ulAssemblyIndex = 1;
|
|
index.ulFileIndexInAssembly = 0;
|
|
|
|
fSuccess = (*pQueryActCtxW)(0, ActivationContextHandle, &index, ulInfoClass, &Data, sizeof(Data), &CbWritten);
|
|
|
|
fprintf(stderr, "\ncall QueryActCtxW with FileInformationInAssemblyOfAssemblyInActivationContext\n" );
|
|
if (fSuccess)
|
|
{
|
|
fprintf(stderr, "file name: %ls\n", Data.acdi.lpFileName);
|
|
fprintf(stderr, "file path: %ls\n", Data.acdi.lpFilePath);
|
|
}
|
|
else
|
|
fprintf(stderr, "QueryActCtxW() failed; ::GetLastError() = %d\n", ::GetLastError());
|
|
}
|
|
} // end of switch
|
|
|
|
}// end of for
|
|
}
|
|
|
|
DeactivateActCtx(0, Cookie);
|
|
// CloseHandle(ActivationContextHandle);
|
|
}
|
|
return;
|
|
}
|
|
|
|
BOOL TestSystemDefaultActivationContextGeneration()
|
|
{
|
|
SXSP_DEBUG_FUNCTION pfn = NULL;
|
|
BOOL fSuccess = FALSE;
|
|
|
|
LoadSxs();
|
|
|
|
GetSxsProc(SXSP_DEBUG_ORDINAL, &pfn);
|
|
|
|
fSuccess = (*pfn)(SXS_DEBUG_SYSTEM_DEFAULT_ACTCTX_GENERATION, 0, NULL, NULL);
|
|
|
|
if (! fSuccess){
|
|
fprintf(stderr, "%s failed!\n", __FUNCTION__);
|
|
return EXIT_FAILURE;
|
|
}
|
|
else
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
CHAR g_AsyncIOBuffer[16384];
|
|
|
|
struct AsyncIOBlock
|
|
{
|
|
OVERLAPPED ol_input;
|
|
OVERLAPPED ol_output;
|
|
HANDLE hInputFile;
|
|
HANDLE hOutputFile;
|
|
} g_AsyncIOBlock;
|
|
|
|
bool g_AsyncIODone = false;
|
|
DWORD g_AsyncIOError = ERROR_SUCCESS;
|
|
|
|
VOID CALLBACK AsyncReadCompleted(
|
|
DWORD dwErrorCode,
|
|
DWORD dwBytesTransferred,
|
|
LPOVERLAPPED ol
|
|
);
|
|
|
|
VOID CALLBACK AsyncWriteCompleted(
|
|
DWORD dwErrorCode,
|
|
DWORD dwBytesTransferred,
|
|
LPOVERLAPPED ol
|
|
);
|
|
|
|
VOID CALLBACK AsyncReadCompleted(
|
|
DWORD dwErrorCode,
|
|
DWORD dwBytesTransferred,
|
|
LPOVERLAPPED ol
|
|
)
|
|
{
|
|
if (dwErrorCode != ERROR_SUCCESS)
|
|
{
|
|
fprintf(stderr, "Error passed to AsyncReadCompleted(); error code = %ul; bytes transferred = %ul\n", dwErrorCode, dwBytesTransferred);
|
|
g_AsyncIOError = dwErrorCode;
|
|
g_AsyncIODone = true;
|
|
}
|
|
else
|
|
{
|
|
g_AsyncIOBlock.ol_input.Offset += dwBytesTransferred;
|
|
if (!::WriteFileEx(g_AsyncIOBlock.hOutputFile, g_AsyncIOBuffer, dwBytesTransferred, &g_AsyncIOBlock.ol_output, &AsyncWriteCompleted))
|
|
{
|
|
g_AsyncIOError = ::GetLastError();
|
|
fprintf(stderr, "WriteFileEx() failed; ::GetLastError() = %d\n", g_AsyncIOError);
|
|
g_AsyncIODone = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID CALLBACK AsyncWriteCompleted(
|
|
DWORD dwErrorCode,
|
|
DWORD dwBytesTransferred,
|
|
LPOVERLAPPED ol
|
|
)
|
|
{
|
|
if (dwErrorCode != ERROR_SUCCESS)
|
|
{
|
|
fprintf(stderr, "Error passed to AsyncWriteCompleted(); error code = %ul; dwBytesTransferred = %ul\n", dwErrorCode, dwBytesTransferred);
|
|
g_AsyncIOError = dwErrorCode;
|
|
g_AsyncIODone = true;
|
|
}
|
|
else
|
|
{
|
|
g_AsyncIOBlock.ol_output.Offset += dwBytesTransferred;
|
|
if (!::ReadFileEx(g_AsyncIOBlock.hInputFile, g_AsyncIOBuffer, sizeof(g_AsyncIOBuffer), &g_AsyncIOBlock.ol_input, &AsyncReadCompleted))
|
|
{
|
|
g_AsyncIOError = ::GetLastError();
|
|
if (g_AsyncIOError != ERROR_HANDLE_EOF)
|
|
fprintf(stderr, "ReadFileEx() failed; ::GetLastError() = %d\n", g_AsyncIOError);
|
|
else
|
|
g_AsyncIOError = ERROR_SUCCESS;
|
|
g_AsyncIODone = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
TestAsyncIO(int argc, wchar_t **argv, int *piNext)
|
|
{
|
|
HANDLE hFileIn;
|
|
HANDLE hFileOut;
|
|
HANDLE hActCtx = NULL;
|
|
ULONG_PTR cookie = 0;
|
|
PCWSTR pszManifest;
|
|
PCWSTR pszInputFile;
|
|
PCWSTR pszOutputFile;
|
|
ACTCTXW acw;
|
|
|
|
pszManifest = argv[(*piNext)++];
|
|
pszInputFile = argv[(*piNext)++];
|
|
pszOutputFile = argv[(*piNext)++];
|
|
|
|
if (wcscmp(pszManifest, L"-") != 0)
|
|
{
|
|
acw.cbSize = sizeof(acw);
|
|
acw.dwFlags = 0;
|
|
acw.lpSource = pszManifest;
|
|
|
|
hActCtx = ::CreateActCtxW(&acw);
|
|
if (hActCtx == INVALID_HANDLE_VALUE)
|
|
{
|
|
fprintf(stderr, "CreateActCtxW() on %ls failed; ::GetLastError() = %d\n", pszManifest, ::GetLastError());
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|
|
|
|
hFileIn = ::CreateFileW(pszInputFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
|
if (hFileIn == INVALID_HANDLE_VALUE)
|
|
{
|
|
fprintf(stderr, "CreateFileW() on %ls failed; ::GetLastError() = %d\n", pszInputFile, ::GetLastError());
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
hFileOut = ::CreateFileW(pszOutputFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL);
|
|
if (hFileOut == INVALID_HANDLE_VALUE)
|
|
{
|
|
fprintf(stderr, "CreateFileW() on %ls failed; ::GetLastError() = %d\n", pszOutputFile, ::GetLastError());
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
ActivateActCtx(hActCtx, &cookie);
|
|
|
|
g_AsyncIOBlock.ol_input.Offset = 0;
|
|
g_AsyncIOBlock.ol_input.OffsetHigh = 0;
|
|
g_AsyncIOBlock.ol_output.Offset = 0;
|
|
g_AsyncIOBlock.ol_output.OffsetHigh = 0;
|
|
g_AsyncIOBlock.hInputFile = hFileIn;
|
|
g_AsyncIOBlock.hOutputFile = hFileOut;
|
|
|
|
if (!::ReadFileEx(hFileIn, &g_AsyncIOBuffer, sizeof(g_AsyncIOBuffer), &g_AsyncIOBlock.ol_input, &AsyncReadCompleted))
|
|
{
|
|
fprintf(stderr, "First ReadFileEx() failed; ::GetLastError() = %d\n", ::GetLastError());
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
while (!g_AsyncIODone)
|
|
{
|
|
::SleepEx(1000, TRUE);
|
|
}
|
|
|
|
if (g_AsyncIOError != ERROR_SUCCESS)
|
|
{
|
|
fprintf(stderr, "Async IO test failed; win32 error code = %d\n", g_AsyncIOError);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
CloseHandle(hFileIn);
|
|
CloseHandle(hFileOut);
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
static
|
|
DWORD
|
|
WINAPI
|
|
TestThreadInheritLeakThreadProc(
|
|
LPVOID lpParameter
|
|
)
|
|
{
|
|
// Don't need to do anything...
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
TestThreadInheritLeak()
|
|
{
|
|
HANDLE ActivationContextHandle = ::CreateActivationContextFromStringW(InheritManifest);
|
|
DWORD dwThreadId;
|
|
ULONG_PTR ulpCookie;
|
|
HANDLE hThread = NULL;
|
|
|
|
::ActivateActCtx(ActivationContextHandle, &ulpCookie);
|
|
hThread = ::CreateThread(NULL, 0, &TestThreadInheritLeakThreadProc, NULL, 0, &dwThreadId);
|
|
|
|
if (hThread == NULL)
|
|
{
|
|
fprintf(stderr, "CreateThread() failed with ::GetLastError = %d\n", ::GetLastError());
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
WaitForSingleObject(hThread, INFINITE);
|
|
|
|
fprintf(stderr, "Created thread %lu\n", dwThreadId);
|
|
::DeactivateActCtx(0, ulpCookie);
|
|
::ReleaseActCtx(ActivationContextHandle);
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
BOOL
|
|
TestNewCatalogSignerThingy(
|
|
PCWSTR CatalogName
|
|
)
|
|
{
|
|
SXSP_DEBUG_FUNCTION pfn = NULL;
|
|
BOOL fSuccess = FALSE;
|
|
|
|
LoadSxs();
|
|
|
|
GetSxsProc(SXSP_DEBUG_ORDINAL, &pfn);
|
|
|
|
fSuccess = (*pfn)(SXS_DEBUG_CATALOG_SIGNER_CHECK, 0, CatalogName, NULL);
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
HMODULE MyHandle;
|
|
WCHAR MyModuleFullPath[MAX_PATH];
|
|
WCHAR MyModuleFullPathWithoutExtension[MAX_PATH];
|
|
|
|
/*
|
|
see \\scratch\scratch\JayK\exedll for a slightly different approach
|
|
*/
|
|
HANDLE GetExeHandle()
|
|
{
|
|
return GetModuleHandle(NULL);
|
|
}
|
|
|
|
extern "C" { extern IMAGE_DOS_HEADER __ImageBase; }
|
|
|
|
HMODULE GetMyHandle()
|
|
{
|
|
//Trace("GetMyHandle():%p\n", &__ImageBase);
|
|
return (HMODULE)&__ImageBase;
|
|
}
|
|
|
|
BOOL AmITheExe()
|
|
{
|
|
IamExe = (GetExeHandle() == GetMyHandle());
|
|
IamDll = !IamExe;
|
|
return IamExe;
|
|
}
|
|
|
|
PCWSTR GetMyModuleFullPath()
|
|
{
|
|
return
|
|
((MyModuleFullPath[0]
|
|
|| ::GetModuleFileNameW(GetMyHandle(), MyModuleFullPath, RTL_NUMBER_OF(MyModuleFullPath))),
|
|
MyModuleFullPath);
|
|
}
|
|
|
|
PCWSTR GetMyModuleFullPathWithoutExtension()
|
|
{
|
|
//
|
|
// not thread safe
|
|
//
|
|
wcscpy(MyModuleFullPathWithoutExtension, GetMyModuleFullPath());
|
|
*wcsrchr(MyModuleFullPathWithoutExtension, '.') = 0;
|
|
return MyModuleFullPathWithoutExtension;
|
|
}
|
|
|
|
void TestExeDll()
|
|
{
|
|
#if defined(_X86_)
|
|
WCHAR x[MAX_PATH];
|
|
CStringBuffer y;
|
|
|
|
Kernel32.GetModuleFileNameW(NULL, x, RTL_NUMBER_OF(x));
|
|
if (!y.Win32Assign(x, StringLength(x)))
|
|
ThrowLastError();
|
|
|
|
if (!y.Win32ChangePathExtension(L"dll", 3, eAddIfNoExtension))
|
|
ThrowLastError();
|
|
|
|
if (!CopyFileW(x, y, FALSE))
|
|
ThrowLastError();
|
|
|
|
SetDllBitInPeImage(y);
|
|
|
|
FreeLibrary(LoadLibraryW(y));
|
|
#endif
|
|
}
|
|
|
|
void PrintDll()
|
|
{
|
|
//Trace("dll %ls\n", GetMyModuleFullPath());
|
|
}
|
|
|
|
void PrintExe()
|
|
{
|
|
//Trace("exe %ls\n", GetMyModuleFullPath());
|
|
}
|
|
|
|
extern "C" void __cdecl wmainCRTStartup();
|
|
extern "C" BOOL __stdcall _DllMainCRTStartup(HINSTANCE, DWORD, PVOID);
|
|
|
|
extern "C" BOOL __stdcall DllMain(HINSTANCE DllHandle, DWORD Reason, PVOID SemiReserved)
|
|
{
|
|
//Trace("Enter DllMain\n");
|
|
switch (Reason)
|
|
{
|
|
default:
|
|
break;
|
|
case DLL_PROCESS_ATTACH:
|
|
if (
|
|
wcsstr(GetCommandLineW(), L" -tQueryActCtx")
|
|
|| wcsstr(GetCommandLineW(), L" -tqueryactctx")
|
|
|| wcsstr(GetCommandLineW(), L" /tQueryActCtx")
|
|
|| wcsstr(GetCommandLineW(), L" /tqueryactctx")
|
|
)
|
|
{
|
|
TestQueryActCtx();
|
|
}
|
|
}
|
|
//Trace("Exit DllMain\n");
|
|
return TRUE;
|
|
}
|
|
|
|
#if defined(_X86_)
|
|
|
|
extern "C" void __declspec(naked) Entry()
|
|
// This works for .dlls or .exes.
|
|
// void ExeMain(void)
|
|
// BOOL __stdcall DllMain(HINSTANCE dll, DWORD reason, void* reserved)
|
|
{
|
|
static const char* DllReason[] =
|
|
{
|
|
"DllProcessDetach %ls\n",
|
|
"DllProcessAttach %ls\n",
|
|
"DllThreadAttach %ls\n",
|
|
"DllThreadDetach %ls\n"
|
|
};
|
|
__asm {
|
|
//int 3
|
|
call AmITheExe
|
|
test eax,eax
|
|
jne Lexe
|
|
//Ldll:
|
|
call GetMyModuleFullPath
|
|
push eax
|
|
mov eax, [esp+12]
|
|
mov eax, DllReason[eax*4]
|
|
push eax
|
|
call Trace
|
|
add esp,8
|
|
jmp _DllMainCRTStartup
|
|
Lexe:
|
|
call PrintExe
|
|
jmp wmainCRTStartup
|
|
}
|
|
}
|
|
|
|
#else
|
|
|
|
extern "C" void Entry()
|
|
{
|
|
wmainCRTStartup();
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
BOOL TestSxsSfcUI()
|
|
{
|
|
SXSP_DEBUG_FUNCTION pfn = NULL;
|
|
BOOL fSuccess = FALSE;
|
|
LoadSxs();
|
|
|
|
GetSxsProc(SXSP_DEBUG_ORDINAL, &pfn);
|
|
|
|
fSuccess = (*pfn)(SXS_DEBUG_SFC_UI_TEST, 0, 0, NULL);
|
|
|
|
if (! fSuccess){
|
|
fprintf(stderr, "%s failed!\n", __FUNCTION__);
|
|
return EXIT_FAILURE;
|
|
}
|
|
else
|
|
return EXIT_SUCCESS;
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
void TestGetModuleHandleEx()
|
|
{
|
|
HMODULE p;
|
|
BOOL f;
|
|
HMODULE q;
|
|
unsigned u;
|
|
#define GetModuleHandleExA pfnGetModuleHandleExA
|
|
#define GetModuleHandleExW pfnGetModuleHandleExW
|
|
HMODULE kernel32 = GetModuleHandleW(L"Kernel32");
|
|
PGET_MODULE_HANDLE_EXA GetModuleHandleExA = reinterpret_cast<PGET_MODULE_HANDLE_EXA>(GetProcAddress(kernel32, "GetModuleHandleExA"));
|
|
PGET_MODULE_HANDLE_EXW GetModuleHandleExW = reinterpret_cast<PGET_MODULE_HANDLE_EXW>(GetProcAddress(kernel32, "GetModuleHandleExW"));
|
|
|
|
if (GetModuleHandleExA == NULL || GetModuleHandleExW == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
union
|
|
{
|
|
CHAR BufferA[MAX_PATH];
|
|
WCHAR BufferW[MAX_PATH];
|
|
};
|
|
BufferA[0] = 0;
|
|
GetWindowsDirectoryA(BufferA, MAX_PATH);
|
|
std::string windowsA = BufferA;
|
|
std::string systemA = windowsA + "System32";
|
|
|
|
BufferW[0] = 0;
|
|
GetWindowsDirectoryW(BufferW, MAX_PATH);
|
|
std::wstring windowsW = BufferW;
|
|
std::wstring systemW = windowsW + L"System32";
|
|
|
|
#define PIN GET_MODULE_HANDLE_EX_FLAG_PIN
|
|
#define NOCHANGE GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
|
|
#define ADDRESS GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
|
|
|
|
#define X(x) SetLastError(NO_ERROR); p = x; printf("%s:%p,%d\n", #x, p, ::GetLastError());
|
|
#define Y(x) SetLastError(NO_ERROR); f = x; printf("%s:%s,%p,%d\n", #x, "false\0true"+f*6, p, ::GetLastError());
|
|
printf("first some basic GetModuleHandle testing\n\n");
|
|
X(GetModuleHandleA(NULL));
|
|
X(GetModuleHandleW(NULL));
|
|
X(GetModuleHandleA("ntdll.dll"));
|
|
X(GetModuleHandleW(L"ntdll.dll"));
|
|
X(GetModuleHandleA("ntdll"));
|
|
X(GetModuleHandleW(L"ntdll"));
|
|
X(GetModuleHandleA("c:\\ntdll"));
|
|
X(GetModuleHandleW(L"c:\\ntdll"));
|
|
X(GetModuleHandleA((systemA + "\\ntdll").c_str()));
|
|
X(GetModuleHandleW((systemW + L"\\ntdll").c_str()));
|
|
X(GetModuleHandleA((systemA + "\\ntdll.dll").c_str()));
|
|
X(GetModuleHandleW((systemW + L"\\ntdll.dll").c_str()));
|
|
X(GetModuleHandleA("sxs"));
|
|
X(GetModuleHandleW(L"sxs.dll"));
|
|
|
|
printf("\n\nnow show that FreeLibrary \"works\", GetModuleHandle honors it\n\n");
|
|
X(LoadLibraryA("Sxs.dll"));
|
|
X(GetModuleHandleA("sxs"));
|
|
X(GetModuleHandleW(L"sxs.dll"));
|
|
Y(FreeLibrary(p = GetModuleHandleA("Sxs.dll")));
|
|
X(GetModuleHandleA("sxs"));
|
|
X(GetModuleHandleW(L"sxs.dll"));
|
|
X(LoadLibraryW(L"Sxs.dll"));
|
|
Y(GetModuleHandleExA(0, NULL, &p));
|
|
Y(GetModuleHandleExW(0, NULL, &p));
|
|
|
|
printf("\n\nsome invalid parameters (%d)\n\n", ERROR_INVALID_PARAMETER);
|
|
|
|
Y(GetModuleHandleExA(PIN | NOCHANGE, "sxs", &p));
|
|
Y(GetModuleHandleExW(PIN | NOCHANGE, L"sxs", &p));
|
|
Y(GetModuleHandleExA(PIN | NOCHANGE, "ntdll", &p));
|
|
Y(GetModuleHandleExW(PIN | NOCHANGE, L"ntdll", &p));
|
|
|
|
printf("\n\nshow NOCHANGE's equiv to regular\n\n");
|
|
|
|
Y(GetModuleHandleExA(NOCHANGE, "sxs", &p));
|
|
Y(GetModuleHandleExW(NOCHANGE, L"sxs", &p));
|
|
Y(FreeLibrary(p = GetModuleHandleA("Sxs.dll")));
|
|
Y(GetModuleHandleExA(NOCHANGE, "sxs", &p));
|
|
Y(GetModuleHandleExW(NOCHANGE, L"sxs", &p));
|
|
|
|
printf("\n\nshow PIN works\n\n");
|
|
|
|
X(LoadLibraryW(L"Sxs.dll"));
|
|
Y(GetModuleHandleExA(PIN, "sxs", &p));
|
|
Y(FreeLibrary(p = GetModuleHandleA("Sxs.dll")));
|
|
Y(GetModuleHandleExW(0, L"sxs", &(q = p)));
|
|
Y(GetModuleHandleExW(0, L"c:\\sxs", &p));
|
|
|
|
printf("\n\nshow the VirtualQuery form\n\n");
|
|
|
|
Y(GetModuleHandleExA(ADDRESS, "sxs", &p)); // string, actually in .exe
|
|
Y(GetModuleHandleExW(ADDRESS, L"c:\\sxs", &p));
|
|
|
|
Y(GetModuleHandleExA(ADDRESS, reinterpret_cast<LPCSTR>(q), &p));
|
|
Y(GetModuleHandleExW(ADDRESS, reinterpret_cast<LPCWSTR>(q), &p));
|
|
|
|
printf("\n\nsome more invalid parameters (%d)\n\n", ERROR_INVALID_PARAMETER);
|
|
|
|
Y(GetModuleHandleExA(0, NULL, NULL));
|
|
Y(GetModuleHandleExW(0, NULL, NULL));
|
|
|
|
printf("\n\nshow that static loads can't be unloaded\n\n");
|
|
for (u = 0 ; u < 4 ; ++u)
|
|
{
|
|
printf("%#x\n", u);
|
|
Y(FreeLibrary(p = GetModuleHandleA("kernel32")));
|
|
Y(FreeLibrary(p = GetModuleHandleW(L"sxstest.exe")));
|
|
Y(FreeLibrary(p = GetModuleHandleA("msvcrt.dll")));
|
|
}
|
|
|
|
printf("\n\ntry all flag combinations, including invalids ones\n\n");
|
|
for (u = 0 ; u <= (PIN | ADDRESS | NOCHANGE) ; ++u)
|
|
{
|
|
printf("%#x\n", u);
|
|
p = NULL;
|
|
Y( GetModuleHandleExA(u, NULL, NULL)); p = NULL;
|
|
Y( GetModuleHandleExW(u, NULL, NULL)); p = NULL;
|
|
Y( GetModuleHandleExA(u, NULL, &p)); p = NULL;
|
|
Y( GetModuleHandleExW(u, NULL, &p)); p = NULL;
|
|
if (u & ADDRESS)
|
|
{
|
|
Y( GetModuleHandleExA(u, "", NULL)); p = NULL;
|
|
Y( GetModuleHandleExW(u, reinterpret_cast<LPCWSTR>(GetModuleHandleExA), NULL)); p = NULL;
|
|
Y( GetModuleHandleExW(u, reinterpret_cast<LPCWSTR>(atexit), NULL)); p = NULL;
|
|
|
|
Y( GetModuleHandleExA(u, "", &p)); p = NULL;
|
|
Y( GetModuleHandleExW(u, reinterpret_cast<LPCWSTR>(GetModuleHandleExA), &p)); p = NULL;
|
|
Y( GetModuleHandleExW(u, reinterpret_cast<LPCWSTR>(atexit), &p)); p = NULL;
|
|
}
|
|
else
|
|
{
|
|
Y( GetModuleHandleExA(u, "foo32", NULL)); p = NULL;
|
|
Y( GetModuleHandleExW(u, L"kernel32", NULL)); p = NULL;
|
|
|
|
Y( GetModuleHandleExA(u, "foo32", &p)); p = NULL;
|
|
Y( GetModuleHandleExW(u, L"kernel32", &p)); p = NULL;
|
|
}
|
|
}
|
|
printf("\n\ntry all bits of flags, should be mostly invalid (%d)\n\n", ERROR_INVALID_PARAMETER);
|
|
for (u = 0 ; u < RTL_BITS_OF(u) ; ++u)
|
|
{
|
|
printf("%#x\n", u);
|
|
Y(GetModuleHandleExW(1<<u, L"kernel32", &p));
|
|
}
|
|
|
|
printf("\n\nPIN | ADDRESS wasn't covered\n\n", ERROR_INVALID_PARAMETER);
|
|
|
|
X(GetModuleHandleW(L"shell32"));
|
|
X(q = LoadLibraryA("shell32"));
|
|
Y(FreeLibrary(GetModuleHandleA("shell32")));
|
|
Y(GetModuleHandleExW(PIN | ADDRESS, reinterpret_cast<LPCWSTR>(q), &p));
|
|
|
|
X(q = LoadLibraryW(L"shell32"));
|
|
Y(GetModuleHandleExW(PIN | ADDRESS, reinterpret_cast<LPCWSTR>(q) + 100, &p));
|
|
Y(FreeLibrary(q)); Y(FreeLibrary(q)); Y(FreeLibrary(q));
|
|
X(GetModuleHandleW(L"shell32.dll"));
|
|
Y(GetModuleHandleExW(ADDRESS, reinterpret_cast<LPCWSTR>(q) + 1000, &p));
|
|
|
|
#undef X
|
|
#undef Y
|
|
#undef PIN
|
|
#undef NOCHANGE
|
|
#undef ADDRESS
|
|
}
|
|
|
|
void
|
|
TestGetFullPathName(
|
|
PCWSTR s
|
|
)
|
|
{
|
|
WCHAR FullPath[MAX_PATH * 2];
|
|
PWSTR FilePart = L"";
|
|
DWORD dw;
|
|
DWORD dwError;
|
|
|
|
SetLastError(NO_ERROR);
|
|
dw = GetFullPathNameW(s, RTL_NUMBER_OF(FullPath), FullPath, &FilePart);
|
|
dwError = ::GetLastError();
|
|
printf(
|
|
"GetFullPathNameW(%ls):%lu,lastError=%lu,filePart=%ls\n",
|
|
FullPath,
|
|
dw,
|
|
dwError,
|
|
FilePart
|
|
);
|
|
}
|
|
|
|
void
|
|
TestCreateFile(
|
|
PCWSTR s
|
|
)
|
|
{
|
|
HANDLE handle;
|
|
DWORD dwError;
|
|
|
|
SetLastError(NO_ERROR);
|
|
handle = CreateFileW(
|
|
s,
|
|
0,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
NULL,
|
|
OPEN_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
dwError = ::GetLastError();
|
|
if (handle != INVALID_HANDLE_VALUE)
|
|
CloseHandle(handle);
|
|
printf(
|
|
"CreateFileW(%ls):%p,lastError=%lu\n",
|
|
s,
|
|
handle,
|
|
dwError
|
|
);
|
|
}
|
|
|
|
/*
|
|
from base\ntsetup\dll\sxs.c
|
|
*/
|
|
VOID
|
|
SxspGetPathBaseName(
|
|
LPCWSTR Path,
|
|
LPWSTR Base
|
|
)
|
|
{
|
|
LPCWSTR Dot = wcsrchr(Path, '.');
|
|
LPCWSTR Slash = wcsrchr(Path, '\\');
|
|
//
|
|
// beware \foo.txt\bar
|
|
// beware \bar
|
|
// beware bar
|
|
// beware .bar
|
|
// beware \.bar
|
|
//
|
|
*Base = 0;
|
|
if (Slash == NULL)
|
|
Slash = Path;
|
|
else
|
|
Slash += 1;
|
|
if (Dot == NULL || Dot < Slash)
|
|
Dot = Path + StringLength(Path);
|
|
CopyMemory(Base, Slash, (Dot - Slash) * sizeof(*Base));
|
|
Base[Dot - Slash] = 0;
|
|
}
|
|
|
|
VOID
|
|
TestGetPathBaseName(
|
|
LPCWSTR Path
|
|
)
|
|
{
|
|
WCHAR Base[MAX_PATH];
|
|
|
|
SxspGetPathBaseName(Path, Base);
|
|
printf("\"%ls\" -> \"%ls\"\n", Path, Base);
|
|
|
|
}
|
|
|
|
void TestVersion()
|
|
{
|
|
printf(
|
|
"Windows NT %lu.%lu.%lu\n",
|
|
FusionpGetWindowsNtMajorVersion(),
|
|
FusionpGetWindowsNtMinorVersion(),
|
|
FusionpGetWindowsNtBuildVersion()
|
|
);
|
|
}
|
|
|
|
void TestGetProcessImageFileName()
|
|
{
|
|
UNICODE_STRING s;
|
|
|
|
FusionpGetProcessImageFileName(&s);
|
|
printf("%wZ\n", &s);
|
|
}
|
|
|
|
BOOL TestErrorInfra1() { FN_PROLOG_WIN32; IFW32FALSE_ORIGINATE_AND_EXIT(LoadLibraryA("1")); FN_EPILOG; }
|
|
BOOL TestErrorInfra2() { FN_PROLOG_WIN32; IFW32NULL_EXIT(LoadLibraryA(" 2 ")); FN_EPILOG; }
|
|
BOOL TestErrorInfra3() { FN_PROLOG_WIN32; IFFAILED_CONVERTHR_HRTOWIN32_EXIT_TRACE(E_FAIL | 3); FN_EPILOG; }
|
|
BOOL TestErrorInfra4() { FN_PROLOG_WIN32; IFCOMFAILED_EXIT(E_FAIL | 4); FN_EPILOG; }
|
|
BOOL TestErrorInfra5() { FN_PROLOG_WIN32; IFCOMFAILED_ORIGINATE_AND_EXIT(E_FAIL | 5); FN_EPILOG; }
|
|
BOOL TestErrorInfra6() { FN_PROLOG_WIN32; IFREGFAILED_EXIT(6); FN_EPILOG; }
|
|
BOOL TestErrorInfra7() { FN_PROLOG_WIN32; IFREGFAILED_ORIGINATE_AND_EXIT(7); FN_EPILOG; }
|
|
|
|
HRESULT TestErrorInfra8() { FN_PROLOG_HR; IFW32FALSE_ORIGINATE_AND_EXIT(LoadLibraryA("8")); FN_EPILOG; }
|
|
HRESULT TestErrorInfra9() { FN_PROLOG_HR; IFW32NULL_EXIT(LoadLibraryA("!@# 9 \\")); FN_EPILOG; }
|
|
HRESULT TestErrorInfra10() { FN_PROLOG_HR; IFFAILED_CONVERTHR_HRTOWIN32_EXIT_TRACE(E_FAIL | 10); FN_EPILOG; }
|
|
HRESULT TestErrorInfra11() { FN_PROLOG_HR; IFCOMFAILED_EXIT(E_FAIL | 11); FN_EPILOG; }
|
|
HRESULT TestErrorInfra12() { FN_PROLOG_HR; IFCOMFAILED_ORIGINATE_AND_EXIT(E_FAIL | 12); FN_EPILOG; }
|
|
HRESULT TestErrorInfra13() { FN_PROLOG_HR; IFREGFAILED_EXIT(13); FN_EPILOG; }
|
|
HRESULT TestErrorInfra14() { FN_PROLOG_HR; IFREGFAILED_ORIGINATE_AND_EXIT(14); FN_EPILOG; }
|
|
|
|
void TestErrorInfra()
|
|
{
|
|
#define X(x) DbgPrint("%s\n", #x); x()
|
|
X(TestErrorInfra1);
|
|
X(TestErrorInfra2);
|
|
X(TestErrorInfra3);
|
|
X(TestErrorInfra4);
|
|
X(TestErrorInfra5);
|
|
X(TestErrorInfra7);
|
|
X(TestErrorInfra8);
|
|
X(TestErrorInfra9);
|
|
X(TestErrorInfra10);
|
|
X(TestErrorInfra11);
|
|
X(TestErrorInfra12);
|
|
X(TestErrorInfra13);
|
|
X(TestErrorInfra14);
|
|
#undef X
|
|
}
|
|
|
|
void TestQueryActCtx3(
|
|
ULONG Flags,
|
|
HANDLE ActCtxHandle
|
|
)
|
|
{
|
|
SIZE_T BytesWrittenOrRequired = 0;
|
|
BYTE QueryBuffer[4][4096];
|
|
ACTIVATION_CONTEXT_QUERY_INDEX QueryIndex = { 0 };
|
|
PACTIVATION_CONTEXT_BASIC_INFORMATION BasicInfo = reinterpret_cast<PACTIVATION_CONTEXT_BASIC_INFORMATION>(&QueryBuffer[0]);
|
|
PASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION DllRedir = reinterpret_cast<PASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION>(&QueryBuffer[1]);
|
|
PACTIVATION_CONTEXT_DETAILED_INFORMATION ContextDetailed = reinterpret_cast<PACTIVATION_CONTEXT_DETAILED_INFORMATION>(&QueryBuffer[2]);
|
|
PACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION AssemblyDetailed = reinterpret_cast<PACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION>(&QueryBuffer[3]);
|
|
CStringBuffer decimalContext;
|
|
|
|
RtlZeroMemory(&QueryBuffer, sizeof(QueryBuffer));
|
|
|
|
if (IS_SPECIAL_ACTCTX(ActCtxHandle))
|
|
decimalContext.Win32Format(L" (%Id)", reinterpret_cast<LONG_PTR>(ActCtxHandle));
|
|
|
|
#define QueryFailed(x,n) Trace("%s:%ld:QueryActCtx(%s) failed %lu\n", __FUNCTION__, ULONG(n), x, GetLastError())
|
|
if (!QueryActCtxW(
|
|
Flags,
|
|
ActCtxHandle,
|
|
NULL,
|
|
ActivationContextBasicInformation,
|
|
&QueryBuffer,
|
|
sizeof(QueryBuffer),
|
|
&BytesWrittenOrRequired
|
|
))
|
|
QueryFailed("ActivationContextBasicInformation", __LINE__ - 1);
|
|
else
|
|
{
|
|
if (IS_SPECIAL_ACTCTX(BasicInfo->hActCtx))
|
|
decimalContext.Win32Format(L" (%Id)", reinterpret_cast<LONG_PTR>(BasicInfo->hActCtx));
|
|
Trace(
|
|
"BytesWrittenOrRequired : 0x%lx\n"
|
|
"BasicInfo->hActCtx : %p%ls\n"
|
|
"BasicInfo->Flags : 0x%lx\n",
|
|
BytesWrittenOrRequired,
|
|
BasicInfo->hActCtx,
|
|
static_cast<PCWSTR>(decimalContext),
|
|
BasicInfo->Flags
|
|
);
|
|
}
|
|
Flags = (Flags & ~QUERY_ACTCTX_FLAG_NO_ADDREF);
|
|
if (!QueryActCtxW(Flags, ActCtxHandle, NULL, ActivationContextDetailedInformation, ContextDetailed, 4096, &BytesWrittenOrRequired))
|
|
QueryFailed("ActivationContextDetailedInformation", __LINE__ - 1);
|
|
else
|
|
{
|
|
Trace(
|
|
"BytesWrittenOrRequired : 0x%lx\n"
|
|
"ContextDetailed->dwFlags : 0x%lx\n"
|
|
"ContextDetailed->ulFormatVersion : 0x%lx\n"
|
|
"ContextDetailed->ulAssemblyCount : 0x%lx\n"
|
|
"ContextDetailed->ulRootManifestPathType : 0x%lx\n"
|
|
"ContextDetailed->ulRootManifestPathChars : 0x%lx\n"
|
|
"ContextDetailed->ulRootConfigurationPathType : 0x%lx\n"
|
|
"ContextDetailed->ulRootConfigurationPathChars : 0x%lx\n"
|
|
"ContextDetailed->ulAppDirPathType : 0x%lx\n"
|
|
"ContextDetailed->ulAppDirPathChars : 0x%lx\n"
|
|
"ContextDetailed->lpRootManifestPath : %ls\n"
|
|
"ContextDetailed->lpRootConfigurationPath : %ls\n"
|
|
"ContextDetailed->lpAppDirPath : %ls\n"
|
|
,
|
|
BytesWrittenOrRequired,
|
|
ContextDetailed->dwFlags,
|
|
ContextDetailed->ulFormatVersion,
|
|
ContextDetailed->ulAssemblyCount,
|
|
ContextDetailed->ulRootManifestPathType,
|
|
ContextDetailed->ulRootManifestPathChars,
|
|
ContextDetailed->ulRootConfigurationPathType,
|
|
ContextDetailed->ulRootConfigurationPathChars,
|
|
ContextDetailed->ulAppDirPathType,
|
|
ContextDetailed->ulAppDirPathChars,
|
|
ContextDetailed->lpRootManifestPath,
|
|
ContextDetailed->lpRootConfigurationPath,
|
|
ContextDetailed->lpAppDirPath
|
|
);
|
|
}
|
|
{
|
|
ULONG AssemblyIndex = 0;
|
|
ULONG FileInAssemblyIndex = 0;
|
|
|
|
//
|
|
// 0 produces ERROR_INTERNAL_ERROR
|
|
//
|
|
for (AssemblyIndex = 0 ; AssemblyIndex <= ContextDetailed->ulAssemblyCount ; AssemblyIndex += 1)
|
|
{
|
|
if (!QueryActCtxW(Flags, ActCtxHandle, &AssemblyIndex, AssemblyDetailedInformationInActivationContext, AssemblyDetailed, 4096, &BytesWrittenOrRequired))
|
|
{
|
|
Trace(
|
|
"%s(%lu):QueryActCtx(Flags=0x%lx, ActCtxHandle=%p%ls, AssemblyIndex=0x%lx, AssemblyDetailedInformationInActivationContext) LastError=%lu (%ls)\n",
|
|
__FUNCTION__,
|
|
__LINE__ - 1,
|
|
Flags,
|
|
ActCtxHandle,
|
|
static_cast<PCWSTR>(decimalContext),
|
|
AssemblyIndex,
|
|
::FusionpGetLastWin32Error(),
|
|
::FusionpThreadUnsafeGetLastWin32ErrorMessageW()
|
|
);
|
|
}
|
|
else
|
|
{
|
|
Trace(
|
|
"AssemblyIndex : 0x%lx\n"
|
|
"BytesWrittenOrRequired : 0x%lx\n"
|
|
"AssemblyDetailed->ulFlags : 0x%lx\n"
|
|
"AssemblyDetailed->ulEncodedAssemblyIdentityLength : 0x%lx\n"
|
|
"AssemblyDetailed->ulManifestPathType : 0x%lx\n"
|
|
"AssemblyDetailed->ulManifestPathLength : 0x%lx\n"
|
|
"AssemblyDetailed->liManifestLastWriteTime : 0x%I64x\n"
|
|
"AssemblyDetailed->ulPolicyPathType : 0x%lx\n"
|
|
"AssemblyDetailed->ulPolicyPathLength : 0x%lx\n"
|
|
"AssemblyDetailed->liPolicyLastWriteTime : 0x%I64x\n"
|
|
"AssemblyDetailed->ulMetadataSatelliteRosterIndex : 0x%lx\n"
|
|
"AssemblyDetailed->ulManifestVersionMajor : 0x%lx\n"
|
|
"AssemblyDetailed->ulManifestVersionMinor : 0x%lx\n"
|
|
"AssemblyDetailed->ulPolicyVersionMajor : 0x%lx\n"
|
|
"AssemblyDetailed->ulPolicyVersionMinor : 0x%lx\n"
|
|
"AssemblyDetailed->ulAssemblyDirectoryNameLength : 0x%lx\n"
|
|
"AssemblyDetailed->lpAssemblyEncodedAssemblyIdentity : %ls\n"
|
|
"AssemblyDetailed->lpAssemblyManifestPath : %ls\n"
|
|
"AssemblyDetailed->lpAssemblyPolicyPath : %ls\n"
|
|
"AssemblyDetailed->lpAssemblyDirectoryName : %ls\n"
|
|
"AssemblyDetailed->ulFileCount : 0x%lx\n"
|
|
,
|
|
AssemblyIndex,
|
|
BytesWrittenOrRequired,
|
|
AssemblyDetailed->ulFlags,
|
|
AssemblyDetailed->ulEncodedAssemblyIdentityLength,
|
|
AssemblyDetailed->ulManifestPathType,
|
|
AssemblyDetailed->ulManifestPathLength,
|
|
AssemblyDetailed->liManifestLastWriteTime.QuadPart,
|
|
AssemblyDetailed->ulPolicyPathType,
|
|
AssemblyDetailed->ulPolicyPathLength,
|
|
AssemblyDetailed->liPolicyLastWriteTime.QuadPart,
|
|
AssemblyDetailed->ulMetadataSatelliteRosterIndex,
|
|
AssemblyDetailed->ulManifestVersionMajor,
|
|
AssemblyDetailed->ulManifestVersionMinor,
|
|
AssemblyDetailed->ulPolicyVersionMajor,
|
|
AssemblyDetailed->ulPolicyVersionMinor,
|
|
AssemblyDetailed->ulAssemblyDirectoryNameLength,
|
|
AssemblyDetailed->lpAssemblyEncodedAssemblyIdentity,
|
|
AssemblyDetailed->lpAssemblyManifestPath,
|
|
AssemblyDetailed->lpAssemblyPolicyPath,
|
|
AssemblyDetailed->lpAssemblyDirectoryName,
|
|
AssemblyDetailed->ulFileCount
|
|
);
|
|
|
|
QueryIndex.ulAssemblyIndex = AssemblyIndex;
|
|
SetLastError(NO_ERROR);
|
|
if (AssemblyDetailed->ulFileCount == 0)
|
|
{
|
|
Trace("AssemblyDetailed->ulFileCount is 0, working around bug, setting it to 4.\n");
|
|
AssemblyDetailed->ulFileCount = 4; // bug workaround
|
|
}
|
|
for (FileInAssemblyIndex = 0 ; FileInAssemblyIndex != AssemblyDetailed->ulFileCount ; FileInAssemblyIndex += 1)
|
|
{
|
|
QueryIndex.ulFileIndexInAssembly = FileInAssemblyIndex;
|
|
if (!QueryActCtxW(Flags, ActCtxHandle, &QueryIndex, FileInformationInAssemblyOfAssemblyInActivationContext, DllRedir, 4096, &BytesWrittenOrRequired))
|
|
{
|
|
Trace(
|
|
"%s(%lu):QueryActCtx(Flags=0x%lx, ActCtxHandle=%p%ls, QueryIndex={ulAssemblyIndex=0x%lx, ulFileIndexInAssembly=0x%lx}, FileInformationInAssemblyOfAssemblyInActivationContext) LastError=%lu (%ls)\n",
|
|
__FUNCTION__,
|
|
__LINE__,
|
|
Flags,
|
|
ActCtxHandle,
|
|
static_cast<PCWSTR>(decimalContext),
|
|
QueryIndex.ulAssemblyIndex,
|
|
QueryIndex.ulFileIndexInAssembly,
|
|
::FusionpGetLastWin32Error(),
|
|
::FusionpThreadUnsafeGetLastWin32ErrorMessageW()
|
|
);
|
|
//break;
|
|
}
|
|
else
|
|
{
|
|
Trace(
|
|
"AssemblyIndex : 0x%lx\n"
|
|
"FileIndex : 0x%lx\n"
|
|
"BytesWrittenOrRequired : 0x%lx\n"
|
|
"DllRedir[0x%lx,0x%lx]->ulFlags : 0x%lx\n"
|
|
"DllRedir[0x%lx,0x%lx]->ulFilenameLength : 0x%lx\n"
|
|
"DllRedir[0x%lx,0x%lx]->ulPathLength : 0x%lx\n"
|
|
"DllRedir[0x%lx,0x%lx]->lpFileName : %ls\n"
|
|
"DllRedir[0x%lx,0x%lx]->lpFilePath : %ls\n"
|
|
,
|
|
AssemblyIndex,
|
|
FileInAssemblyIndex,
|
|
BytesWrittenOrRequired,
|
|
AssemblyIndex, FileInAssemblyIndex, DllRedir->ulFlags,
|
|
AssemblyIndex, FileInAssemblyIndex, DllRedir->ulFilenameLength,
|
|
AssemblyIndex, FileInAssemblyIndex, DllRedir->ulPathLength,
|
|
AssemblyIndex, FileInAssemblyIndex, DllRedir->lpFileName,
|
|
AssemblyIndex, FileInAssemblyIndex, DllRedir->lpFilePath
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void TestQueryActCtx2()
|
|
{
|
|
{
|
|
CFusionActCtxHandle LogonuiActCtxHandle;
|
|
{
|
|
WCHAR LogonuiManifest[MAX_PATH * 2];
|
|
ACTCTXW LogonuiActCtx = {sizeof(LogonuiActCtx)};
|
|
|
|
LogonuiManifest[0] = 0;
|
|
GetSystemDirectoryW(LogonuiManifest, MAX_PATH);
|
|
wcscat(LogonuiManifest, L"\\logonui.exe.manifest");
|
|
LogonuiActCtx.lpSource = LogonuiManifest;
|
|
LogonuiActCtxHandle.Win32Create(&LogonuiActCtx);
|
|
}
|
|
{
|
|
CFusionActCtxScope LogonuiActCtxScope;
|
|
LogonuiActCtxScope.Win32Activate(LogonuiActCtxHandle);
|
|
|
|
TestQueryActCtx3(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX | QUERY_ACTCTX_FLAG_NO_ADDREF, NULL);
|
|
}
|
|
TestQueryActCtx3(QUERY_ACTCTX_FLAG_NO_ADDREF, LogonuiActCtxHandle);
|
|
}
|
|
TestQueryActCtx3(QUERY_ACTCTX_FLAG_NO_ADDREF, ACTCTX_EMPTY);
|
|
TestQueryActCtx3(QUERY_ACTCTX_FLAG_NO_ADDREF, ACTCTX_SYSTEM_DEFAULT);
|
|
}
|
|
|
|
void TestQueryActCtx()
|
|
{
|
|
WCHAR ExePath[MAX_PATH];
|
|
CStringBuffer DllPath;
|
|
HMODULE hmod = NULL;
|
|
WCHAR buffer[200];
|
|
|
|
if (IamExe)
|
|
{
|
|
if (!Kernel32.GetModuleFileNameW(NULL, ExePath, RTL_NUMBER_OF(ExePath)))
|
|
ThrowLastError();
|
|
if (!DllPath.Win32Format(L"%ls.dll", ExePath))
|
|
ThrowLastError();
|
|
::CopyFileW(ExePath, DllPath, FALSE);
|
|
}
|
|
|
|
if (IamDll)
|
|
{
|
|
hmod = NULL;
|
|
hmod = (HMODULE)RtlPcToFileHeader(InitCommonControls, (PVOID*)&hmod);
|
|
wcscpy(buffer, L"FAILED");
|
|
if (hmod != NULL)
|
|
Kernel32.GetModuleFileNameW(hmod, buffer, RTL_NUMBER_OF(buffer));
|
|
Trace("from dll static dep: %p %ls\n", hmod, buffer);
|
|
|
|
#if defined(ISOLATION_AWARE_ENABLED)
|
|
hmod = IsolationAwareLoadLibraryW(L"comctl32.dll");
|
|
LastError = ::GetLastError();
|
|
wcscpy(buffer, L"FAILED");
|
|
if (hmod != NULL)
|
|
Kernel32.GetModuleFileNameW(hmod, buffer, RTL_NUMBER_OF(buffer));
|
|
Trace("from dll IsolationAwareLoadLibraryW: %p %ls\n", hmod, buffer);
|
|
#endif
|
|
|
|
hmod = LoadLibraryW(L"comctl32.dll");
|
|
LastError = ::GetLastError();
|
|
wcscpy(buffer, L"FAILED");
|
|
if (hmod != NULL)
|
|
Kernel32.GetModuleFileNameW(hmod, buffer, RTL_NUMBER_OF(buffer));
|
|
Trace("from dll LoadLibraryW: %p %ls\n", hmod, buffer);
|
|
|
|
return;
|
|
}
|
|
|
|
{
|
|
hmod = NULL;
|
|
hmod = (HMODULE)RtlPcToFileHeader(InitCommonControls, (PVOID*)&hmod);
|
|
wcscpy(buffer, L"FAILED");
|
|
if (hmod != NULL)
|
|
Kernel32.GetModuleFileNameW(hmod, buffer, RTL_NUMBER_OF(buffer));
|
|
Trace("from exe static dep: %p %ls\n", hmod, buffer);
|
|
|
|
#if defined(ISOLATION_AWARE_ENABLED)
|
|
hmod = IsolationAwareLoadLibraryW(L"comctl32.dll");
|
|
LastError = ::GetLastError();
|
|
wcscpy(buffer, L"FAILED");
|
|
if (hmod != NULL)
|
|
Kernel32.GetModuleFileNameW(hmod, buffer, RTL_NUMBER_OF(buffer));
|
|
Trace("from exe IsolationAwareLoadLibraryW: %p %ls\n", hmod, buffer);
|
|
#endif
|
|
hmod = LoadLibraryW(L"comctl32.dll");
|
|
LastError = ::GetLastError();
|
|
wcscpy(buffer, L"FAILED");
|
|
if (hmod != NULL)
|
|
Kernel32.GetModuleFileNameW(hmod, buffer, RTL_NUMBER_OF(buffer));
|
|
Trace("from exe LoadLibraryW: %p %ls\n", hmod, buffer);
|
|
|
|
}
|
|
|
|
SetDllBitInPeImage(DllPath);
|
|
Trace("Enter LoadLibraryW\n");
|
|
hmod = LoadLibraryW(DllPath);
|
|
LastError = ::GetLastError();
|
|
Trace("Exit LoadLibraryW\n");
|
|
void (*pfn)(void) = reinterpret_cast<void (*)(void)>(GetProcAddress(hmod, "TestQueryActCtx"));
|
|
Trace("Enter non DllMain call to TestQueryActCtx\n");
|
|
pfn();
|
|
Trace("Exit non DllMain call to TestQueryActCtx\n");
|
|
FreeLibrary(hmod);
|
|
DeleteFileW(DllPath);
|
|
}
|
|
|
|
DWORD WINAPI Test64kThreadMain(void* pv)
|
|
{
|
|
LONG_PTR i = 0;
|
|
HANDLE h = 0;
|
|
ULONG_PTR cookie = 0;
|
|
LONG_PTR j = reinterpret_cast<LONG_PTR>(pv);
|
|
|
|
GetCurrentActCtx(&h);
|
|
|
|
ActivateActCtx(h, &cookie);
|
|
printf("%Id ", cookie);
|
|
if (cookie == 0) printf("cookie 0\n");
|
|
ActivateActCtx(h, &cookie);
|
|
printf("%Id ", cookie);
|
|
if (cookie == 0) printf("cookie 0\n");
|
|
|
|
__try
|
|
{
|
|
for (i = 0 ; i < j ; ++i)
|
|
{
|
|
if (!ActivateActCtx(h, &cookie))
|
|
printf("activate error %lu\n", ::GetLastError());
|
|
else
|
|
{
|
|
if (cookie == 0) printf("cookie 0\n");
|
|
//printf("%Id ", cookie);
|
|
if (!DeactivateActCtx(0, cookie))
|
|
printf("deactivate error %lu\n", ::GetLastError());
|
|
}
|
|
}
|
|
}
|
|
__except(printf("exception %lx\n", GetExceptionCode()),EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
printf("final cookie value %Id\n", cookie);
|
|
return 0;
|
|
}
|
|
|
|
void Test64k()
|
|
{
|
|
HANDLE h = 0;
|
|
ULONG_PTR cookie = 0;
|
|
DWORD threadId = 0;
|
|
LONG_PTR i = 0;
|
|
LONG_PTR j = 0;
|
|
HANDLE thread = 0;
|
|
|
|
GetCurrentActCtx(&h);
|
|
|
|
ActivateActCtx(h, &cookie);
|
|
if (cookie == 0) printf("cookie 0\n");
|
|
printf("%Id ", cookie);
|
|
ActivateActCtx(h, &cookie);
|
|
if (cookie == 0) printf("cookie 0\n");
|
|
printf("%Id ", cookie);
|
|
|
|
for (j = 0 ; j < 0xfff0 ; ++j)
|
|
{
|
|
if (!ActivateActCtx(h, &cookie))
|
|
printf("activate error %lu\n", ::GetLastError());
|
|
else
|
|
{
|
|
if (cookie == 0) printf("cookie 0\n");
|
|
if (!DeactivateActCtx(0, cookie))
|
|
printf("deactivate error %lu\n", ::GetLastError());
|
|
}
|
|
}
|
|
for ( ; j < 0xffff + 0xf ; ++j)
|
|
{
|
|
if (!ActivateActCtx(h, &cookie))
|
|
printf("activate error %lu\n", ::GetLastError());
|
|
printf("%Id ", cookie);
|
|
if (cookie == 0) printf("cookie 0\n");
|
|
thread = CreateThread(NULL, 0, Test64kThreadMain, reinterpret_cast<void*>(j), 0, &threadId);
|
|
}
|
|
WaitForSingleObject(thread, INFINITE);
|
|
}
|
|
|
|
void TestDotLocalSingleInstancing()
|
|
{
|
|
FILE* File = 0;
|
|
HMODULE DllHandle = 0;
|
|
|
|
{
|
|
WCHAR DotLocal[MAX_PATH];
|
|
if (!Kernel32.GetModuleFileNameW(GetMyHandle(), DotLocal, NUMBER_OF(DotLocal) - sizeof(".local")))
|
|
ThrowLastError();
|
|
wcscat(DotLocal, L".local");
|
|
File = _wfopen(DotLocal, L"w");
|
|
fprintf(File, "\n");
|
|
fclose(File);
|
|
}
|
|
{
|
|
WCHAR System32Mshtml[MAX_PATH];
|
|
WCHAR LocalMshtml[MAX_PATH];
|
|
WCHAR ResultingMshtml[MAX_PATH];
|
|
|
|
if (!GetSystemDirectoryW(System32Mshtml, NUMBER_OF(System32Mshtml) - sizeof("\\Mshtml.dll")))
|
|
ThrowLastError();
|
|
wcscat(System32Mshtml, L"\\Mshtml.dll");
|
|
|
|
if (!Kernel32.GetModuleFileNameW(GetMyHandle(), LocalMshtml, NUMBER_OF(LocalMshtml) - sizeof("\\Mshtml.dll")))
|
|
ThrowLastError();
|
|
*wcsrchr(LocalMshtml, '\\') = 0;
|
|
wcscat(LocalMshtml, L"\\Mshtml.dll");
|
|
|
|
//DllHandle = LoadLibraryW(L"Mshtml.dll");
|
|
//Trace("LoadLibrary(Mshtml): %p\n", DllHandle);
|
|
|
|
if (!CopyFileW(System32Mshtml, LocalMshtml, FALSE))
|
|
ThrowLastError();
|
|
Trace("copy %ls -> %ls\n", System32Mshtml, LocalMshtml);
|
|
|
|
ULONG i;
|
|
for (i = 0 ; i != 4 ; i += 1)
|
|
{
|
|
DllHandle = LoadLibraryW(System32Mshtml);
|
|
wcscpy(ResultingMshtml, L"FAILED");
|
|
if (DllHandle != NULL)
|
|
Kernel32.GetModuleFileNameW(DllHandle, ResultingMshtml, RTL_NUMBER_OF(ResultingMshtml));
|
|
Trace("LoadLibrary(%ls): %p %ls\n", System32Mshtml, DllHandle, ResultingMshtml);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
TestCreateActCtx(
|
|
int n,
|
|
wchar_t **args
|
|
)
|
|
{
|
|
ACTCTXW acw;
|
|
int i;
|
|
WCHAR rgwchSource[MAX_PATH];
|
|
PCWSTR pszResource;
|
|
HANDLE hActCtx;
|
|
DWORD dwLastError;
|
|
|
|
for (i=0; i<n; i++)
|
|
{
|
|
PCWSTR arg = args[i];
|
|
PCWSTR semi = wcschr(arg, L';');
|
|
|
|
memset(&acw, 0, sizeof(acw));
|
|
|
|
acw.cbSize = sizeof(acw);
|
|
|
|
if (semi == NULL)
|
|
{
|
|
acw.lpSource = arg;
|
|
}
|
|
else
|
|
{
|
|
int cch = (int) (semi - arg);
|
|
|
|
if (cch >= NUMBER_OF(rgwchSource))
|
|
cch = NUMBER_OF(rgwchSource) - 1;
|
|
|
|
memcpy(rgwchSource, arg, cch * sizeof(WCHAR));
|
|
rgwchSource[cch] = L'\0';
|
|
|
|
if (semi[1] == L'#')
|
|
{
|
|
wchar_t *pszDummy;
|
|
pszResource = MAKEINTRESOURCEW(wcstoul(semi+1, &pszDummy, 10));
|
|
}
|
|
else
|
|
{
|
|
pszResource = semi+1;
|
|
}
|
|
|
|
acw.lpSource = rgwchSource;
|
|
acw.lpResourceName = pszResource;
|
|
acw.dwFlags |= ACTCTX_FLAG_RESOURCE_NAME_VALID;
|
|
}
|
|
|
|
hActCtx = ::CreateActCtxW(&acw);
|
|
dwLastError = ::GetLastError();
|
|
printf("CreateActCtxW() on \"%ls\" returned %p\n", arg, hActCtx);
|
|
if (hActCtx == INVALID_HANDLE_VALUE)
|
|
{
|
|
printf(" ::GetLastError() = %lu\n", dwLastError);
|
|
}
|
|
|
|
::ReleaseActCtx(hActCtx);
|
|
}
|
|
}
|
|
|
|
const char comctlv6manifest[]=
|
|
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
|
|
"<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
|
|
"<assemblyIdentity"
|
|
" name=\"Microsoft.Windows.Shell.notepad\""
|
|
" processorArchitecture=\"x86\""
|
|
" version=\"5.1.0.0\""
|
|
" type=\"win32\"/>"
|
|
"<dependency>"
|
|
" <dependentAssembly>"
|
|
" <assemblyIdentity"
|
|
" type=\"win32\""
|
|
" name=\"Microsoft.Windows.Common-Controls\""
|
|
" version=\"6.0.0.0\""
|
|
" processorArchitecture=\"x86\""
|
|
" publicKeyToken=\"6595b64144ccf1df\""
|
|
" language=\"*\""
|
|
" />"
|
|
" </dependentAssembly>"
|
|
"</dependency>"
|
|
"</assembly>"
|
|
;
|
|
|
|
const char comctlv5manifest[]=
|
|
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
|
|
"<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
|
|
"<assemblyIdentity"
|
|
" name=\"Microsoft.Windows.Shell.notepad\""
|
|
" processorArchitecture=\"x86\""
|
|
" version=\"5.1.0.0\""
|
|
" type=\"win32\"/>"
|
|
"</assembly>"
|
|
;
|
|
|
|
void TestCreateActctxAdminOverride()
|
|
{
|
|
WCHAR exe[MAX_PATH];
|
|
WCHAR dll[MAX_PATH];
|
|
WCHAR comctl[MAX_PATH];
|
|
WCHAR manifest[MAX_PATH];
|
|
ACTCTXW Actctx = {sizeof(Actctx)};
|
|
FILE* File = NULL;
|
|
ULONG_PTR ulCookie = 0;
|
|
HMODULE DllHandle = 0;
|
|
HANDLE ActctxHandle;
|
|
GUID Guid = { 0 };
|
|
|
|
wcscpy(exe, GetMyModuleFullPath());
|
|
wcscpy(dll, GetMyModuleFullPath());
|
|
wcscat(dll, L".dll");
|
|
CopyFileW(exe, dll, FALSE);
|
|
SetDllBitInPeImage(dll);
|
|
|
|
#if 0
|
|
wcscpy(String, GetMyModuleFullPath());
|
|
wcscat(String, L".Manifest");
|
|
DeleteFileW(String);
|
|
Trace("DeleteFile(%ls)\n", String);
|
|
|
|
wcscpy(String, GetMyModuleFullPath());
|
|
wcscat(String, L".2.Manifest");
|
|
DeleteFileW(String);
|
|
Trace("DeleteFile(%ls)\n", String);
|
|
|
|
wcscpy(String, GetMyModuleFullPath());
|
|
wcscat(String, L".3.Manifest");
|
|
DeleteFileW(String);
|
|
Trace("DeleteFile(%ls)\n", String);
|
|
#endif
|
|
|
|
Actctx.lpSource = dll;
|
|
/*
|
|
ActctxHandle = CreateActCtxW(&Actctx);
|
|
if (ActctxHandle == INVALID_HANDLE_VALUE)
|
|
return;
|
|
Trace("CreateActCtxW succeeded\n");
|
|
*/
|
|
|
|
//
|
|
// manfile is number to put in the manifest file name, 0 for none
|
|
// good is what the contents of the file are, 0=>bad, 1=>v5, 2=>v6
|
|
// res is what resource id to ask for
|
|
//
|
|
for (int manfile = 0 ; manfile != 4 ; manfile += 1)
|
|
{
|
|
WCHAR Number[RTL_BITS_OF(ULONG_PTR) + 3];
|
|
for (int good = 0 ; good != 3 ; good += 1)
|
|
{
|
|
for (int res = -1 ; res != 4 ; res += 1)
|
|
{
|
|
Trace("---------------------------------------------------------------\n");
|
|
Trace("resourceid is %d%s\n", res, (res != -1) ? "" : " (flag not set)");
|
|
if (res != -1)
|
|
{
|
|
Actctx.lpResourceName = MAKEINTRESOURCEW(res);
|
|
Actctx.dwFlags |= ACTCTX_FLAG_RESOURCE_NAME_VALID;
|
|
Actctx.lpResourceName = MAKEINTRESOURCEW(res);
|
|
}
|
|
else
|
|
{
|
|
Actctx.dwFlags &= ~ACTCTX_FLAG_RESOURCE_NAME_VALID;
|
|
}
|
|
for (int delman = 0 ; delman != 4 ; delman += 1)
|
|
{
|
|
Number[0] = 0;
|
|
if (delman)
|
|
swprintf(Number, L".%d", delman);
|
|
swprintf(manifest, L"%ls%ls%ls%ls", GetMyModuleFullPathWithoutExtension(), L".dll", Number, L".Manifest");
|
|
/*
|
|
CoCreateGuid(&Guid);
|
|
swprintf(String3, L"%ls%I64x%I64x", GetMyModuleFullPath(), *reinterpret_cast<__int64*>(&Guid), *(1+reinterpret_cast<__int64*>(&Guid)));
|
|
if (!MoveFileW(String, String3) && ::GetLastError() != ERROR_FILE_NOT_FOUND)
|
|
Trace("MoveFile(%ls -> %ls) FAILED %d\n", String, String3, ::GetLastError());
|
|
else
|
|
;//Trace("MoveFile(%ls -> %ls)\n", String, String3);
|
|
*/
|
|
if (!DeleteFileW(manifest) && ::GetLastError() != ERROR_FILE_NOT_FOUND)
|
|
Trace("DeleteFile(%ls) FAILED %d\n", manifest, ::GetLastError());
|
|
else
|
|
;//Trace("DeleteFile(%ls)\n", String3);
|
|
}
|
|
Number[0] = 0;
|
|
if (manfile != 0)
|
|
{
|
|
swprintf(Number, L".%d", manfile);
|
|
}
|
|
swprintf(manifest, L"%ls%ls%ls%ls", GetMyModuleFullPathWithoutExtension(), L".dll", Number, L".Manifest");
|
|
//Trace("fopen(%ls)\n", String);
|
|
File = _wfopen(manifest, L"w+");
|
|
if (File == NULL)
|
|
{
|
|
perror("fopen");
|
|
}
|
|
switch (good)
|
|
{
|
|
case 0:
|
|
fprintf(File, "bad");
|
|
Trace("%ls is bad\n", manifest);
|
|
break;
|
|
case 1:
|
|
fprintf(File, "%s", comctlv5manifest);
|
|
Trace("%ls is comctlv5manifest\n", manifest);
|
|
break;
|
|
case 2:
|
|
fprintf(File, "%s", comctlv6manifest);
|
|
Trace("%ls is comctlv6manifest\n", manifest);
|
|
break;
|
|
}
|
|
fclose(File);
|
|
|
|
ActctxHandle = CreateActCtxW(&Actctx);
|
|
if (ActctxHandle == INVALID_HANDLE_VALUE)
|
|
{
|
|
Trace("CreateActCtxW failed %d\n", ::GetLastError());
|
|
ulCookie = 0;
|
|
}
|
|
else
|
|
{
|
|
Trace("CreateActCtxW succeeded %p\n", ActctxHandle);
|
|
ActivateActCtx(ActctxHandle, &ulCookie);
|
|
}
|
|
__try
|
|
{
|
|
PWSTR filePart;
|
|
comctl[0] = 0;
|
|
SearchPathW(NULL, L"comctl32.dll", NULL, RTL_NUMBER_OF(comctl), comctl, &filePart);
|
|
}
|
|
__finally
|
|
{
|
|
if (ActctxHandle != INVALID_HANDLE_VALUE)
|
|
DeactivateActCtx(0, ulCookie);
|
|
}
|
|
Trace("SearchPathW(comctl32.dll): %ls\n", comctl);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void TestCreateActctxLikeCreateProcess()
|
|
{
|
|
#if defined(ACTCTX_FLAG_LIKE_CREATEPROCESS)
|
|
WCHAR comctl[MAX_PATH];
|
|
WCHAR manifest[MAX_PATH];
|
|
ACTCTXW Actctx = {sizeof(Actctx)};
|
|
FILE* File = NULL;
|
|
ULONG_PTR ulCookie = 0;
|
|
HMODULE DllHandle = 0;
|
|
HANDLE ActctxHandle;
|
|
PWSTR filePart;
|
|
|
|
Actctx.lpSource = GetMyModuleFullPath();
|
|
Actctx.dwFlags = ACTCTX_FLAG_LIKE_CREATEPROCESS;
|
|
|
|
wcscpy(manifest, GetMyModuleFullPath());
|
|
wcscat(manifest, L".Manifest");
|
|
DeleteFileW(manifest);
|
|
//Trace("DeleteFile(%ls)\n", manifest);
|
|
|
|
ActctxHandle = CreateActCtxW(&Actctx);
|
|
if (ActctxHandle == INVALID_HANDLE_VALUE)
|
|
{
|
|
Trace("CreateActCtxW failed %d\n", ::GetLastError());
|
|
ulCookie = 0;
|
|
}
|
|
else
|
|
{
|
|
Trace("CreateActCtxW succeeded %p\n", ActctxHandle);
|
|
ActivateActCtx(ActctxHandle, &ulCookie);
|
|
}
|
|
__try
|
|
{
|
|
comctl[0] = 0;
|
|
SearchPathW(NULL, L"comctl32.dll", NULL, RTL_NUMBER_OF(comctl), comctl, &filePart);
|
|
}
|
|
__finally
|
|
{
|
|
if (ActctxHandle != INVALID_HANDLE_VALUE)
|
|
DeactivateActCtx(0, ulCookie);
|
|
}
|
|
Trace("SearchPathW(comctl32.dll): %ls\n", comctl);
|
|
|
|
File = _wfopen(manifest, L"w");
|
|
fprintf(File, "%s", comctlv5manifest);
|
|
fclose(File);
|
|
Trace("%ls == comctlv5manifest\n", manifest);
|
|
|
|
ActctxHandle = CreateActCtxW(&Actctx);
|
|
if (ActctxHandle == INVALID_HANDLE_VALUE)
|
|
{
|
|
Trace("CreateActCtxW failed %d\n", ::GetLastError());
|
|
ulCookie = 0;
|
|
}
|
|
else
|
|
{
|
|
Trace("CreateActCtxW succeeded %p\n", ActctxHandle);
|
|
ActivateActCtx(ActctxHandle, &ulCookie);
|
|
}
|
|
__try
|
|
{
|
|
comctl[0] = 0;
|
|
SearchPathW(NULL, L"comctl32.dll", NULL, RTL_NUMBER_OF(comctl), comctl, &filePart);
|
|
}
|
|
__finally
|
|
{
|
|
if (ActctxHandle != INVALID_HANDLE_VALUE)
|
|
DeactivateActCtx(0, ulCookie);
|
|
}
|
|
Trace("SearchPathW(comctl32.dll): %ls\n", comctl);
|
|
|
|
File = _wfopen(manifest, L"w");
|
|
fprintf(File, "%ls", comctlv6manifest);
|
|
fclose(File);
|
|
Trace("%ls == comctlv6manifest\n", manifest);
|
|
|
|
ActctxHandle = CreateActCtxW(&Actctx);
|
|
if (ActctxHandle == INVALID_HANDLE_VALUE)
|
|
{
|
|
Trace("CreateActCtxW failed %d\n", ::GetLastError());
|
|
ulCookie = 0;
|
|
}
|
|
else
|
|
{
|
|
Trace("CreateActCtxW succeeded %p\n", ActctxHandle);
|
|
ActivateActCtx(ActctxHandle, &ulCookie);
|
|
}
|
|
__try
|
|
{
|
|
comctl[0] = 0;
|
|
SearchPathW(NULL, L"comctl32.dll", NULL, RTL_NUMBER_OF(comctl), comctl, &filePart);
|
|
}
|
|
__finally
|
|
{
|
|
if (ActctxHandle != INVALID_HANDLE_VALUE)
|
|
DeactivateActCtx(0, ulCookie);
|
|
}
|
|
Trace("SearchPathW(comctl32.dll): %ls\n", comctl);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
TestQueryManifestInformationBasic(
|
|
PCWSTR pszManifest
|
|
)
|
|
{
|
|
PSXS_QUERY_MANIFEST_INFORMATION pfn = NULL;
|
|
LoadSxs();
|
|
struct {
|
|
SXS_MANIFEST_INFORMATION_BASIC mib;
|
|
WCHAR rgwchSpaceForIdentity[1024];
|
|
WCHAR rgwchSpaceForDirName[1024];
|
|
} buff;
|
|
|
|
GetSxsProc("SxsQueryManifestInformation", &pfn);
|
|
|
|
if (!(*pfn)(0, pszManifest, SXS_QUERY_MANIFEST_INFORMATION_INFOCLASS_BASIC, 0, sizeof(buff), &buff, NULL)) {
|
|
fprintf(stderr, "%s failed!\n", __FUNCTION__);
|
|
}
|
|
}
|
|
|
|
void TestImage()
|
|
{
|
|
PIMAGE_RESOURCE_DIRECTORY ImageResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY)4;
|
|
PIMAGE_RESOURCE_DIRECTORY_ENTRY ImageResourceDirectoryEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)4;;
|
|
|
|
printf("ImageResourceDirectory %p\n", ImageResourceDirectory);
|
|
printf("ImageResourceDirectory + 1 %p\n", ImageResourceDirectory + 1);
|
|
|
|
printf("ImageResourceDirectoryEntry %p\n", ImageResourceDirectoryEntry);
|
|
printf("ImageResourceDirectoryEntry + 1 %p\n", ImageResourceDirectoryEntry + 1);
|
|
}
|
|
|
|
class CSxsTestCleanup : public CCleanupBase
|
|
{
|
|
public:
|
|
VOID DeleteYourself() { }
|
|
~CSxsTestCleanup() { }
|
|
};
|
|
|
|
#define private public
|
|
#include "sxsprotect.h"
|
|
#undef private
|
|
|
|
void TestInterlockedAlignment()
|
|
{
|
|
__declspec(align(16)) SLIST_HEADER SlistHeader;
|
|
|
|
RtlInitializeSListHead(&SlistHeader);
|
|
|
|
CSxsTestCleanup* pc = new CSxsTestCleanup();
|
|
printf("%p\n", pc);
|
|
printf("%p\n", static_cast<SINGLE_LIST_ENTRY*>(pc));
|
|
SxspAtExit(pc);
|
|
|
|
CProtectionRequestRecord* pr = new CProtectionRequestRecord;
|
|
printf("%p\n", pr);
|
|
printf("%p\n", &pr->m_ListHeader);
|
|
|
|
CStringListEntry* psle = new CStringListEntry;
|
|
printf("%p\n", psle);
|
|
printf("%p\n", static_cast<SINGLE_LIST_ENTRY*>(psle));
|
|
|
|
RtlInterlockedPushEntrySList(&SlistHeader, pc);
|
|
RtlInterlockedPushEntrySList(&SlistHeader, psle);
|
|
RtlQueryDepthSList(&SlistHeader);
|
|
RtlInterlockedPopEntrySList(&SlistHeader);
|
|
RtlInterlockedFlushSList(&SlistHeader);
|
|
// untested: RtlInterlockedPushListSList
|
|
|
|
RtlInterlockedPushEntrySList(&pr->m_ListHeader, pc);
|
|
RtlInterlockedPushEntrySList(&pr->m_ListHeader, psle);
|
|
RtlQueryDepthSList(&pr->m_ListHeader);
|
|
RtlInterlockedPopEntrySList(&pr->m_ListHeader);
|
|
RtlInterlockedFlushSList(&pr->m_ListHeader);
|
|
// untested: RtlInterlockedPushListSList
|
|
|
|
printf("success\n");
|
|
}
|
|
|
|
void TestCreateActctxWindowsShellManifest()
|
|
{
|
|
WCHAR WindowsShellManifestFileName[MAX_PATH];
|
|
ACTCTXW ActCtx = { sizeof(ActCtx) };
|
|
HANDLE ActCtxHandle = 0;
|
|
WindowsShellManifestFileName[0] = 0;
|
|
|
|
GetWindowsDirectoryW(WindowsShellManifestFileName, NUMBER_OF(WindowsShellManifestFileName) - 64);
|
|
wcscat(WindowsShellManifestFileName, L"\\WindowsShell.Manifest");
|
|
ActCtx.lpSource = WindowsShellManifestFileName;
|
|
|
|
ActCtxHandle = CreateActCtxW(&ActCtx);
|
|
Trace("TestCreateActctxWindowsShellManifest: %p, %lu\n", ActCtxHandle, ::GetLastError());
|
|
ReleaseActCtx(ActCtxHandle);
|
|
}
|
|
|
|
class CObjectTypes
|
|
{
|
|
protected:
|
|
std::vector<BYTE> m_ByteBuffer;
|
|
PSYSTEM_OBJECTTYPE_INFORMATION m_TypedBuffer;
|
|
public:
|
|
};
|
|
|
|
void TestCreateGlobalEvent()
|
|
{
|
|
if (!::CreateEventW(NULL, FALSE, FALSE, L"MGRIER"))
|
|
return;
|
|
Sleep(500000);
|
|
}
|
|
|
|
class CObjectSnapshot
|
|
{
|
|
protected:
|
|
//
|
|
// This interface is not very good, but it's easy..the entries
|
|
// are of variable size...
|
|
//
|
|
std::vector<BYTE> m_ByteBuffer;
|
|
SIZE_T m_Size;
|
|
|
|
//
|
|
// Some operations, like sorting, require us to move all the string data
|
|
// out of the elements. We do not manage this data in a lossless way.
|
|
//
|
|
// Ultimately, you may benefit from copying/transforming the data completely.
|
|
//
|
|
std::vector<BYTE> m_StringData;
|
|
public:
|
|
|
|
SIZE_T size() const { return m_Size; }
|
|
|
|
class iterator;
|
|
|
|
class const_iterator
|
|
{
|
|
protected:
|
|
const SYSTEM_OBJECT_INFORMATION* m_p;
|
|
public:
|
|
~const_iterator() { }
|
|
|
|
void operator=(const const_iterator& x) { m_p = x.m_p; }
|
|
const_iterator(const const_iterator& x) : m_p(x.m_p) { }
|
|
const_iterator(const BYTE* p = NULL) : m_p(reinterpret_cast<const SYSTEM_OBJECT_INFORMATION*>(p)) { }
|
|
|
|
//void operator=(const iterator& x);
|
|
//const_iterator(const iterator& x);
|
|
|
|
bool operator==(const const_iterator& i) const
|
|
{
|
|
return (m_p == i.m_p);
|
|
}
|
|
|
|
bool operator!=(const const_iterator& i) const
|
|
{
|
|
return (m_p != i.m_p);
|
|
}
|
|
|
|
const SYSTEM_OBJECT_INFORMATION& operator*() const { return *m_p; }
|
|
|
|
void operator++()
|
|
{
|
|
if (m_p != NULL)
|
|
{
|
|
if (m_p->NextEntryOffset != 0)
|
|
m_p = reinterpret_cast<const SYSTEM_OBJECT_INFORMATION*>(reinterpret_cast<const BYTE*>(m_p) + m_p->NextEntryOffset);
|
|
else
|
|
m_p = NULL; // end
|
|
}
|
|
}
|
|
|
|
const_iterator operator++(int)
|
|
{
|
|
const_iterator tmp = *this;
|
|
++*this;;
|
|
return tmp;
|
|
}
|
|
};
|
|
|
|
class iterator : public const_iterator
|
|
{
|
|
private:
|
|
void operator=(const const_iterator&);
|
|
public:
|
|
~iterator() { }
|
|
iterator(BYTE* p = NULL) : const_iterator(p) { }
|
|
|
|
SYSTEM_OBJECT_INFORMATION& operator*() { return const_cast<SYSTEM_OBJECT_INFORMATION&>(*m_p); }
|
|
};
|
|
|
|
const_iterator begin() const { return const_iterator(&m_ByteBuffer[0]); }
|
|
iterator begin() { return iterator(&m_ByteBuffer[0]); }
|
|
const_iterator end() const { return const_iterator(); }
|
|
iterator end() { return iterator(); }
|
|
|
|
void swap(CObjectSnapshot& x)
|
|
{
|
|
std::swap(m_ByteBuffer, x.m_ByteBuffer);
|
|
std::swap(m_Size, x.m_Size);
|
|
}
|
|
|
|
CObjectSnapshot() { }
|
|
~CObjectSnapshot() { }
|
|
};
|
|
|
|
class CHandleSnapshot
|
|
{
|
|
protected:
|
|
std::vector<BYTE> m_ByteBuffer;
|
|
PSYSTEM_HANDLE_INFORMATION_EX m_TypedBuffer;
|
|
public:
|
|
|
|
SIZE_T size() const { return m_TypedBuffer->NumberOfHandles; }
|
|
|
|
SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX* begin() { return &m_TypedBuffer->Handles[0]; }
|
|
const SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX* begin() const { return &m_TypedBuffer->Handles[0]; }
|
|
|
|
SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX* end() { return begin() + size(); }
|
|
const SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX* end() const { return begin() + size(); }
|
|
|
|
SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX& operator[](size_t index) { return *(begin() + index); }
|
|
const SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX& operator[](size_t index) const { return *(begin() + index); }
|
|
|
|
void reserve(SIZE_T n)
|
|
{
|
|
resize(n); // since there's no constructor..
|
|
}
|
|
|
|
void resize(SIZE_T n)
|
|
{
|
|
m_ByteBuffer.resize(sizeof(SYSTEM_HANDLE_INFORMATION_EX) + (n - 1) * sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX));
|
|
Resync();
|
|
m_TypedBuffer->NumberOfHandles = n;
|
|
}
|
|
|
|
void swap(CHandleSnapshot& x)
|
|
{
|
|
std::swap(m_ByteBuffer, x.m_ByteBuffer);
|
|
x.Resync();
|
|
Resync();
|
|
}
|
|
|
|
CHandleSnapshot() : m_TypedBuffer(NULL) { }
|
|
~CHandleSnapshot() { }
|
|
|
|
void GetHandlesForCurrentProcess()
|
|
{
|
|
GetHandlesForProcess(GetCurrentProcessId());
|
|
}
|
|
|
|
void GetHandlesForProcess(ULONG_PTR pid)
|
|
{
|
|
GetHandlesForSystem();
|
|
FilterByProcessId(pid);
|
|
}
|
|
|
|
void GetHandlesForSystem()
|
|
{
|
|
//
|
|
// the actual needed size can be very large, over 256k
|
|
//
|
|
ULONG Size = 0;
|
|
|
|
m_TypedBuffer = NULL;
|
|
m_ByteBuffer.resize(sizeof(SYSTEM_HANDLE_INFORMATION_EX));
|
|
NTSTATUS Status = NtQuerySystemInformation(SystemExtendedHandleInformation, &m_ByteBuffer[0], static_cast<ULONG>(m_ByteBuffer.size()), &Size);
|
|
while (Status == STATUS_INFO_LENGTH_MISMATCH && Size != 0)
|
|
{
|
|
//
|
|
// since it is transient, let's be safe and double it
|
|
//
|
|
m_ByteBuffer.resize(Size * 2);
|
|
Status = NtQuerySystemInformation(SystemExtendedHandleInformation, &m_ByteBuffer[0], static_cast<ULONG>(m_ByteBuffer.size()), &Size);
|
|
}
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
Trace("NtQuerySystemInformation failed 0x%lx\n", Status);
|
|
return;
|
|
}
|
|
m_ByteBuffer.resize(Size);
|
|
m_TypedBuffer = reinterpret_cast<PSYSTEM_HANDLE_INFORMATION_EX>(&m_ByteBuffer[0]);
|
|
Trace("%Id total handles system-wide\n", m_TypedBuffer->NumberOfHandles);
|
|
}
|
|
|
|
void FilterByProcessId(ULONG_PTR pid)
|
|
{
|
|
SIZE_T Scan = 0;
|
|
SIZE_T Keep = 0;
|
|
|
|
for (Scan = 0 ; Scan != m_TypedBuffer->NumberOfHandles ; Scan += 1)
|
|
{
|
|
if (m_TypedBuffer->Handles[Scan].UniqueProcessId == pid)
|
|
{
|
|
if (Keep != Scan)
|
|
m_TypedBuffer->Handles[Keep] = m_TypedBuffer->Handles[Scan]; // struct copy
|
|
Keep += 1;
|
|
}
|
|
}
|
|
m_TypedBuffer->NumberOfHandles = Keep;
|
|
}
|
|
|
|
void Resync()
|
|
{
|
|
m_TypedBuffer = reinterpret_cast<PSYSTEM_HANDLE_INFORMATION_EX>(&m_ByteBuffer[0]);
|
|
}
|
|
|
|
CHandleSnapshot(const CHandleSnapshot& x) : m_TypedBuffer(NULL)
|
|
{
|
|
this->m_ByteBuffer = x.m_ByteBuffer;
|
|
Resync();
|
|
}
|
|
|
|
void operator=(const CHandleSnapshot& x)
|
|
{
|
|
this->m_ByteBuffer = x.m_ByteBuffer;
|
|
Resync();
|
|
}
|
|
|
|
class CHandleValueOperatorLessThan
|
|
{
|
|
public:
|
|
bool operator()(const SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX& x, const SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX& y)
|
|
{
|
|
return (x.HandleValue < y.HandleValue);
|
|
}
|
|
};
|
|
|
|
void SortByHandleValue()
|
|
{
|
|
std::sort(begin(), end(), CHandleValueOperatorLessThan());
|
|
}
|
|
|
|
void operator-=(/*const*/CHandleSnapshot& x)
|
|
{
|
|
SortByHandleValue();
|
|
x.SortByHandleValue();
|
|
CHandleSnapshot temp(*this);
|
|
resize(
|
|
std::set_difference(temp.begin(), temp.end(), x.begin(), x.end(), begin(), CHandleValueOperatorLessThan())
|
|
- begin());
|
|
}
|
|
|
|
void Dump()
|
|
{
|
|
}
|
|
};
|
|
|
|
class CHandleSnapshots
|
|
{
|
|
public:
|
|
void Begin() { m_Begin.GetHandlesForCurrentProcess(); }
|
|
void End() { m_End.GetHandlesForCurrentProcess(); m_Diff = m_Begin; m_Diff -= m_End; }
|
|
|
|
CHandleSnapshot m_Begin;
|
|
CHandleSnapshot m_End;
|
|
CHandleSnapshot m_Diff;
|
|
};
|
|
|
|
void Pause()
|
|
{
|
|
Trace("Press a key to continue\n");
|
|
getchar();
|
|
}
|
|
|
|
void TestHandleLeaks()
|
|
{
|
|
WCHAR WindowsDirectory[MAX_PATH];
|
|
ULONG i = 0;
|
|
CFusionFile DevNull;
|
|
//SECURITY_ATTRIBUTES SecurityAttributes = { sizeof(SecurityAttributes), NULL, TRUE};
|
|
|
|
WindowsDirectory[0] = 0;
|
|
|
|
DevNull = CreateFileW(L"nul:", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
NULL/*&SecurityAttributes*/, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (DevNull == INVALID_HANDLE_VALUE)
|
|
Trace("Open(nul:) failed %ld\n", ::GetLastError());
|
|
|
|
GetWindowsDirectoryW(WindowsDirectory, NUMBER_OF(WindowsDirectory) - 64);
|
|
|
|
{
|
|
const WCHAR SubFunction[] = L"CreateActCtx";
|
|
|
|
CHandleSnapshots handleSnapshots;
|
|
handleSnapshots.Begin();
|
|
Trace("%s Begin %ls : %Id handles\n", __FUNCTION__, SubFunction, handleSnapshots.m_Begin.size());
|
|
{
|
|
WCHAR WindowsShellManifestFileName[MAX_PATH];
|
|
ACTCTXW ActCtx = { sizeof(ActCtx) };
|
|
HANDLE ActCtxHandle = 0;
|
|
|
|
WindowsShellManifestFileName[0] = 0;
|
|
wcscpy(WindowsShellManifestFileName, WindowsDirectory);
|
|
wcscat(WindowsShellManifestFileName, L"\\WindowsShell.Manifest");
|
|
ActCtx.lpSource = WindowsShellManifestFileName;
|
|
|
|
for (i = 0 ; i != 100 ; ++i)
|
|
{
|
|
HANDLE ActCtxHandle = CreateActCtxW(&ActCtx);
|
|
if (ActCtxHandle == INVALID_HANDLE_VALUE)
|
|
Trace("TestCreateActctxWindowsShellManifest: %p, %lu\n", ActCtxHandle, ::GetLastError());
|
|
else
|
|
ReleaseActCtx(ActCtxHandle);
|
|
}
|
|
}
|
|
handleSnapshots.End();
|
|
Trace("%s End %ls : %Id handles\n", __FUNCTION__, SubFunction, handleSnapshots.m_End.size());
|
|
|
|
if (handleSnapshots.m_Diff.size() != 0)
|
|
{
|
|
Trace("%s Diff %ls : %Id handles\n", __FUNCTION__, SubFunction, handleSnapshots.m_Diff.size());
|
|
}
|
|
}
|
|
|
|
Pause();
|
|
{
|
|
const WCHAR SubFunction[] = L"CreateActCtx + LoadLibrary(comctl32)";
|
|
|
|
CHandleSnapshots handleSnapshots;
|
|
handleSnapshots.Begin();
|
|
Trace("%s Begin %ls : %Id handles\n", __FUNCTION__, SubFunction, handleSnapshots.m_Begin.size());
|
|
{
|
|
WCHAR WindowsShellManifestFileName[MAX_PATH];
|
|
ACTCTXW ActCtx = { sizeof(ActCtx) };
|
|
HANDLE ActCtxHandle = 0;
|
|
|
|
WindowsShellManifestFileName[0] = 0;
|
|
wcscpy(WindowsShellManifestFileName, WindowsDirectory);
|
|
wcscat(WindowsShellManifestFileName, L"\\WindowsShell.Manifest");
|
|
ActCtx.lpSource = WindowsShellManifestFileName;
|
|
|
|
for (i = 0 ; i != 100 ; ++i)
|
|
{
|
|
ULONG_PTR ulCookie = 0;
|
|
|
|
HANDLE ActCtxHandle = CreateActCtxW(&ActCtx);
|
|
if (ActCtxHandle == INVALID_HANDLE_VALUE)
|
|
Trace("TestCreateActctxWindowsShellManifest: %p, %lu\n", ActCtxHandle, ::GetLastError());
|
|
else
|
|
{
|
|
ActivateActCtx(ActCtxHandle, &ulCookie);
|
|
HMODULE Comctl = LoadLibraryW(L"comctl32.dll");
|
|
if (i == 1)
|
|
{
|
|
CHandleSnapshot handleSnapshot;
|
|
handleSnapshot.GetHandlesForCurrentProcess();
|
|
Trace("Comctl32.dll loaded first time %Id\n", handleSnapshot.size());
|
|
Pause();
|
|
}
|
|
FreeLibrary(Comctl);
|
|
if (i == 1)
|
|
{
|
|
CHandleSnapshot handleSnapshot;
|
|
handleSnapshot.GetHandlesForCurrentProcess();
|
|
Trace("Comctl32.dll unloaded first time %Id\n", handleSnapshot.size());
|
|
Pause();
|
|
}
|
|
if (ulCookie != 0)
|
|
DeactivateActCtx(0, ulCookie);
|
|
ReleaseActCtx(ActCtxHandle);
|
|
if (i == 1)
|
|
{
|
|
CHandleSnapshot handleSnapshot;
|
|
handleSnapshot.GetHandlesForCurrentProcess();
|
|
Trace("Comctl32.dll unloaded + ReleaseActCtxfirst time %Id\n", handleSnapshot.size());
|
|
Pause();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
handleSnapshots.End();
|
|
Trace("%s End %ls : %Id handles\n", __FUNCTION__, SubFunction, handleSnapshots.m_End.size());
|
|
|
|
if (handleSnapshots.m_Diff.size() != 0)
|
|
{
|
|
Trace("%s Diff %ls : %Id handles\n", __FUNCTION__, SubFunction, handleSnapshots.m_Diff.size());
|
|
}
|
|
}
|
|
|
|
Pause();
|
|
{
|
|
WCHAR Me[MAX_PATH];
|
|
STARTUPINFOW StartupInfo = {sizeof(StartupInfo)};
|
|
PROCESS_INFORMATION ProcessInfo = {0};
|
|
static const WCHAR SubFunction[] = L"CreateProcess";
|
|
|
|
Kernel32.GetModuleFileNameW(NULL, Me, NUMBER_OF(Me));
|
|
|
|
CHandleSnapshots handleSnapshots;
|
|
handleSnapshots.Begin();
|
|
Trace("%s Begin %ls : %Id handles\n", __FUNCTION__, SubFunction, handleSnapshots.m_Begin.size());
|
|
|
|
for (i = 0 ; i != 100 ; ++i)
|
|
{
|
|
StartupInfo.hStdOutput = DevNull;
|
|
StartupInfo.hStdError = DevNull;
|
|
StartupInfo.dwFlags = STARTF_USESTDHANDLES;
|
|
|
|
if (!CreateProcessW(Me, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &StartupInfo, &ProcessInfo))
|
|
{
|
|
Trace("CreateProcess failed %ld\n", ::GetLastError());
|
|
}
|
|
else
|
|
{
|
|
WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
|
|
WaitForSingleObject(ProcessInfo.hThread, INFINITE);
|
|
if (!CloseHandle(ProcessInfo.hProcess))
|
|
Trace("CloseHandle(Process %p) failed %ld\n", ProcessInfo.hProcess, ::GetLastError());
|
|
if (!CloseHandle(ProcessInfo.hThread))
|
|
Trace("CloseHandle(Thread %p) failed %ld\n", ProcessInfo.hThread, ::GetLastError());
|
|
}
|
|
}
|
|
handleSnapshots.End();
|
|
Trace("%s End %ls : %Id handles\n", __FUNCTION__, SubFunction, handleSnapshots.m_End.size());
|
|
|
|
if (handleSnapshots.m_Diff.size() != 0)
|
|
{
|
|
Trace("%s Diff %ls : %Id handles\n", __FUNCTION__, SubFunction, handleSnapshots.m_Diff.size());
|
|
}
|
|
}
|
|
Pause();
|
|
{
|
|
WCHAR SubFunction[sizeof("LoadLibrary xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")];
|
|
WCHAR DllPath[MAX_PATH];
|
|
ULONG j = 0;
|
|
|
|
const static PCWSTR Leaves[] = {
|
|
L"mshtml.dll",
|
|
L"wintrust.dll",
|
|
L"shell32.dll",
|
|
L"crypt32.dll",
|
|
L"msxml.dll",
|
|
L"shdocvw.dll",
|
|
L"msxml2.dll",
|
|
L"msxml3.dll"
|
|
};
|
|
|
|
for (j = 0 ; j != NUMBER_OF(Leaves) ; ++j)
|
|
{
|
|
SubFunction[0] = 0;
|
|
wcscat(SubFunction, L"LoadLibrary ");
|
|
wcscat(SubFunction, Leaves[j]);
|
|
|
|
DllPath[0] = 0;
|
|
wcscat(DllPath, WindowsDirectory);
|
|
wcscat(DllPath, L"\\system32\\");
|
|
wcscat(DllPath, Leaves[j]);
|
|
|
|
CHandleSnapshots handleSnapshots;
|
|
handleSnapshots.Begin();
|
|
Trace("%s Begin %ls : %Id handles\n", __FUNCTION__, SubFunction, handleSnapshots.m_Begin.size());
|
|
for (i = 0 ; i != 20 ; ++i)
|
|
{
|
|
HMODULE DllHandle;
|
|
|
|
if ((DllHandle = LoadLibraryW(DllPath)) != NULL)
|
|
FreeLibrary(DllHandle);
|
|
else
|
|
Trace("LoadLibraryW(%ls) failed %ld\n", DllPath, ::GetLastError());
|
|
}
|
|
handleSnapshots.End();
|
|
Trace("%s End %ls : %Id handles\n", __FUNCTION__, SubFunction, handleSnapshots.m_End.size());
|
|
if (handleSnapshots.m_Diff.size() != 0)
|
|
{
|
|
Trace("%s Diff %s : %Id handles\n", __FUNCTION__, SubFunction, handleSnapshots.m_Diff.size());
|
|
}
|
|
}
|
|
}
|
|
Pause();
|
|
}
|
|
|
|
#define YET_ANOTHER_PASTE(x,y) x##y
|
|
#define YET_YET_ANOTHER_PASTE(x,y) YET_ANOTHER_PASTE(x,y)
|
|
#define LSXS_PROCESSOR_ARCHITECTURE YET_YET_ANOTHER_PASTE(L, SXS_PROCESSOR_ARCHITECTURE)
|
|
|
|
const WCHAR ToolsCrtManifest[]=
|
|
L"<?xml version=\"1.0\" standalone=\"yes\"?>"
|
|
L"<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
|
|
L"<assemblyIdentity"
|
|
L" name=\"Microsoft.Windows.SxsTest.ToolsCrtClient\""
|
|
L" processorArchitecture=\"" LSXS_PROCESSOR_ARCHITECTURE L"\"" /* Note that this only actually exists on x86 */
|
|
L" version=\"5.1.0.0\""
|
|
L" type=\"win32\"/>"
|
|
L"<dependency>"
|
|
L" <dependentAssembly>"
|
|
L" <assemblyIdentity"
|
|
L" type=\"win32\""
|
|
L" name=\"Microsoft.Tools.VisualCPlusPlus.Runtime-Libraries\""
|
|
L" version=\"6.0.0.0\""
|
|
L" processorArchitecture=\"" LSXS_PROCESSOR_ARCHITECTURE L"\""
|
|
L" publicKeyToken=\"6595b64144ccf1df\""
|
|
L" language=\"*\""
|
|
L" />"
|
|
L" </dependentAssembly>"
|
|
L"</dependency>"
|
|
L"</assembly>"
|
|
;
|
|
|
|
const WCHAR WindowsCrtManifest[]=
|
|
L"<?xml version=\"1.0\" standalone=\"yes\"?>"
|
|
L"<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
|
|
L"<assemblyIdentity"
|
|
L" name=\"Microsoft.Windows.SxsTest.WindowsCrtClient\""
|
|
L" processorArchitecture=\"" LSXS_PROCESSOR_ARCHITECTURE L"\""
|
|
L" version=\"5.1.0.0\""
|
|
L" type=\"win32\"/>"
|
|
L"<dependency>"
|
|
L" <dependentAssembly>"
|
|
L" <assemblyIdentity"
|
|
L" type=\"win32\""
|
|
L" name=\"Microsoft.Windows.CPlusPlusRuntime\""
|
|
L" version=\"7.0.0.0\""
|
|
L" processorArchitecture=\"" LSXS_PROCESSOR_ARCHITECTURE L"\""
|
|
L" publicKeyToken=\"6595b64144ccf1df\""
|
|
L" language=\"*\""
|
|
L" />"
|
|
L" </dependentAssembly>"
|
|
L"</dependency>"
|
|
L"</assembly>"
|
|
;
|
|
|
|
void TestCRuntimeAsms()
|
|
{
|
|
CFusionActCtxHandle WindowsCrtActCtxHandle;
|
|
CFusionActCtxHandle ToolsCrtActCtxHandle;
|
|
|
|
WindowsCrtActCtxHandle = ::CreateActivationContextFromStringW(WindowsCrtManifest);
|
|
if (WindowsCrtActCtxHandle == INVALID_HANDLE_VALUE)
|
|
::Trace("CreateActCtx(WindowsCrtManifest %p) failed %ld\n", WindowsCrtManifest, ::GetLastError());
|
|
ToolsCrtActCtxHandle = ::CreateActivationContextFromStringW(ToolsCrtManifest);
|
|
if (ToolsCrtActCtxHandle == INVALID_HANDLE_VALUE)
|
|
::Trace("CreateActCtx(WindowsCrtManifest %p) failed %ld\n", WindowsCrtManifest, ::GetLastError());
|
|
|
|
CFusionActCtxScope ToolsCrtActCtxScope;
|
|
CFusionActCtxScope WindowsCrtActCtxScope;
|
|
|
|
if (!WindowsCrtActCtxScope.Win32Activate(WindowsCrtActCtxHandle))
|
|
::Trace("Activate(WindowsCrtActCtxHandle %p) failed %ld\n", WindowsCrtActCtxHandle, ::GetLastError());
|
|
|
|
if (!ToolsCrtActCtxScope.Win32Activate(ToolsCrtActCtxHandle))
|
|
::Trace("Activate(ToolsCrtActCtxHandle %p) failed %ld\n", ToolsCrtActCtxHandle, ::GetLastError());
|
|
|
|
CStringBuffer MsvcrtBuffer;
|
|
CStringBuffer AtlBuffer;
|
|
|
|
//::SearchPathW();
|
|
}
|
|
|
|
/*
|
|
<comInterfaceExternalProxyStub
|
|
name="IPropertyPage"
|
|
iid="{B196B28D-BAB4-101A-B69C-00AA00341D07}"
|
|
proxyStubClsid32="{B196B286-BAB4-101A-B69C-00AA00341D07}"
|
|
numMethods="14"
|
|
baseInterface="{00000000-0000-0000-C000-000000000046}"
|
|
>
|
|
|
|
<comInterfaceExternalProxyStub
|
|
name="IPropertyPage2"
|
|
iid="{01E44665-24AC-101B-84ED-08002B2EC713}"
|
|
proxyStubClsid32="{B196B286-BAB4-101A-B69C-00AA00341D07}"
|
|
numMethods="15"
|
|
baseInterface="{B196B28D-BAB4-101A-B69C-00AA00341D07}"
|
|
>
|
|
|
|
<comInterfaceExternalProxyStub
|
|
name="IPropertyNotifySink"
|
|
iid="{9BFBBC02-EFF1-101A-84ED-00AA00341D07}"
|
|
proxyStubClsid32="{B196B286-BAB4-101A-B69C-00AA00341D07}"
|
|
baseInterface="{00000000-0000-0000-C000-00 00 00 00 00 46}"
|
|
numMethods="5"
|
|
>
|
|
*/
|
|
|
|
#if 0
|
|
BOOL Win32FormatGuid(
|
|
CBaseStringBuffer& buff
|
|
REFGUID guid
|
|
)
|
|
{
|
|
FN_PROLOG_WIN32
|
|
IFW32FALSE_EXIT(this->Win32ResizeBuffer(64));
|
|
IFW32FALSE_EXIT(buff.Win32Format(L"{%08lx-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x}",
|
|
guid.Data1,
|
|
guid.Data2,
|
|
guid.Data3,
|
|
guid.Data4[0], guid.Data4[1],
|
|
guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7],
|
|
));
|
|
FN_EPILOG
|
|
}
|
|
#endif
|
|
|
|
BOOL Win32Append(
|
|
CBaseStringBuffer& s,
|
|
PCWSTR t
|
|
)
|
|
{
|
|
FN_PROLOG_WIN32
|
|
IFW32FALSE_EXIT(s.Win32Append(t, wcslen(t)));
|
|
FN_EPILOG
|
|
}
|
|
|
|
typedef struct _FUSIONTESTP_REG_DATA
|
|
{
|
|
#define FUSIONTESTP_REG_TYPE_INTERFACE (1)
|
|
#define FUSIONTESTP_REG_TYPE_CLASS (2)
|
|
ULONG Type;
|
|
PCWSTR Name; // for debugging/tracing purposes (should coincide with InterfaceName)
|
|
PCWSTR Guid;
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
WCHAR InprocServerFilePath[MAX_PATH];
|
|
WCHAR ThreadingModel[64];
|
|
};
|
|
struct
|
|
{
|
|
WCHAR InterfaceName[MAX_PATH];
|
|
WCHAR NumMethods[64];
|
|
WCHAR ProxyStubClsid[64];
|
|
//
|
|
// These usually aren't provided.
|
|
//
|
|
// WCHAR BaseInterface[64];
|
|
// WCHAR OLEViewerIViewerCLSID[64];
|
|
//
|
|
};
|
|
};
|
|
#define FUSIONTESTP_REG_ROOT_CURRENT_USER (1)
|
|
#define FUSIONTESTP_REG_ROOT_LOCAL_MACHINE (2)
|
|
#define FUSIONTESTP_REG_ROOT_CLASSES_ROOT (3)
|
|
ULONG Root;
|
|
|
|
//
|
|
// It is perhaps a bit inelegant to put this data here, perhaps not..
|
|
// We are deliberately a bit sloppy on the refcounting of these right now.
|
|
//
|
|
//#define FUSIONTESTP_PLAIN_COM_POINTER(t) CSmartRef<t>
|
|
#define FUSIONTESTP_PLAIN_COM_POINTER(t) t*
|
|
//#define FUSIONTESTP_PLAIN_COM_POINTER(t) void*
|
|
FUSIONTESTP_PLAIN_COM_POINTER(IUnknown) CoCreatedObject;
|
|
//FUSIONTESTP_PLAIN_COM_POINTER(IUnknown) InterfaceIntoObjectInCreatingThread;
|
|
//FUSIONTESTP_PLAIN_COM_POINTER(IUnknown) InterfaceIntoObjectInAnotherThread;
|
|
//WCHAR ModulePathInOtherThread[MAX_PATH]; // expected to be oleaut32.dll, but possibly already unloaded
|
|
//IID InterfaceIdOfObject;
|
|
DWORD GlobalInterfaceTableCookie;
|
|
} FUSIONTESTP_REG_DATA, *PFUSIONTESTP_REG_DATA;
|
|
typedef const FUSIONTESTP_REG_DATA* PCFUSIONTESTP_REG_DATA;
|
|
|
|
#if 0
|
|
//
|
|
// In reality, all three MFC classes implement all three interfaces, but let's broaden
|
|
// our minds a bit, ok?
|
|
//
|
|
BOOL
|
|
FusionTestpDynamicallyFindAnyInterfaceIntoObjectExceptIUnknown(
|
|
IUnknown* Object,
|
|
PCFUSIONTESTP_REG_DATA RegData, // too broad of a type really, but ok
|
|
SIZE_T Count,
|
|
FUSIONTESTP_PLAIN_COM_POINTER(IUnknown)& InterfaceIntoObject,
|
|
SIZE_T& InterfaceId
|
|
)
|
|
{
|
|
BOOL Success = FALSE;
|
|
FN_PROLOG_WIN32(Success);
|
|
IID LocalInterfaceId = { 0 };
|
|
FUSIONTESTP_PLAIN_COM_POINTER(IUnknown) LocalInterfaceIntoObject = NULL;
|
|
SIZE_T InterfaceIndex = 0;
|
|
|
|
InterfaceIntoObject = LocalInterfaceIntoObject;
|
|
InterfaceId = LocalInterfaceId;
|
|
|
|
for ( LocalInterfaceIndex = 0; LocalInterfaceIndex != Count ; LocalInterfaceIndex += 1)
|
|
{
|
|
FUSIONTESTP_REG_DATA* const p = &RegData[LocalInterfaceIndex];
|
|
|
|
IFCOMFAILED_EXIT(hr = Ole32.IIDFromString(const_cast<PWSTR>(p->Guid), &InterfaceId));
|
|
|
|
if (InterfaceId == IID_IUnknown) // shouldn't happen, but easy enough to handle
|
|
continue;
|
|
|
|
hr = Object->QueryInterface(InterfaceId, reinterpret_cast<void**>(&LocalInterfaceIntoObject));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
::Trace("%s found interface %ls\n", __FUNCTION__, p->Name);
|
|
InterfaceIntoObject = LocalInterfaceIntoObject;
|
|
InterfaceId = LocalInterfaceId;
|
|
Success = TRUE;
|
|
goto Exit;
|
|
}
|
|
}
|
|
FN_EPILOG
|
|
}
|
|
#endif
|
|
|
|
#define OLEAUT_MARSHALER_CLSID_STRING L"{B196B286-BAB4-101A-B69C-00AA00341D07}"
|
|
|
|
FUSIONTESTP_REG_DATA FusionTestpMfcRegData[] =
|
|
{
|
|
{ FUSIONTESTP_REG_TYPE_CLASS, L"Font Property Page", L"{0BE35200-8F91-11CE-9DE3-00AA004BB851}" },
|
|
{ FUSIONTESTP_REG_TYPE_CLASS, L"Color Property Page", L"{0BE35201-8F91-11CE-9DE3-00AA004BB851}" },
|
|
{ FUSIONTESTP_REG_TYPE_CLASS, L"Picture Property Page", L"{0BE35202-8F91-11CE-9DE3-00AA004BB851}" },
|
|
{ FUSIONTESTP_REG_TYPE_INTERFACE, L"IPropertyPage", L"{B196B28D-BAB4-101A-B69C-00AA00341D07}" },
|
|
{ FUSIONTESTP_REG_TYPE_INTERFACE, L"IPropertyPage2", L"{01E44665-24AC-101B-84ED-08002B2EC713}" },
|
|
{ FUSIONTESTP_REG_TYPE_INTERFACE, L"IPropertyNotifySink", L"{9BFBBC02-EFF1-101A-84ED-00AA00341D07}" },
|
|
// Leave this registered, since the manifest does not specify a file.
|
|
//{ FUSIONTESTP_REG_TYPE_CLASS, L"oleaut32 marshaller (PSFactoryBuffer)", OLEAUT_MARSHALER_CLSID_STRING }
|
|
};
|
|
|
|
FUSIONTESTP_REG_DATA FusionTestpAtlRegData[1];
|
|
|
|
const HKEY FusionTestpHkeyRoots[] = { NULL, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_CLASSES_ROOT };
|
|
const PCWSTR FusionTestpClassStringRoots[] = { NULL, L"Software\\Classes\\CLSID\\", L"Software\\Classes\\CLSID\\", L"CLSID\\" };
|
|
const PCWSTR FusionTestpInterfaceStringRoots[] = { NULL, L"Software\\Classes\\Interface\\", L"Software\\Classes\\Interface\\", L"Interface\\" };
|
|
const PCWSTR* FusionTestpStringRoots[] = { NULL, FusionTestpInterfaceStringRoots, FusionTestpClassStringRoots};
|
|
|
|
#define FUSIONTESTP_REG_DELETE (1)
|
|
#define FUSIONTESTP_REG_RESTORE (2)
|
|
#define FUSIONTESTP_REG_BACKUP (3)
|
|
|
|
BOOL FusionTestpEnumerateRegistryData(FUSIONTESTP_REG_DATA* RegData, ULONG Count, ULONG Mode)
|
|
{
|
|
BOOL Success = FALSE;
|
|
FN_PROLOG_WIN32(Success);
|
|
|
|
for (ULONG i = 0 ; i != Count ; i += 1)
|
|
{
|
|
FUSIONTESTP_REG_DATA* const p = &RegData[i];
|
|
ULONG MinRoot = 0;
|
|
ULONG MaxRoot = 0;
|
|
switch (Mode)
|
|
{
|
|
case FUSIONTESTP_REG_RESTORE:
|
|
case FUSIONTESTP_REG_DELETE:
|
|
MinRoot = p->Root;
|
|
if (MinRoot == 0)
|
|
continue;
|
|
MaxRoot = MinRoot;
|
|
break;
|
|
case FUSIONTESTP_REG_BACKUP:
|
|
MinRoot = 1;
|
|
MaxRoot = 3;
|
|
break;
|
|
}
|
|
//
|
|
// It'd be nice if you could embed the if within a switch..
|
|
//
|
|
for (ULONG root = MinRoot ; root <= MaxRoot ; root += 1)
|
|
{
|
|
CFusionRegKey regKey;
|
|
CFusionRegKey inprocServerKey;
|
|
CStringBuffer stringBuffer;
|
|
CFusionRegKey numMethodsKey;
|
|
CFusionRegKey proxyStubClsidKey;
|
|
DWORD dwSize = 0;
|
|
DWORD dwType = 0;
|
|
|
|
CFusionRegKey rootKey(FusionTestpHkeyRoots[root]);
|
|
|
|
IFW32FALSE_EXIT(Win32Append(stringBuffer, FusionTestpStringRoots[p->Type][root]));
|
|
IFW32FALSE_EXIT(Win32Append(stringBuffer, p->Guid));
|
|
switch (Mode)
|
|
{
|
|
case FUSIONTESTP_REG_DELETE:
|
|
case FUSIONTESTP_REG_BACKUP:
|
|
rootKey.OpenSubKey(regKey, stringBuffer);
|
|
break;
|
|
case FUSIONTESTP_REG_RESTORE:
|
|
IFW32FALSE_EXIT(rootKey.OpenOrCreateSubKey(regKey, stringBuffer));
|
|
break;
|
|
}
|
|
if (regKey != regKey.GetInvalidValue())
|
|
{
|
|
switch (Mode)
|
|
{
|
|
case FUSIONTESTP_REG_BACKUP:
|
|
p->Root = root;
|
|
break;
|
|
case FUSIONTESTP_REG_DELETE:
|
|
case FUSIONTESTP_REG_RESTORE:
|
|
break;
|
|
}
|
|
switch (p->Type)
|
|
{
|
|
case FUSIONTESTP_REG_TYPE_CLASS:
|
|
switch (Mode)
|
|
{
|
|
case FUSIONTESTP_REG_BACKUP:
|
|
#define FusionTestpQueryRegString(hkey, name, value) \
|
|
do { dwSize = sizeof(value); \
|
|
RegQueryValueExW(hkey, name, NULL, &dwType, reinterpret_cast<BYTE*>(value), &dwSize); \
|
|
} while(false)
|
|
if (regKey.OpenSubKey(inprocServerKey, L"InprocServer32"))
|
|
{
|
|
FusionTestpQueryRegString(inprocServerKey, NULL, p->InprocServerFilePath);
|
|
FusionTestpQueryRegString(inprocServerKey, L"ThreadingModel", p->ThreadingModel);
|
|
}
|
|
break;
|
|
case FUSIONTESTP_REG_RESTORE:
|
|
if (regKey.OpenOrCreateSubKey(inprocServerKey, L"InprocServer32"))
|
|
{
|
|
#define FusionTestpRegStringSize(x) static_cast<ULONG>(((wcslen(x) + 1)*sizeof((x)[0])))
|
|
#define FusionTestpSetRegString(hkey, name, value) \
|
|
do { if (value[0] != 0) \
|
|
RegSetValueExW(hkey, name, NULL, REG_SZ, reinterpret_cast<const BYTE*>(value), FusionTestpRegStringSize(value)); \
|
|
} while(false)
|
|
FusionTestpSetRegString(inprocServerKey, NULL, p->InprocServerFilePath);
|
|
FusionTestpSetRegString(inprocServerKey, L"ThreadingModel", p->ThreadingModel);
|
|
}
|
|
break;
|
|
case FUSIONTESTP_REG_DELETE:
|
|
break;
|
|
}
|
|
break;
|
|
case FUSIONTESTP_REG_TYPE_INTERFACE:
|
|
switch (Mode)
|
|
{
|
|
case FUSIONTESTP_REG_BACKUP:
|
|
FusionTestpQueryRegString(regKey, NULL, p->InterfaceName);
|
|
if (regKey.OpenSubKey(numMethodsKey, L"NumMethods"))
|
|
FusionTestpQueryRegString(numMethodsKey, NULL, p->NumMethods);
|
|
if (regKey.OpenSubKey(proxyStubClsidKey, L"ProxyStubClsid32"))
|
|
FusionTestpQueryRegString(proxyStubClsidKey, NULL, p->ProxyStubClsid);
|
|
break;
|
|
case FUSIONTESTP_REG_RESTORE:
|
|
FusionTestpSetRegString(regKey, NULL, p->InterfaceName);
|
|
if (regKey.OpenOrCreateSubKey(numMethodsKey, L"NumMethods"))
|
|
FusionTestpSetRegString(numMethodsKey, NULL, p->NumMethods);
|
|
if (regKey.OpenOrCreateSubKey(proxyStubClsidKey, L"ProxyStubClsid32"))
|
|
FusionTestpSetRegString(proxyStubClsidKey, NULL, p->ProxyStubClsid);
|
|
case FUSIONTESTP_REG_DELETE:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
switch (Mode)
|
|
{
|
|
case FUSIONTESTP_REG_DELETE:
|
|
regKey.DestroyKeyTree();
|
|
break;
|
|
case FUSIONTESTP_REG_BACKUP:
|
|
case FUSIONTESTP_REG_RESTORE:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
FN_EPILOG
|
|
}
|
|
|
|
#if 0 // Use CoWaitForMultipleHandles instead, it is much safer because it only
|
|
// pumps particular messages.
|
|
void FusionTestpPumpMessages()
|
|
{
|
|
MSG msg;
|
|
BOOL bRet;
|
|
while ((bRet = ::GetMessageW(&msg, NULL, 0, 0)) != 0)
|
|
{
|
|
if (bRet == -1)
|
|
return;
|
|
else
|
|
{
|
|
::TranslateMessage(&msg);
|
|
if (::IsWindowUnicode(msg.hwnd))
|
|
::DispatchMessageW(&msg);
|
|
else
|
|
::DispatchMessage(&msg);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
HMODULE FusionTestpHmoduleFromComObject(IUnknown* unk)
|
|
{
|
|
void** ppv = reinterpret_cast<void**>(unk);
|
|
void* pv = *ppv;
|
|
MEMORY_BASIC_INFORMATION MemBasicInfo = { 0 };
|
|
SIZE_T dw = 0;
|
|
|
|
if ((dw = Kernel32.VirtualQuery(pv, &MemBasicInfo, sizeof(MemBasicInfo))) == 0
|
|
|| (dw < RTL_SIZEOF_THROUGH_FIELD(MEMORY_BASIC_INFORMATION, BaseAddress)))
|
|
{
|
|
::Trace("VirtualQuery(%p) failed %lu\n", pv, ::GetLastError());
|
|
return NULL;
|
|
}
|
|
return reinterpret_cast<HMODULE>(MemBasicInfo.AllocationBase);
|
|
}
|
|
|
|
|
|
DWORD WINAPI FusionTestpMfcCreateAndMarshalThreadMain(LPVOID pvShouldBeAbleToMarshal)
|
|
{
|
|
BOOL Success = FALSE;
|
|
FN_PROLOG_WIN32(Success);
|
|
HRESULT hr = 0;
|
|
const bool ShouldBeAbleToMarshal = (pvShouldBeAbleToMarshal != NULL ? true : false);
|
|
Ole32.CoInitialize(NULL);
|
|
|
|
//
|
|
// For each interface, make sure we can unmarshal at least one object.
|
|
//
|
|
for (ULONG InterfaceIndex = 0 ; InterfaceIndex != NUMBER_OF(::FusionTestpMfcRegData) ; InterfaceIndex += 1)
|
|
{
|
|
FUSIONTESTP_REG_DATA* const pi = &::FusionTestpMfcRegData[InterfaceIndex];
|
|
|
|
switch (pi->Type)
|
|
{
|
|
case FUSIONTESTP_REG_TYPE_CLASS:
|
|
continue;
|
|
case FUSIONTESTP_REG_TYPE_INTERFACE:
|
|
IID InterfaceId = { 0 };
|
|
FUSIONTESTP_PLAIN_COM_POINTER(IUnknown) InterfaceIntoObjectInAnotherThread = NULL;
|
|
|
|
IFCOMFAILED_EXIT(hr = Ole32.IIDFromString(const_cast<PWSTR>(pi->Guid), &InterfaceId));
|
|
|
|
// nested loop..
|
|
for (ULONG ClassIndex = 0 ;
|
|
ClassIndex != NUMBER_OF(::FusionTestpMfcRegData) ;
|
|
ClassIndex += 1)
|
|
{
|
|
CLSID ClassId = { 0 };
|
|
FUSIONTESTP_REG_DATA* const pc = &::FusionTestpMfcRegData[ClassIndex];
|
|
|
|
switch (pc->Type)
|
|
{
|
|
case FUSIONTESTP_REG_TYPE_INTERFACE:
|
|
continue;
|
|
case FUSIONTESTP_REG_TYPE_CLASS:
|
|
|
|
WCHAR ModulePathInOtherThread[MAX_PATH];
|
|
ModulePathInOtherThread[0] = 0;
|
|
|
|
ASSERT(pc->GlobalInterfaceTableCookie != 0);
|
|
IFCOMFAILED_EXIT(hr = Ole32.CLSIDFromString(const_cast<PWSTR>(pc->Guid), &ClassId));
|
|
|
|
hr = g.GlobalInterfaceTable->GetInterfaceFromGlobal(
|
|
pc->GlobalInterfaceTableCookie, InterfaceId,
|
|
reinterpret_cast<void**>(&InterfaceIntoObjectInAnotherThread));
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IFW32FALSE_EXIT(Kernel32.GetModuleFileNameW(
|
|
::FusionTestpHmoduleFromComObject(InterfaceIntoObjectInAnotherThread),
|
|
ModulePathInOtherThread, NUMBER_OF(ModulePathInOtherThread)));
|
|
}
|
|
if (SUCCEEDED(hr) && ShouldBeAbleToMarshal)
|
|
{
|
|
Trace("%s SUCCESSfully marshaled interface %ls on class %ls using proxy/stub in %ls\n",
|
|
__FUNCTION__, pi->Name, pc->Name, ModulePathInOtherThread);
|
|
g.Successes += 1;
|
|
}
|
|
else if (SUCCEEDED(hr) && !ShouldBeAbleToMarshal)
|
|
{
|
|
// unexpected success -> ERROR
|
|
|
|
Trace("%s FAILED to fail to marshal interface %ls on class %ls (using proxy/stub in %ls)\n",
|
|
__FUNCTION__, pi->Name, pc->Name, ModulePathInOtherThread);
|
|
g.Failures += 1;
|
|
}
|
|
else if (FAILED(hr) && ShouldBeAbleToMarshal)
|
|
{
|
|
// keep looping, try other objects
|
|
}
|
|
else if (FAILED(hr) && !ShouldBeAbleToMarshal)
|
|
{
|
|
// keep looping, make sure none succeed
|
|
//::Trace("%s OK Unable to marshal interface %ls (%ls) 0x%lx (fac 0x%lx code 0x%lx)\n", __FUNCTION__, pi->Name, pi->Guid, hr, HRESULT_FACILITY(hr), HRESULT_CODE(hr));
|
|
}
|
|
break;
|
|
}
|
|
if (InterfaceIntoObjectInAnotherThread != NULL && ShouldBeAbleToMarshal)
|
|
{
|
|
// one successful unmarshal is enough
|
|
break;
|
|
}
|
|
}
|
|
// use the nullness of InterfaceIntoObjectInAnotherThread as a summary of the loop
|
|
if (InterfaceIntoObjectInAnotherThread == NULL && ShouldBeAbleToMarshal)
|
|
{
|
|
::Trace("%s FAILURE Unable to marshal interface %ls (%ls)\n", __FUNCTION__, pi->Name, pi->Guid);
|
|
g.Failures += 1;
|
|
}
|
|
else if (InterfaceIntoObjectInAnotherThread == NULL && !ShouldBeAbleToMarshal)
|
|
{
|
|
::Trace("%s GOOD Unable to marshal interface %ls without actctx as expected\n", __FUNCTION__, pi->Name);
|
|
g.Successes += 1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
Ole32.CoUninitialize();
|
|
FN_EPILOG
|
|
}
|
|
|
|
BOOL TestMfcCreateAndMarshal()
|
|
{
|
|
BOOL Success = FALSE;
|
|
FN_PROLOG_WIN32(Success);
|
|
|
|
ULONG i = 0;
|
|
HRESULT hr = 0;
|
|
HANDLE ThreadHandle = 0;
|
|
DWORD Ignored = 0;
|
|
|
|
CFusionActCtxHandle ToolsCrtActCtxHandle;
|
|
|
|
::FusionTestpEnumerateRegistryData(::FusionTestpMfcRegData, NUMBER_OF(::FusionTestpMfcRegData), FUSIONTESTP_REG_BACKUP);
|
|
::FusionTestpEnumerateRegistryData(::FusionTestpMfcRegData, NUMBER_OF(::FusionTestpMfcRegData), FUSIONTESTP_REG_DELETE);
|
|
|
|
Ole32.CoInitialize(NULL);
|
|
|
|
//
|
|
// Verify that we cannot create any of the classes.
|
|
//
|
|
for (i = 0 ; i != NUMBER_OF(::FusionTestpMfcRegData) ; i += 1)
|
|
{
|
|
CSmartRef<IUnknown> unk;
|
|
CLSID ClassId = { 0 };
|
|
|
|
FUSIONTESTP_REG_DATA* const p = &::FusionTestpMfcRegData[i];
|
|
switch (p->Type)
|
|
{
|
|
case FUSIONTESTP_REG_TYPE_INTERFACE:
|
|
break;
|
|
case FUSIONTESTP_REG_TYPE_CLASS:
|
|
IFCOMFAILED_EXIT(hr = Ole32.CLSIDFromString(const_cast<PWSTR>(p->Guid), &ClassId));
|
|
hr = Ole32.CoCreateInstance(ClassId, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, reinterpret_cast<void**>(&unk));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
::Trace("%s BAD, no registry, no actctx CoCreate(%ls) SUCCEEDED, not expected\n", __FUNCTION__, p->Name);
|
|
g.Failures += 1;
|
|
}
|
|
else
|
|
{
|
|
::Trace("%s GOOD, no registry, no actctx CoCreate(%ls) FAILed 0x%lx, as expected\n", __FUNCTION__, p->Name, hr);
|
|
g.Successes += 1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create and activate the context.
|
|
//
|
|
|
|
ToolsCrtActCtxHandle = ::CreateActivationContextFromStringW(ToolsCrtManifest);
|
|
if (ToolsCrtActCtxHandle == INVALID_HANDLE_VALUE)
|
|
::Trace("CreateActCtx(WindowsCrtManifest %p) failed %ld\n", WindowsCrtManifest, ::GetLastError());
|
|
|
|
{
|
|
CFusionActCtxScope ToolsCrtActCtxScope;
|
|
if (!ToolsCrtActCtxScope.Win32Activate(ToolsCrtActCtxHandle))
|
|
::Trace("Activate(ToolsCrtActCtxHandle %p) failed %ld\n", ToolsCrtActCtxHandle, ::GetLastError());
|
|
|
|
//
|
|
// Now create each class and print the .dll it came from.
|
|
// And put it in the global interface table for later unmarshalling.
|
|
//
|
|
|
|
IFCOMFAILED_EXIT(hr = Ole32.CoCreateInstance(CLSID_StdGlobalInterfaceTable,NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IGlobalInterfaceTable, reinterpret_cast<void**>(&g.GlobalInterfaceTable)));
|
|
|
|
for (i = 0 ; i != NUMBER_OF(::FusionTestpMfcRegData) ; i += 1)
|
|
{
|
|
CLSID ClassId = { 0 };
|
|
|
|
FUSIONTESTP_REG_DATA* const p = &::FusionTestpMfcRegData[i];
|
|
|
|
//
|
|
// We are not supposed to be able to cocreate this here.
|
|
//
|
|
if (FusionpStrCmpI(p->Guid, OLEAUT_MARSHALER_CLSID_STRING) == 0)
|
|
continue;
|
|
|
|
switch (p->Type)
|
|
{
|
|
case FUSIONTESTP_REG_TYPE_INTERFACE:
|
|
break;
|
|
case FUSIONTESTP_REG_TYPE_CLASS:
|
|
IFCOMFAILED_EXIT(hr = Ole32.CLSIDFromString(const_cast<PWSTR>(p->Guid), &ClassId));
|
|
hr = Ole32.CoCreateInstance(ClassId, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown,
|
|
reinterpret_cast<void**>(&p->CoCreatedObject));
|
|
if (FAILED(hr))
|
|
{
|
|
Trace("%s Failure: CoCreate(%ls) FAILED\n", __FUNCTION__, p->Name);
|
|
g.Failures += 1;
|
|
}
|
|
else
|
|
{
|
|
WCHAR ComObjectModule[MAX_PATH];
|
|
ComObjectModule[0] = 0;
|
|
|
|
IFW32FALSE_EXIT(Kernel32.GetModuleFileNameW(
|
|
::FusionTestpHmoduleFromComObject(p->CoCreatedObject), ComObjectModule, NUMBER_OF(ComObjectModule)));
|
|
Trace("%s SUCCESSfully cocreated %p of type %ls from %ls with actctx influence\n",
|
|
__FUNCTION__, p->CoCreatedObject, p->Name, ComObjectModule);
|
|
|
|
g.Successes += 1;
|
|
|
|
#if 0
|
|
//
|
|
// Put it in the global interface table for later marshalling.
|
|
// It does not make sense to use IUnknown here, because ole32 can always
|
|
// marshal IUnknown itself without any proxy/stubs found via the
|
|
// registry or fusion (see also my special message pumper in vsee that
|
|
// takes advantage of this feature...)
|
|
//
|
|
IFW32FALSE_EXIT(
|
|
FusionTestpDynamicallyFindAnyInterfaceIntoObjectExceptIUnknown(
|
|
p->CoCreatedObject,
|
|
::FusionTestpMfcRegData,
|
|
RTL_NUMBER_OF(::FusionTestpMfcRegData),
|
|
p->InterfaceIntoObjectInCreatingThread,
|
|
p->InterfaceIdOfObject
|
|
));
|
|
|
|
IFCOMFAILED_EXIT(hr = g.GlobalInterfaceTable->RegisterInterfaceInGlobal(
|
|
p->InterfaceIntoObjectInCreatingThread,
|
|
p->InterfaceIdOfObject,
|
|
&p->GlobalInterfaceTableCookie
|
|
));
|
|
#else
|
|
//
|
|
// It'll still have to look for the proxy/stub at unmarshal time. This is fine.
|
|
//
|
|
IFCOMFAILED_EXIT(hr = g.GlobalInterfaceTable->RegisterInterfaceInGlobal(
|
|
p->CoCreatedObject,
|
|
IID_IUnknown,
|
|
&p->GlobalInterfaceTableCookie
|
|
));
|
|
#endif
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
CFusionActCtxScope ToolsCrtActCtxScope;
|
|
if (!ToolsCrtActCtxScope.Win32Activate(ToolsCrtActCtxHandle))
|
|
::Trace("Activate(ToolsCrtActCtxHandle %p) failed %ld\n", ToolsCrtActCtxHandle, ::GetLastError());
|
|
//
|
|
// try marshalling with the actctx activated, it should work (not NULL => expected success==TRUE)
|
|
//
|
|
ThreadHandle = CreateThread(NULL, 0, FusionTestpMfcCreateAndMarshalThreadMain, &Ignored, 0, &Ignored);
|
|
CoWaitForMultipleHandles(0, INFINITE, 1, &ThreadHandle, &Ignored);
|
|
CloseHandle(ThreadHandle);
|
|
}
|
|
|
|
#if 0
|
|
//
|
|
// If interfaces are _really_never_ changed, (but doesn't Fusion let you violate that?),
|
|
// this test case isn't valid. COM does caching and prefills caches when you may not expect
|
|
// (like when you put stuff in the GlobalInterfaceTable), and it does not invalidate its caches
|
|
// because of actctx pushes and pops.
|
|
//
|
|
{
|
|
//
|
|
// try marshalling without the actctx activated, it should NOT work (NULL => expected success==FALSE)
|
|
//
|
|
ThreadHandle = CreateThread(NULL, 0, FusionTestpMfcCreateAndMarshalThreadMain, NULL, 0, &Ignored);
|
|
CoWaitForMultipleHandles(0, INFINITE, 1, &ThreadHandle, &Ignored);
|
|
CloseHandle(ThreadHandle);
|
|
}
|
|
#endif
|
|
|
|
|
|
Ole32.CoUninitialize();
|
|
|
|
//::FusionTestpEnumerateRegistryData(::FusionTestpMfcRegData, NUMBER_OF(::FusionTestpMfcRegData), FUSIONTESTP_REG_RESTORE);
|
|
|
|
FN_EPILOG
|
|
}
|
|
|
|
|
|
void TestAtlCreate()
|
|
{
|
|
::FusionTestpEnumerateRegistryData(FusionTestpAtlRegData, NUMBER_OF(FusionTestpAtlRegData), FUSIONTESTP_REG_BACKUP);
|
|
::FusionTestpEnumerateRegistryData(FusionTestpAtlRegData, NUMBER_OF(FusionTestpAtlRegData), FUSIONTESTP_REG_DELETE);
|
|
|
|
::FusionTestpEnumerateRegistryData(FusionTestpAtlRegData, NUMBER_OF(FusionTestpAtlRegData), FUSIONTESTP_REG_RESTORE);
|
|
}
|
|
|
|
BOOL TestPrivateSha1Impl(
|
|
PCWSTR pcwszDirName
|
|
)
|
|
{
|
|
FN_PROLOG_WIN32
|
|
CFusionArray<BYTE> rgbShaState;
|
|
CFusionFile ffInputFile;
|
|
BYTE bChunkletBuffer[4096];
|
|
CSmallStringBuffer sbHashedString;
|
|
DWORD dwReadData;
|
|
HCRYPTPROV hProvider;
|
|
HCRYPTHASH hHash;
|
|
CFusionHash fHashObject;
|
|
|
|
IFW32FALSE_EXIT(fHashObject.Win32Initialize(CALG_SHA1));
|
|
IFW32FALSE_EXIT(ffInputFile.Win32CreateFile(
|
|
pcwszDirName,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
OPEN_EXISTING));
|
|
|
|
IFW32FALSE_EXIT(CryptAcquireContextW(
|
|
&hProvider,
|
|
NULL,
|
|
NULL,
|
|
PROV_RSA_FULL,
|
|
CRYPT_SILENT | CRYPT_VERIFYCONTEXT ));
|
|
|
|
IFW32FALSE_EXIT(CryptCreateHash(
|
|
hProvider,
|
|
CALG_SHA1,
|
|
0,
|
|
0,
|
|
&hHash ));
|
|
|
|
do
|
|
{
|
|
IFW32FALSE_EXIT(::ReadFile(
|
|
ffInputFile,
|
|
bChunkletBuffer,
|
|
sizeof(bChunkletBuffer),
|
|
&dwReadData,
|
|
NULL));
|
|
IFW32FALSE_EXIT(fHashObject.Win32HashData(bChunkletBuffer, dwReadData));
|
|
IFW32FALSE_EXIT(CryptHashData(hHash, bChunkletBuffer, dwReadData, 0));
|
|
}
|
|
while ( dwReadData != 0 );
|
|
|
|
IFW32FALSE_EXIT(fHashObject.Win32GetValue(rgbShaState));
|
|
|
|
wprintf(L"%ls (private) hashed to ", pcwszDirName);
|
|
for ( SIZE_T n = 0; n < rgbShaState.GetSize(); n++ )
|
|
{
|
|
wprintf(L"%02x", rgbShaState[n]);
|
|
}
|
|
|
|
|
|
IFW32FALSE_EXIT(CryptGetHashParam(
|
|
hHash,
|
|
HP_HASHVAL,
|
|
bChunkletBuffer,
|
|
&(dwReadData = sizeof(bChunkletBuffer)),
|
|
0));
|
|
|
|
wprintf(L"\n%ls (regular) hashed to ", pcwszDirName);
|
|
for ( SIZE_T n = 0; n < dwReadData; n++ )
|
|
{
|
|
wprintf(L"%02x", bChunkletBuffer[n]);
|
|
}
|
|
|
|
IFW32FALSE_EXIT(CryptReleaseContext(hProvider, 0));
|
|
|
|
FN_EPILOG
|
|
}
|
|
|
|
void TestAlignment()
|
|
{
|
|
CCleanupBase* p = reinterpret_cast<CCleanupBase*>(ULONG_PTR(0xffff0000));
|
|
SINGLE_LIST_ENTRY* q = p;
|
|
|
|
printf("%p %Ix\n", q, ULONG_PTR(q) % 16);
|
|
}
|
|
|
|
void TestCreateActCtx_PE_flags0()
|
|
{
|
|
WCHAR SyssetupDll[MAX_PATH * 2];
|
|
ACTCTXW ActCtx = {sizeof(ActCtx)};
|
|
CFusionActCtxHandle ActCtxHandle;
|
|
|
|
GetSystemDirectoryW(SyssetupDll, MAX_PATH);
|
|
wcscat(SyssetupDll, L"\\syssetup.dll");
|
|
ActCtx.lpSource = SyssetupDll;
|
|
|
|
printf("%s\n", ActCtxHandle.Win32Create(&ActCtx) ? "true" : "false");
|
|
}
|
|
|
|
void
|
|
TestUninstall(
|
|
PCWSTR ManifestPath,
|
|
PCWSTR ReferenceString
|
|
)
|
|
{
|
|
SXS_UNINSTALLW UninstallParameters = {sizeof(UninstallParameters)};
|
|
SXS_INSTALL_REFERENCEW Reference = {sizeof(Reference)};
|
|
PSXS_UNINSTALL_W_ROUTINE Uninstall = NULL;
|
|
PSXS_QUERY_MANIFEST_INFORMATION QueryManifestInformation;
|
|
BYTE ManifestInformationBuffer[1UL << 16];
|
|
PSXS_MANIFEST_INFORMATION_BASIC ManifestBasicInfo = reinterpret_cast<PSXS_MANIFEST_INFORMATION_BASIC>(&ManifestInformationBuffer);
|
|
DWORD Disposition = 0;
|
|
BOOL Success = FALSE;
|
|
|
|
LoadSxs();
|
|
GetSxsProc("SxsUninstallW", &Uninstall);
|
|
GetSxsProc("SxsQueryManifestInformation", &QueryManifestInformation);
|
|
|
|
Success = QueryManifestInformation(0, ManifestPath,
|
|
SXS_QUERY_MANIFEST_INFORMATION_INFOCLASS_BASIC, 0, sizeof(ManifestInformationBuffer),
|
|
ManifestBasicInfo, NULL);
|
|
|
|
printf("QueryManifestInformation(%ls)->(%ls, %ls)\n", ManifestPath, ManifestBasicInfo->lpIdentity, ManifestBasicInfo->lpShortName);
|
|
|
|
UninstallParameters.dwFlags |= SXS_UNINSTALL_FLAG_REFERENCE_VALID;
|
|
UninstallParameters.lpInstallReference = &Reference;
|
|
UninstallParameters.lpAssemblyIdentity = ManifestBasicInfo->lpIdentity;
|
|
|
|
Reference.lpIdentifier = ReferenceString;
|
|
Reference.guidScheme = SXS_INSTALL_REFERENCE_SCHEME_OPAQUESTRING;
|
|
|
|
Success = Uninstall(&UninstallParameters, &Disposition);
|
|
|
|
printf("TestUninstall(%ls, %ls) : %s, 0x%lx\n", ManifestPath, ReferenceString, Success ? "true" : "false", Disposition);
|
|
}
|
|
|
|
BOOL
|
|
TestNewSxsInstallAPI(
|
|
PCWSTR pcwszManifest
|
|
)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
PSXS_INSTALL_W sxsInstallW = NULL;
|
|
PSXS_UNINSTALL_ASSEMBLYW sxsUninstallW = NULL;
|
|
SXS_INSTALLW Info = {sizeof(Info)};
|
|
SXS_INSTALL_REFERENCEW Reference = {sizeof(Reference)};
|
|
SXS_UNINSTALLW Uninstall = {sizeof(Uninstall)};
|
|
DWORD dwDisposition;
|
|
|
|
Info.dwFlags = SXS_INSTALL_FLAG_REPLACE_EXISTING |
|
|
SXS_INSTALL_FLAG_REFERENCE_VALID |
|
|
SXS_INSTALL_FLAG_CODEBASE_URL_VALID |
|
|
SXS_INSTALL_FLAG_LOG_FILE_NAME_VALID;
|
|
Info.lpManifestPath = pcwszManifest;
|
|
Info.lpCodebaseURL = Info.lpManifestPath;
|
|
Info.lpReference = &Reference;
|
|
Info.lpLogFileName = L"c:\\thelogfile";
|
|
|
|
DWORD dwAttribute = GetFileAttributesW(pcwszManifest);
|
|
if ( dwAttribute == 0xffffffff) // non-exist
|
|
goto Exit;
|
|
if ( dwAttribute & FILE_ATTRIBUTE_DIRECTORY) // install from a directory recursively
|
|
{
|
|
Info.dwFlags |= SXS_INSTALL_FLAG_FROM_DIRECTORY_RECURSIVE;
|
|
}
|
|
|
|
Reference.guidScheme = SXS_INSTALL_REFERENCE_SCHEME_OPAQUESTRING;
|
|
Reference.lpIdentifier = L"Sxs installation";
|
|
|
|
LoadSxs();
|
|
GetSxsProc(SXS_INSTALL_W, &sxsInstallW);
|
|
GetSxsProc(SXS_UNINSTALL_ASSEMBLYW, &sxsUninstallW);
|
|
|
|
if (!(*sxsInstallW)(&Info))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Uninstall.dwFlags = SXS_UNINSTALL_FLAG_USE_INSTALL_LOG;
|
|
Uninstall.lpInstallLogFile = L"c:\\thelogfile";
|
|
|
|
if (!(*sxsUninstallW)(&Uninstall, &dwDisposition))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
fSuccess = TRUE;
|
|
Exit:
|
|
if (!fSuccess)
|
|
{
|
|
fprintf(stderr, "%s failed!\n", __FUNCTION__);
|
|
return EXIT_FAILURE;
|
|
}
|
|
else
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
NTAPI
|
|
SimpleContextNotification(
|
|
IN ULONG NotificationType,
|
|
IN PACTIVATION_CONTEXT ActivationContext,
|
|
IN const VOID *ActivationContextData,
|
|
IN PVOID NotificationContext,
|
|
IN PVOID NotificationData,
|
|
IN OUT PBOOLEAN DisableNotification
|
|
)
|
|
{
|
|
switch (NotificationType)
|
|
{
|
|
case ACTIVATION_CONTEXT_NOTIFICATION_DESTROY:
|
|
RTL_SOFT_VERIFY(NT_SUCCESS(NtUnmapViewOfSection(NtCurrentProcess(), (PVOID) ActivationContextData)));
|
|
break;
|
|
|
|
default:
|
|
// Otherwise, we don't need to see this notification ever again.
|
|
*DisableNotification = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
MakeActCtxFromCurrentSxsDll(
|
|
PCWSTR pcwszFileName,
|
|
HANDLE *phActCtx
|
|
)
|
|
{
|
|
FN_PROLOG_WIN32;
|
|
|
|
SXS_GENERATE_ACTIVATION_CONTEXT_PARAMETERS Parameters = {0};
|
|
PACTIVATION_CONTEXT pContextCreated = NULL;
|
|
CStringBuffer AssemblyDirectory;
|
|
CFileStream SourceManifestStream;
|
|
PVOID pvMappedSection = NULL;
|
|
NTSTATUS status;
|
|
BOOL (WINAPI *pfnSxsGenerateActivationContext)(PSXS_GENERATE_ACTIVATION_CONTEXT_PARAMETERS Parameters);
|
|
|
|
*phActCtx = INVALID_HANDLE_VALUE;
|
|
|
|
LoadSxs();
|
|
GetSxsProc("SxsGenerateActivationContext", &pfnSxsGenerateActivationContext);
|
|
|
|
IFW32FALSE_EXIT(SourceManifestStream.OpenForRead(pcwszFileName, CImpersonationData(), FILE_SHARE_READ, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN));
|
|
Parameters.Manifest.Path = pcwszFileName;
|
|
Parameters.Manifest.PathType = ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE;
|
|
Parameters.Manifest.Stream = &SourceManifestStream;
|
|
|
|
IFW32FALSE_EXIT(AssemblyDirectory.Win32Assign(pcwszFileName, ::wcslen(pcwszFileName)));
|
|
AssemblyDirectory.RemoveLastPathElement();
|
|
Parameters.AssemblyDirectory = AssemblyDirectory;
|
|
Parameters.ProcessorArchitecture = 0;
|
|
Parameters.LangId = GetUserDefaultUILanguage();
|
|
|
|
IFW32FALSE_EXIT(pfnSxsGenerateActivationContext(&Parameters));
|
|
IFW32NULL_EXIT(pvMappedSection = MapViewOfFile(Parameters.SectionObjectHandle, FILE_MAP_READ, 0, 0, 0));
|
|
|
|
status = RtlCreateActivationContext(
|
|
0,
|
|
pvMappedSection,
|
|
0,
|
|
SimpleContextNotification,
|
|
NULL,
|
|
&pContextCreated);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
ORIGINATE_WIN32_FAILURE_AND_EXIT(RtlCreateActivationContext, RtlNtStatusToDosError(status));
|
|
}
|
|
|
|
*phActCtx = pContextCreated;
|
|
|
|
FN_EPILOG;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOL SimpleTestFindAndUseSurrogateInformation(PCWSTR filename, PCWSTR GuidToDisplay)
|
|
{
|
|
FN_PROLOG_WIN32;
|
|
SXS_GENERATE_ACTIVATION_CONTEXT_PARAMETERS Parameters = {0};
|
|
BOOL (WINAPI *pfnSxsGenerateActivationContext)(PSXS_GENERATE_ACTIVATION_CONTEXT_PARAMETERS Parameters);
|
|
CFileStream SourceManifestStream;
|
|
CStringBuffer AssemblyDirectory;
|
|
BOOL fCreatedOk = false;
|
|
GUID GuidToFind;
|
|
|
|
LoadSxs();
|
|
GetSxsProc("SxsGenerateActivationContext", &pfnSxsGenerateActivationContext);
|
|
|
|
IFW32FALSE_EXIT(SxspParseGUID(GuidToDisplay, ::wcslen(GuidToDisplay), GuidToFind));
|
|
|
|
IFW32FALSE_EXIT(SourceManifestStream.OpenForRead(filename, CImpersonationData(), FILE_SHARE_READ, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN));
|
|
Parameters.Manifest.Path = filename;
|
|
Parameters.Manifest.PathType = ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE;
|
|
Parameters.Manifest.Stream = &SourceManifestStream;
|
|
|
|
IFW32FALSE_EXIT(AssemblyDirectory.Win32Assign(filename, ::wcslen(filename)));
|
|
AssemblyDirectory.RemoveLastPathElement();
|
|
Parameters.AssemblyDirectory = AssemblyDirectory;
|
|
Parameters.ProcessorArchitecture = 0;
|
|
Parameters.LangId = GetUserDefaultUILanguage();
|
|
|
|
fCreatedOk = pfnSxsGenerateActivationContext(&Parameters);
|
|
|
|
//
|
|
// Spiffy, we've got the thing.
|
|
//
|
|
if (fCreatedOk && (Parameters.SectionObjectHandle != INVALID_HANDLE_VALUE) && (Parameters.SectionObjectHandle != NULL))
|
|
{
|
|
PACTIVATION_CONTEXT pActivationContext = NULL;
|
|
NTSTATUS status;
|
|
ULONG_PTR ulCookie;
|
|
ACTCTX_SECTION_KEYED_DATA Data = { sizeof(Data) };
|
|
// PCACTIVATION_CONTEXT_DATA_CLR_SURROGATE pFoundData;
|
|
/*
|
|
status = RtlCreateActivationContext(
|
|
0,
|
|
Parameters.SectionObjectHandle,
|
|
0,
|
|
SimpleContextNotification,
|
|
NULL,
|
|
&pActivationContext);
|
|
*/
|
|
if (ActivateActCtx(static_cast<HANDLE>(pActivationContext), &ulCookie))
|
|
{
|
|
status = FindActCtxSectionGuid(
|
|
0,
|
|
NULL,
|
|
ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES,
|
|
&GuidToFind,
|
|
&Data);
|
|
DeactivateActCtx(0, ulCookie);
|
|
ReleaseActCtx(static_cast<HANDLE>(pActivationContext));
|
|
}
|
|
}
|
|
|
|
FN_EPILOG
|
|
}
|
|
|
|
void TestFindAndUseSurrogateInformation(PCWSTR pcwsz, PCWSTR GuidToDisplay)
|
|
{
|
|
ACTCTXW actctx = { sizeof(actctx) };
|
|
HANDLE hActCtx = INVALID_HANDLE_VALUE;
|
|
GUID GuidToFind;
|
|
ACTCTX_SECTION_KEYED_DATA Data = { sizeof(Data) };
|
|
PCACTIVATION_CONTEXT_DATA_CLR_SURROGATE pFoundData;
|
|
BOOL status;
|
|
ULONG_PTR ulCookie;
|
|
|
|
SxspParseGUID(GuidToDisplay, wcslen(GuidToDisplay), GuidToFind);
|
|
|
|
actctx.lpSource = pcwsz;
|
|
hActCtx = CreateActCtxW(&actctx);
|
|
|
|
if ((hActCtx == INVALID_HANDLE_VALUE) || (hActCtx == NULL))
|
|
{
|
|
printf("Sorry, can't find file %ls, error %d", pcwsz, ::GetLastError());
|
|
return;
|
|
}
|
|
|
|
ActivateActCtx(hActCtx, &ulCookie);
|
|
__try {
|
|
status = FindActCtxSectionGuid(
|
|
0,
|
|
NULL,
|
|
ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES,
|
|
&GuidToFind,
|
|
&Data);
|
|
|
|
pFoundData = (PCACTIVATION_CONTEXT_DATA_CLR_SURROGATE)Data.lpData;
|
|
|
|
wprintf(L"The guid %ls maps to assembly '%.*ls', runtime version '%.*ls', module '%.*ls'\n",
|
|
GuidToDisplay,
|
|
pFoundData->TypeNameLength / 2,
|
|
(PCWSTR)(((PBYTE)pFoundData) + pFoundData->TypeNameOffset),
|
|
pFoundData->VersionLength / 2,
|
|
(PCWSTR)(((PBYTE)pFoundData) + pFoundData->VersionOffset));
|
|
|
|
}
|
|
__finally
|
|
{
|
|
if (ulCookie != 0)
|
|
DeactivateActCtx(0, ulCookie);
|
|
}
|
|
|
|
ReleaseActCtx(hActCtx);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
TestSxsExportedSurrogateStuff(
|
|
PCWSTR pcwszManifest,
|
|
PCWSTR pcwszWhat,
|
|
PCWSTR pcwszData
|
|
)
|
|
{
|
|
FN_PROLOG_WIN32;
|
|
|
|
PFN_SXS_FIND_CLR_CLASS_INFO pfnClrClass = NULL;
|
|
PFN_SXS_FIND_CLR_SURROGATE_INFO pfnClrSurrogate = NULL;
|
|
PFN_SXS_LOOKUP_CLR_GUID pfnClrLookup = NULL;
|
|
SIZE_T cbRequired = 0;
|
|
BOOL f = false;
|
|
PVOID pvTargetBuffer = NULL;
|
|
PCSXS_CLR_SURROGATE_INFORMATION pSurrogateInfo = NULL;
|
|
PCSXS_CLR_CLASS_INFORMATION pClassInfo = NULL;
|
|
CFusionActCtxHandle hActCtxCreated;
|
|
CFusionActCtxScope ActivationScope;
|
|
ACTCTXW ActCtxStruct = {sizeof(ActCtxStruct)};
|
|
|
|
LoadSxs();
|
|
GetSxsProc(SXS_FIND_CLR_SURROGATE_INFO, &pfnClrSurrogate);
|
|
GetSxsProc(SXS_FIND_CLR_CLASS_INFO, &pfnClrClass);
|
|
GetSxsProc(SXS_LOOKUP_CLR_GUID, &pfnClrLookup);
|
|
|
|
IFW32FALSE_EXIT(MakeActCtxFromCurrentSxsDll(pcwszManifest, &hActCtxCreated));
|
|
IFW32FALSE_EXIT(ActivationScope.Win32Activate(hActCtxCreated));
|
|
|
|
if (lstrcmpiW(pcwszWhat, L"clrprogid") == 0)
|
|
{
|
|
f = pfnClrClass(
|
|
SXS_FIND_CLR_CLASS_SEARCH_PROGID | SXS_FIND_CLR_CLASS_GET_ALL,
|
|
(PVOID)pcwszData,
|
|
hActCtxCreated,
|
|
NULL, 0, &cbRequired);
|
|
|
|
if (!f)
|
|
{
|
|
SIZE_T cbWritten = 0;
|
|
pvTargetBuffer = HeapAlloc(GetProcessHeap(), 0, cbRequired);
|
|
pfnClrClass(
|
|
SXS_FIND_CLR_CLASS_SEARCH_PROGID | SXS_FIND_CLR_CLASS_GET_ALL,
|
|
(PVOID)pcwszData,
|
|
hActCtxCreated,
|
|
pvTargetBuffer,
|
|
cbRequired,
|
|
&cbWritten);
|
|
|
|
pClassInfo = (PCSXS_CLR_CLASS_INFORMATION)pvTargetBuffer;
|
|
}
|
|
}
|
|
else if (lstrcmpiW(pcwszWhat, L"clrguid") == 0)
|
|
{
|
|
GUID ParsedGuid;
|
|
IFW32FALSE_EXIT(SxspParseGUID(pcwszData, wcslen(pcwszData), ParsedGuid));
|
|
|
|
f = pfnClrClass(
|
|
SXS_FIND_CLR_CLASS_SEARCH_GUID | SXS_FIND_CLR_CLASS_GET_ALL,
|
|
(PVOID)&ParsedGuid,
|
|
hActCtxCreated,
|
|
NULL, 0, &cbRequired);
|
|
|
|
if (!f)
|
|
{
|
|
SIZE_T cbWritten = 0;
|
|
pvTargetBuffer = HeapAlloc(GetProcessHeap(), 0, cbRequired);
|
|
pfnClrClass(
|
|
SXS_FIND_CLR_CLASS_SEARCH_GUID | SXS_FIND_CLR_CLASS_GET_ALL,
|
|
(PVOID)&ParsedGuid,
|
|
hActCtxCreated,
|
|
pvTargetBuffer, cbRequired, &cbWritten);
|
|
|
|
pClassInfo = (PCSXS_CLR_CLASS_INFORMATION)pvTargetBuffer;
|
|
}
|
|
|
|
}
|
|
else if (lstrcmpiW(pcwszWhat, L"lookup") == 0)
|
|
{
|
|
GUID ParsedGuid;
|
|
PCSXS_GUID_INFORMATION_CLR pGuidInfo = NULL;
|
|
|
|
IFW32FALSE_EXIT(SxspParseGUID(pcwszData, wcslen(pcwszData), ParsedGuid));
|
|
|
|
f = pfnClrLookup(
|
|
SXS_LOOKUP_CLR_GUID_FIND_ANY,
|
|
&ParsedGuid,
|
|
hActCtxCreated,
|
|
NULL,
|
|
0,
|
|
&cbRequired);
|
|
|
|
if (!f)
|
|
{
|
|
SIZE_T cbWritten = 0;
|
|
pvTargetBuffer = HeapAlloc(GetProcessHeap(), 0, cbRequired);
|
|
|
|
f = pfnClrLookup(
|
|
SXS_LOOKUP_CLR_GUID_FIND_ANY,
|
|
&ParsedGuid,
|
|
hActCtxCreated,
|
|
pvTargetBuffer,
|
|
cbRequired,
|
|
&cbWritten);
|
|
|
|
pGuidInfo = (PCSXS_GUID_INFORMATION_CLR)pvTargetBuffer;
|
|
}
|
|
}
|
|
else if (lstrcmpiW(pcwszWhat, L"surrogate") == 0)
|
|
{
|
|
GUID ParsedGuid;
|
|
|
|
IFW32FALSE_EXIT(SxspParseGUID(pcwszData, wcslen(pcwszData), ParsedGuid));
|
|
|
|
f = pfnClrSurrogate(
|
|
SXS_FIND_CLR_SURROGATE_USE_ACTCTX | SXS_FIND_CLR_SURROGATE_GET_ALL,
|
|
&ParsedGuid,
|
|
hActCtxCreated,
|
|
NULL, 0, &cbRequired);
|
|
|
|
if (!f)
|
|
{
|
|
SIZE_T cbWritten = 0;
|
|
pvTargetBuffer = HeapAlloc(GetProcessHeap(), 0, cbRequired);
|
|
pfnClrSurrogate(
|
|
SXS_FIND_CLR_SURROGATE_USE_ACTCTX | SXS_FIND_CLR_SURROGATE_GET_ALL,
|
|
&ParsedGuid,
|
|
hActCtxCreated,
|
|
pvTargetBuffer, cbRequired, &cbWritten);
|
|
|
|
pSurrogateInfo = (PCSXS_CLR_SURROGATE_INFORMATION)pvTargetBuffer;
|
|
}
|
|
}
|
|
|
|
FN_EPILOG;
|
|
}
|
|
|
|
|
|
|