【问题标题】:Win32 C++ DLL function gets garbage values in parametersWin32 C++ DLL 函数获取参数中的垃圾值
【发布时间】:2014-05-26 14:14:14
【问题描述】:

我有一个调用另一个 Win32 C++ dll (B) 的 Win32 C++ dll (A)。 (B) 使用 LoadLibrary 加载并包含一个方法:

Draw(HDC hDC, LPRECT lpRect, LPBUFFER buffer, LPOPTIONS options)

缓冲区结构定义为:

struct Buffer
{
    char*           pData;
    long            Length;
    TCHAR           FileName[MAX_PATH];
    Extension       Extension;
};

typedef Buffer BUFFER, *LPBUFFER;

(A) 用文件名、长度等填充 BUFFER 并调用 Draw 函数。然后,Draw 函数使用来自 BUFFER 的值。当 DLL 编译为 64 位时一切正常,但如果我将它们编译为 32 位,那么我开始在 (B) 中的 BUFFER 字段中获取垃圾值。日志显示(A)中的值很好,但当它们到达(B)时变成垃圾。

我尝试更改结构对齐选项 /ZpX 和 Draw 方法的调用约定(__cdecl、__stdcall),但没有任何帮助。我认为这与调用约定有关,因为如果我更改 Draw 函数语法并将 BUFFER 作为第一个参数,那么 (B) 将获得正确的值。这是怎么回事?

函数指针类型:

typedef bool (__cdecl *DrawFunc)(HDC hDC, LPRECT lpRect, LPBUFFER buffer, LPOPTIONS options);

然后在 InitInstance 中:

pDrawFunc = (DrawFunc)GetProcAddress(dllHandle, "Draw");

更新
1. 如上所述,如果我将 BUFFER 作为第一个参数,那么它会收到正确的值。
2. HDC 是一个单一的数值总是得到正确的值
3. RECT 得到不正确的值,非常大的值

我认为问题与结构有关。只有结构得到不正确的值。

更新 2
好的,我发现了我自己的愚蠢错误,Draw 方法的声明有 LPRECT,而实现有 RECT。我的错,对此感到抱歉。
但我仍然不确定为什么:
1.其他参数显示垃圾值?
2. 为什么它在 64 位下工作?

【问题讨论】:

  • 你确定这两个 dll 都是 32 位的吗?
  • LPBUFFER 是如何定义的?如何声明和初始化函数指针类型和实例?
  • @user2451677:是的,因为在 32 位环境中加载和写入文件日志。 64 位系统无法在 32 位 Windows 上加载。
  • @MichaelUrman:我已经更新了问题。
  • 如果没有诊断问题的方法,没有人能真正提供帮助。请出示 SSCCE。简化的 DLL 源代码和简化的调用代码。我们试图猜测这一点没有多大意义。

标签: c++ dll cross-platform calling-convention


【解决方案1】:

好的,我创建了一个包含 3 个项目的解决方案:库 B,包含 Draw(),库 A,包含 Test(),加载库 B 并使用一些 Buffer* 和应用程序测试调用 Draw(),链接使用库 A 并调用 Test()。对于 32 位和 64 位,一切正常。Test() 的小 sn-p:

#include "stdafx.h"
#include "A.h"
#include "../B/B.h"

namespace {
LPBUFFER CreateBuffer(const char* const data, LPCTSTR const name)
{
    if(!data || !name)
        return NULL;

    LPBUFFER buffer = new BUFFER();
    buffer->Length = static_cast<long>(strlen(data) + 1);
    buffer->pData = new char[buffer->Length];
    strcpy_s(buffer->pData, buffer->Length * sizeof(char), data);
    buffer->Extension = 0;
    ::ZeroMemory(buffer->FileName, _countof(buffer->FileName) * sizeof(TCHAR));
    _tcscpy_s(buffer->FileName, name);
    return buffer;
}

void DestroyBuffer(LPBUFFER buffer)
{
    delete [] buffer->pData;
    buffer->Length = 0;
    buffer->pData = NULL;
    buffer->Extension = 0;
    ::ZeroMemory(buffer->FileName, _countof(buffer->FileName) * sizeof(TCHAR));
    delete buffer;
}
} // namespace

A_API void Test()
{
    HMODULE b_lib = ::LoadLibrary(_T("B.dll"));
    if(!b_lib)
    {
        ::OutputDebugString(_T("Can't load library\n"));
        return;
    }

    typedef bool (*DrawFunction)(HDC hDC, LPRECT lpRect, LPBUFFER buffer, LPOPTIONS options);
    DrawFunction draw = reinterpret_cast<DrawFunction>(::GetProcAddress(b_lib, "Draw"));
    if(!draw)
    {
        ::OutputDebugString(_T("Can't get address of Draw()"));
        goto FINISH_LABEL;
    }

    LPBUFFER buffer = CreateBuffer("test", _T("path"));
    draw(NULL, NULL, buffer, NULL);
    DestroyBuffer(buffer);

FINISH_LABEL:
    ::FreeLibrary(b_lib);
    b_lib = NULL;
}

还有一个完整的解决方案:https://www.dropbox.com/s/5ei6ros9e8s94e2/B.zip

【讨论】:

  • 第一个参数总是得到正确的值。它的第二个及以上 STRUCT 参数包含垃圾。
  • 我不知道 - 适合我
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-07
  • 1970-01-01
  • 2019-04-29
  • 2011-06-05
  • 1970-01-01
相关资源
最近更新 更多