与 Berkeley DB 混合的 C++/CLI 代码
我打算在 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我可以看到您的应用程序存在两个问题:
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
您使用 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.