I'm traying to use Berkeley DB in C++/CLI with /clr
mode. I wrote this code:
我正在使用c++ /clr模式使用Berkeley DB。我写的这段代码:
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?
代码编译成功,但输出错误。我只是盛盘存储字符串^ HexSig =“D8B1048900ABFF8B”;在SigDb。然后直接读取相同的字符串并打印出来!结果不像预期的那样显示为D8B1048900ABFF8B,但它显示为一个随机字符串。什么好主意吗?
After Editing: This segment of code is always executed Console::WriteLine("Not Found !");
编辑后:此段代码始终执行控制台::WriteLine(“Not Found !”);
2 个解决方案
#1
2
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.
1)两个调用Marshal::FreeHGlobal是在使用缓冲区的内容之前生成的。你不应该在put操作之后释放A,也不应该在put操作和get操作之后释放A。
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);
2)您是在Berkeley DB中存储指针,而不是在字符串本身中存储指针。这是由于Dbt构造函数调用。您的应用程序是:Dbt key1(&a,100);应该是:Dbt key1(a, 100);
Similarly for the getKey.set_data method - it should use the pointer, not a reference to the pointer.
getKey类似。set_data方法——它应该使用指针,而不是指针的引用。
Once I made the above changes to your application, it ran as expected.
一旦我对您的应用程序做了上述更改,它就会按预期运行。
Regards, Alex Gorrod Oracle Berkeley DB
问候,Alex Gorrod Oracle Berkeley DB
#2
1
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().
您可以使用Marshal: StringToHGlobalUni(),转换后的字符串是wchar_t*,而不是char*。在utf16中编码的Unicode编码点的宽字符串。要获得char*,需要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.
考虑一下这是一个有损的转换,dbase引擎已经在十多年前启用了Unicode。另一个严重的问题是,您没有释放为这个字符串分配的内存,因此需要在最终块中调用Marshal::FreeHGlobal()。您还应该从技术上使用GlobalLock()将返回的HGLOBAL转换为指针,考虑Marshal: StringToCoTaskMemXxx。
#1
2
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.
1)两个调用Marshal::FreeHGlobal是在使用缓冲区的内容之前生成的。你不应该在put操作之后释放A,也不应该在put操作和get操作之后释放A。
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);
2)您是在Berkeley DB中存储指针,而不是在字符串本身中存储指针。这是由于Dbt构造函数调用。您的应用程序是:Dbt key1(&a,100);应该是:Dbt key1(a, 100);
Similarly for the getKey.set_data method - it should use the pointer, not a reference to the pointer.
getKey类似。set_data方法——它应该使用指针,而不是指针的引用。
Once I made the above changes to your application, it ran as expected.
一旦我对您的应用程序做了上述更改,它就会按预期运行。
Regards, Alex Gorrod Oracle Berkeley DB
问候,Alex Gorrod Oracle Berkeley DB
#2
1
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().
您可以使用Marshal: StringToHGlobalUni(),转换后的字符串是wchar_t*,而不是char*。在utf16中编码的Unicode编码点的宽字符串。要获得char*,需要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.
考虑一下这是一个有损的转换,dbase引擎已经在十多年前启用了Unicode。另一个严重的问题是,您没有释放为这个字符串分配的内存,因此需要在最终块中调用Marshal::FreeHGlobal()。您还应该从技术上使用GlobalLock()将返回的HGLOBAL转换为指针,考虑Marshal: StringToCoTaskMemXxx。