Mixed C++/CLI code with Berkeley DB
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=( wch开发者_JAVA百科ar_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 !");
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
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.
精彩评论