我正在编写各种调用相对复杂的 Win32 API 函数的东西。这是一个例子:
//Encapsulates calling NtQuerySystemInformation buffer management.
WindowsApi::AutoArray NtDll::NtQuerySystemInformation(
SystemInformationClass toGet ) const
{
AutoArray result;
ULONG allocationSize = 1024;
ULONG previousSize;
NTSTATUS errorCheck;
do
{
previousSize = allocationSize;
result.Allocate(allocationSize);
errorCheck = WinQuerySystemInformation(toGet,
result.GetAs<void>(), allocationSize, &allocationSize);
if (allocationSize <= previousSize)
allocationSize = previousSize * 2;
} while (errorCheck == 0xC0000004L);
if (errorCheck != 0)
{
THROW_MANUAL_WINDOWS_ERROR(WinRtlNtStatusToDosError(errorCheck));
}
return result;
}
//Client of the above.
ProcessSnapshot::ProcessSnapshot()
{
using Dll::NtDll;
NtDll ntdll;
AutoArray systemInfoBuffer = ntdll.NtQuerySystemInformation(
NtDll::SystemProcessInformation);
BYTE * currentPtr = systemInfoBuffer.GetAs<BYTE>();
//Loop through the results, creating Process objects.
SYSTEM_PROCESSES * asSysInfo;
do
{
// Loop book keeping
asSysInfo = reinterpret_cast<SYSTEM_PROCESSES *>(currentPtr);
currentPtr += asSysInfo->NextEntryDelta;
//Create the process for the current iteration and fill it with data.
std::auto_ptr<ProcImpl> currentProc(ProcFactory(
static_cast<unsigned __int32>(asSysInfo->ProcessId), this));
NormalProcess* nptr = dynamic_cast<NormalProcess*>(currentProc.get());
if (nptr)
{
nptr->SetProcessName(asSysInfo->ProcessName);
}
// Populate process threads
for(ULONG idx = 0; idx < asSysInfo->ThreadCount; ++idx)
{
SYSTEM_THREADS& sysThread = asSysInfo->Threads[idx];
Thread thread(
currentProc.get(),
static_cast<unsigned __int32>(sysThread.ClientId.UniqueThread),
sysThread.StartAddress);
currentProc->AddThread(thread);
}
processes.push_back(currentProc);
} while(asSysInfo->NextEntryDelta != 0);
}
我的问题是模拟 NtDll::NtQuerySystemInformation
方法——也就是说,返回的数据结构很复杂(好吧,这里它实际上相对简单,但也可能很复杂),然后编写像 API 调用那样构建数据结构的测试所花费的时间是编写使用 API 的代码的 5-6 倍。
我想做的是调用 API,并以某种方式记录它,这样我就可以将记录的值返回给被测代码,而无需实际调用 API。返回的结构不能简单地被 memcpy,因为它们通常包含内部指针(指向同一缓冲区中其他位置的指针)。有问题的库需要检查这些类型的东西,并能够在重放时将指针值恢复到类似的缓冲区。 (即检查每个指针大小的值是否可以解释为缓冲区内的指针,将其更改为偏移量,并记住在重播时将其更改回指针——此处的误报率是可以接受的)
有没有什么东西可以做这样的事情?
最佳答案
手工实现真的那么难吗?
#include <stddef.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
typedef char BYTE;
//Note: Buffer is MODIFIED after this call (hence why it's not const)! Don't re-use it!
void saveBuffer(FILE* stream, BYTE* buffer, size_t bufferSize)
{
assert(bufferSize % sizeof(void*) == 0);
fwrite(&bufferSize, sizeof(bufferSize), 1, stream);
for (size_t i = 0; i < bufferSize - sizeof(void*) + 1; i += sizeof(void*))
{
void** pAsPointer = (void**)&buffer[i];
if (*pAsPointer >= buffer && *pAsPointer < buffer + bufferSize)
{
fwrite(&i, sizeof(i), 1, stream);
*pAsPointer = pAsPointer;
}
}
void* null = NULL;
fwrite(&null, sizeof(null), 1, stream); //Null-terminator
fwrite(buffer, 1, bufferSize, stream);
}
size_t loadBuffer(FILE* stream, BYTE* buffer, size_t bufferCapacity) //Buffer size is in stream
{
size_t bufferSize;
fread(&bufferSize, sizeof(bufferSize), 1, stream);
if (bufferSize >= bufferCapacity)
{
memset(buffer, 0, bufferSize);
for (;;)
{
size_t pointerOffset;
fread(&pointerOffset, sizeof(pointerOffset), 1, stream);
if (pointerOffset != 0)
{ *(size_t*)&buffer[pointerOffset] = (size_t)buffer + pointerOffset; }
else { break; }
}
for (size_t i = 0; i < bufferSize; i += sizeof(void*))
{
if (*(void**)&buffer[i] == NULL)
{ fread(&buffer[i], sizeof(size_t), 1, stream); }
}
}
return bufferSize;
}
(抱歉,我还没有测试它,但它应该非常接近工作。)
唯一的问题是假设所有可能是指针的值实际上都是指针,但除此之外,它看起来很简单。
关于c++ - 是否有可以轻松记录和重放 API 调用结果的库?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4638553/