【问题标题】:Mixed C++/CLI code with Berkeley DB使用 Berkeley DB 的混合 C++/CLI 代码
【发布时间】:2011-08-08 15:05:47
【问题描述】:

我正在尝试在 C++/CLI 中以 /clr 模式使用 Berkeley DB。我写了这段代码:

编辑:

// DB_test1.cpp : main project file.

#include "stdafx.h"
#pragma comment(lib,"libdb51")
using namespace System;
using namespace System::Runtime::InteropServices;

int main(array<System::String ^> ^args)
{
    Db SigDb(0,0);
    unsigned int oFlags= DB_CREATE;
    SigDb.open(NULL,"SigDb.db",0,DB_BTREE,oFlags,0);
    String^ HexSig="D8B1048900ABFF8B";
    wchar_t* a=( wchar_t* )Marshal::StringToHGlobalUni(HexSig).ToPointer() ;
    wchar_t* A=( wchar_t* )Marshal::StringToHGlobalUni(HexSig).ToPointer();;

    Dbt key1(&a,100);
    Dbt data1(&A,100);

    Marshal::FreeHGlobal(IntPtr(A));
    int ret= SigDb.put(NULL,&key1,&data1, DB_NOOVERWRITE);
    if(ret==DB_KEYEXIST){
        Console::WriteLine("You are trying to insert an exist key!");
    }


    wchar_t DDData[200];
    Dbt getKey, getData;
    getKey.set_data(&a);

    getKey.set_size(100);
    getData.set_data(DDData);
    getData.set_ulen(200);
    getData.set_flags(DB_DBT_USERMEM);
    Marshal::FreeHGlobal(IntPtr(a));
    if(SigDb.get(NULL,&getKey,&getData,0)==DB_NOTFOUND)
        Console::WriteLine("Not Found !");
    else
        Console::WriteLine(" {0}",Marshal::PtrToStringUni((IntPtr)DDData));


    return 0;
}

代码编译成功,但输出错误。我只是将String^ HexSig="D8B1048900ABFF8B"; 存储在SigDb.db 中,然后直接读取相同的字符串并打印它!结果不像预期的那样看起来像D8B1048900ABFF8B,但它显示为随机字符串。有什么想法吗?

编辑后: 这段代码一直执行Console::WriteLine("Not Found !");

【问题讨论】:

    标签: database visual-c++ c++-cli berkeley-db mixed-mode


    【解决方案1】:

    我发现您的应用程序存在两个问题:

    1) 对 Marshal::FreeHGlobal 的两次调用是在使用缓冲区内容之前进行的。在 put 操作之后,您不应该释放“A”,并且在 put 和 get 操作之后,您不应该释放“a”。

    2) 您将指针存储在 Berkeley DB 中,而不是字符串本身。这是由于 Dbt 构造函数调用。你的申请是: dbt key1(&a,100); 它应该是: dbt key1(a, 100);

    getKey.set_data 方法也是如此——它应该使用指针,而不是对指针的引用。

    一旦我对您的应用程序进行了上述更改,它就会按预期运行。

    问候, 亚历克斯·戈罗德 甲骨文伯克利数据库

    【讨论】:

    • 非常感谢亚历克斯!按照你的笔记,问题已经解决了!
    【解决方案2】:

    您使用 Marshal::StringToHGlobalUni(),转换后的字符串是 wchar_t*,而不是 char*。具有以 utf16 编码的 Unicode 代码点的宽字符串。要获得 char*,您需要 StringToHGlobalAnsi()。

    请考虑这是一种有损转换,dbase 引擎已启用 Unicode 十多年了。另一个严重的问题是您没有释放为该字符串分配的内存,因此需要在 finally 块中调用 Marshal::FreeHGlobal()。您还应该在技术上使用 GlobalLock() 将返回的 HGLOBAL 转换为指针,考虑 Marshal::StringToCoTaskMemXxx。

    【讨论】:

    • @Hans 我做了一些你建议的修改,我在数据库中找不到字符串,它总是显示这段代码总是被执行Console::WriteLine("Not Found !");
    • 我可以帮助您找回它的可能性很小。如果你没有从 put() 得到错误返回,那么就写了一些东西。请注意,您的错误检查代码不正确,您只捕获 DB_KEYEXIST。
    • 我确信类似于String^ HexSig 的内容已写入数据库(或确切的String^ HexSig 内容)。我觉得问题在于读取参数,但我无法确定它到底在哪里!!
    • 你确实用 PtrToStringAnsi() 替换了 PtrToStringUni(),对吧?
    • 我已经请我们的一位 C++ 工程师来看看这个问题。将来,您可能希望在 BDB 论坛bit.ly/eIREhr 上发布此类问题,那里有很多 BDB 用户、开发和支持工程师在关注论坛。
    猜你喜欢
    • 1970-01-01
    • 2011-12-03
    • 1970-01-01
    • 2014-04-15
    • 2011-08-30
    • 1970-01-01
    • 1970-01-01
    • 2020-03-29
    相关资源
    最近更新 更多