与 Berkeley DB 混合的 C++/CLI 代码

发布于 2024-11-02 09:36:07 字数 1624 浏览 5 评论 0原文

我打算在 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 !");

I'm traying to use Berkeley DB in C++/CLI with /clr mode. I wrote this code:

Edit:

// 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;
}

The code is compiled successfully but it shows wrong output. I am just traying to store String^ HexSig="D8B1048900ABFF8B"; in SigDb.db and then directly read the same string and print it!. The result does not appear like D8B1048900ABFF8B as it expected, but it appears as a random string. Any ideas?

After Editing:
This segment of code is always executed Console::WriteLine("Not Found !");

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

赠意 2024-11-09 09:36:07

我可以看到您的应用程序存在两个问题:

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

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

类似地,对于 getKey.set_data 方法 - 它应该使用指针,而不是对指针的引用。

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

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

I can see two issues with your application:

1) The two calls to Marshal::FreeHGlobal are made before the contents of the buffers are used. You shouldn't free 'A' until after the put operation, and you shouldn't free 'a' until after both the put and get operations.

2) You are storing the pointers in Berkeley DB, rather than the strings themselves. That's due to the Dbt constructor calls. You're application is:
Dbt key1(&a,100);
It should be:
Dbt key1(a, 100);

Similarly for the getKey.set_data method - it should use the pointer, not a reference to the pointer.

Once I made the above changes to your application, it ran as expected.

Regards,
Alex Gorrod
Oracle Berkeley DB

一向肩并 2024-11-09 09:36:07

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

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

You use Marshal::StringToHGlobalUni(), the converted string is a wchar_t*, not a char*. A wide string with the Unicode codepoints encoded in utf16. To get a char* you need StringToHGlobalAnsi().

Do consider that this is a lossy conversion, dbase engines have been Unicode enabled for well over a decade now. Another serious problem is that you don't release the memory allocated for this string, calling Marshal::FreeHGlobal() in a finally block is required. You also should technically use GlobalLock() to convert the returned HGLOBAL to a pointer, consider Marshal::StringToCoTaskMemXxx.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文