XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
param([string]$OutputDirectory='artifacts/plugin-handshake-test')
$ErrorActionPreference='Stop'
$taskRoot=Split-Path -Parent $PSScriptRoot
$taskFolder=[IO.Path]::GetFullPath((Join-Path $taskRoot $OutputDirectory))
if(-not $taskFolder.StartsWith($taskRoot+[IO.Path]::DirectorySeparatorChar,[StringComparison]::OrdinalIgnoreCase)){throw 'The fixture must stay within this workspace.'}
New-Item -ItemType Directory -Path $taskFolder -Force | Out-Null
$taskHost=Join-Path $taskFolder 'EliteDangerous64.exe'
$taskSource=Join-Path $taskFolder 'host.cpp'
@'
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <unknwn.h>
#include <string>
#include <initializer_list>
int wmain(int argc,wchar_t** argv) {
    if(argc!=2)return 2;
    const auto module=LoadLibraryW(argv[1]);if(!module)return 3;
    using Create=HRESULT(WINAPI*)(HINSTANCE,DWORD,REFIID,LPVOID*,LPUNKNOWN);
    const auto create=reinterpret_cast<Create>(GetProcAddress(module,"DirectInput8Create"));if(!create)return 4;
    wchar_t system[MAX_PATH]{};GetSystemDirectoryW(system,MAX_PATH);
    const auto genuine=LoadLibraryExW((std::wstring(system)+L"\\dinput8.dll").c_str(),nullptr,LOAD_LIBRARY_SEARCH_SYSTEM32);if(!genuine)return 5;
    const auto baseline=reinterpret_cast<Create>(GetProcAddress(genuine,"DirectInput8Create"));if(!baseline)return 6;
    struct Result{HRESULT result;DWORD last;bool output;};
    auto call=[](Create function,DWORD version,DWORD seed){
        void* output{};SetLastError(seed);
        const auto result=function(GetModuleHandleW(nullptr),version,__uuidof(IUnknown),&output,nullptr);
        const auto error=GetLastError();const bool returned=output!=nullptr;
        if(output)reinterpret_cast<IUnknown*>(output)->Release();
        return Result{result,error,returned};
    };
    for(const DWORD version:{0x800u,0u}){
        const auto expected=call(baseline,version,0x5A5A1234);
        const auto actual=call(create,version,0x5A5A1234);
        if(expected.result!=actual.result||expected.last!=actual.last||expected.output!=actual.output)return 7;
    }
    Sleep(20000);return 0;
}
'@ | Set-Content -LiteralPath $taskSource -Encoding utf8
$taskVs=& 'C:/Program Files (x86)/Microsoft Visual Studio/Installer/vswhere.exe' -latest -products '*' -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
$taskBatch=Join-Path $taskFolder 'build.cmd'
[IO.File]::WriteAllText($taskBatch,"@call `"$taskVs\VC\Auxiliary\Build\vcvars64.bat`" >nul`r`n@cl /nologo /std:c++20 /O2 /MT /EHsc `"$taskSource`" /Fo`"$taskFolder\host.obj`" /link /OUT:`"$taskHost`" ole32.lib`r`n@exit /b %ERRORLEVEL%`r`n")
& $env:ComSpec /d /c $taskBatch
if($LASTEXITCODE -ne 0){throw 'Fixture build failed.'}
$taskDll=Join-Path $taskRoot 'artifacts/plugin-build/dinput8.dll'
if(-not (Test-Path -LiteralPath $taskDll -PathType Leaf)){throw 'Build the diagnostic loader first: scripts/Build-Plugin.ps1 -ExportDiagnostics.'}
$taskProcess=Start-Process -FilePath $taskHost -ArgumentList @(('"'+$taskDll+'"')) -WindowStyle Hidden -PassThru
$taskReplies=@()
try {
    for($taskIndex=0;$taskIndex -lt 23;$taskIndex++) {
        $taskPipe=[IO.Pipes.NamedPipeClientStream]::new('.','XFEEDToolBox.Plugin.'+$taskProcess.Id,[IO.Pipes.PipeDirection]::InOut,[IO.Pipes.PipeOptions]::Asynchronous)
        try {
            $taskPipe.Connect(2000)
            $taskText=switch($taskIndex){20{"navigation.observe.start`n"}21{"deactivate`n"}default{"status`n"}}
            $taskCommand=[Text.Encoding]::UTF8.GetBytes($taskText);$taskPipe.Write($taskCommand,0,$taskCommand.Length);$taskPipe.Flush()
            $taskReader=[IO.StreamReader]::new($taskPipe,[Text.Encoding]::UTF8,$false,4096,$true)
            $taskJson=$taskReader.ReadLineAsync().WaitAsync([TimeSpan]::FromSeconds(2)).GetAwaiter().GetResult()
            $taskReply=$taskJson|ConvertFrom-Json
            if($taskReply.processId -ne $taskProcess.Id -or -not $taskReply.loaded -or $taskReply.active -ne ($taskIndex -lt 21) -or $taskReply.observationStarted -or $taskReply.supportsNavigation -or $taskReply.supportsTrade -or $taskReply.supportsRelog){throw 'Unexpected fixture capability or identity.'}
            $taskReplies+=$taskReply
        } finally {$taskPipe.Dispose()}
    }
    [ordered]@{fixtureExecutable=$taskHost;pluginSha256=(Get-FileHash -LiteralPath $taskDll -Algorithm SHA256).Hash;version=$taskReplies[0].version;statusReplies=20;lifecycleReplies=3;directInputReturnAndLastErrorMatched=$true;passed=$true;commands=@('status','navigation.observe.start','deactivate','status');actualGameTouched=$false}|ConvertTo-Json|Set-Content -LiteralPath (Join-Path $taskFolder 'result.json') -Encoding utf8
    Get-Content -LiteralPath (Join-Path $taskFolder 'result.json')
} finally {
    $taskObserved=Get-Process -Id $taskProcess.Id -ErrorAction SilentlyContinue
    if($taskObserved -and [string]::Equals($taskObserved.Path,$taskHost,[StringComparison]::OrdinalIgnoreCase)){Stop-Process -Id $taskObserved.Id -ErrorAction SilentlyContinue}
}