如何为通过地址传递参数的Windows API调用编写测试双精度

How to write test doubles for Windows API calls that pass arguments by address

本文关键字:调用 API Windows 双精度 测试 参数 地址 址传      更新时间:2023-10-16

我有一些可用的模拟类来代替对Windows API的实际调用。然而,我正在努力为使用FORMAT_MESSAGE_ALLOCATE_BUFFER标志时使用FormatMessageW的功能组合一些东西。

当使用FormatMessageW函数时,我首先声明我的缓冲区如下:

wchar_t * buffer = nullptr;

然后我通过地址传递缓冲区作为lpBuffer参数(预期类型是LPWSTR):

reinterpret_cast<::LPWSTR>(&buffer)

Windows API函数将自动创建一个正确大小的缓冲区。

我通过剥离换行符,从宽字符转换为多字节字符等来进一步处理缓冲区。

为了对输出缓冲区的清理进行完整的单元测试,我试图通过让函数简单地返回一个预定义的字符串(它将是模拟对象的成员)来模拟FormatMessageW调用。

为了简化问题,下面的代码试图复制我的问题:

// represents my mock class
class mocker
{
public:
    // takes a wchar_t pointer and attempts to reassign it
    int mockFunction(wchar_t * buffer)
    {
        // assigns local copy of wchar_t pointer!
        buffer = &message[0];
        return message.length();
    }
protected:
    std::wstring message = L"test";
};
// test code
mocker mocking;
wchar_t * buffer = nullptr;
auto size = mocking.mockFunction(&buffer);
// at this point buffer is still null
// but I want the buffer to point to L"test"

是否有一种方法可以实现我的目标重定向指针到现有的std::wstring而不改变int mockFunction(wchar_t * buffer)的实现?

您需要的可能是使用FORMAT_MESSAGE_ALLOCATE_BUFFER选项的此方法。您可以在这里找到该选项的示例用法:

https://support.microsoft.com/en-us/kb/256348

内容如下:

HLOCAL pBuffer;   // Buffer to hold the textual error description.
// .... 
ret = FormatMessage( 
                FORMAT_MESSAGE_ALLOCATE_BUFFER | // Function will handle memory allocation.
                FORMAT_MESSAGE_FROM_HMODULE | // Using a module's message table.
                FORMAT_MESSAGE_IGNORE_INSERTS, 
                hInst, // Handle to the DLL.
                dwErrorMsgId, // Message identifier.
                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language.
                (LPTSTR)&pBuffer, // Buffer that will hold the text string.
                ERRMSGBUFFERSIZE, // Allocate at least this many chars for pBuffer.
                NULL // No insert values.
                    );

HLOCAL定义为typedef HANDLE HLOCAL;, HANDLE定义为typedef void *HANDLE;。所以在上面的例子中,&pBuffer返回指针指向指针,然后将其强制转换为LPTSTR,这也是一个指针。在FormatMessage内部,检查是否使用了FORMAT_MESSAGE_ALLOCATE_BUFFER,如果使用了,则将buffer参数(可能)、HLOCAL* pToAllocBuffer = reinterpret_cast<HLOCAL*>(buffer)以及后来的*pToAllocBuffer = LocalAlloc(.....)进行类型转换。

所以,在你的mockFunction内部,你也必须做这样丑陋的类型转换,首先:

wchar_t * buffer = nullptr;
auto size = mocking.mockFunction(reinterpret_cast<wchar_t * >(&buffer));

and inside mockFunction:

wchar_t ** buffer = reinterpret_cast<wchar_t ** >(buffer);

现在你可以像这样分配内存给缓冲区:

*buffer = [HERE YOUR ALLOCATION];

不要这样做:

//分配wchar_t指针的本地副本…

如果你分配本地拷贝,它将在函数返回时被释放,你必须使用new

多亏了marcinj的回答,我能够通过使用以下实现实现我的目标:

int mockFunction(wchar_t * buffer)
{
    wchar_t ** bufferPointer = reinterpret_cast<wchar_t **>(buffer);
    *bufferPointer = &message[0];
    return message.length();
}

当我在工作模拟类中实现这一点时,我将wchar_t *替换为LPWSTR