2011-04-19 2 views
1

/clr 모드의 C++/CLI에서 버클리 DB를 사용하고 있습니다.버클리 DB와 혼합 된 C++/CLI 코드

편집 :

// 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처럼 나타나지 않지만 임의의 문자열로 나타납니다. 어떤 아이디어? 편집 후

: 는이 코드 세그먼트는 항상

답변

2

난 당신의 응용 프로그램과 함께이 문제를 볼 수 있습니다. put 연산이 끝날 때까지 'A'를 해제하면 안되며, put 및 get 연산이 끝날 때까지 'a'를 해제하면 안됩니다.

2) 문자열 자체가 아닌 Berkeley DB에 포인터를 저장하고 있습니다. 그것은 Dbt 생성자 호출 때문입니다. 응용 프로그램 : Dbt key1 (& a, 100); 다음과 같아야합니다. Dbt key1 (a, 100);

getKey.set_data 메소드와 마찬가지로 - 포인터에 대한 참조가 아니라 포인터를 사용해야합니다.

위의 변경 사항을 응용 프로그램에 적용하면 예상대로 실행됩니다.

감사합니다, 알렉스 Gorrod 오라클 버클리 DB

+0

Alex 대단히 감사합니다. 당신의 노트를 따라 가면서 문제가 해결되었습니다! – Aan

1

당신은 원수 :: StringToHGlobalUni를 (사용 Console::WriteLine("Not Found !");를) 실행되고, 변환 된 문자열은 wchar_t를의 *가 아닌 문자 *입니다. utf16으로 인코딩 된 유니 코드 코드 포인트가있는 넓은 문자열입니다. char *를 얻으려면 StringToHGlobalAnsi()가 필요합니다.

dbase 엔진은 10 년 동안 유니 코드를 사용할 수있게되었으므로 손실 변환이라고 생각하십시오. 또 다른 심각한 문제는이 문자열에 할당 된 메모리를 해제하지 않고 finally 블록에서 Marshal :: FreeHGlobal()을 호출해야한다는 것입니다. 기술적으로 GlobalLock()을 사용하여 반환 된 HGLOBAL을 포인터로 변환해야합니다. Marshal :: StringToCoTaskMemXxx를 고려하십시오.

1) 버퍼의 내용이 사용되기 전에 만들어진 원수 :: FreeHGlobal에 두 통화 :

+0

@Hans 난 당신이 제안하고 난 데이터베이스에서 문자열을 찾을 수있는 몇 가지 수정, 항상이 코드 세그먼트는 항상 실행 표시했다'콘솔 ::를 WriteLine ("찾을 수 없습니다!"); ' – Aan

+0

당신이 그것을 찾는데 도움이 될 확률은 거의 없습니다. put()에서 오류가 반환되지 않으면 무언가가 작성되었습니다. 오류 검사 코드가 좋지 않음을 유의하십시오. DB_KEYEXIST 만 트랩합니다. –

+0

'String^HexSig'의 내용과 비슷한 것이 데이터베이스 (또는 정확한'String^HexSig' 내용)에 쓰여졌을 것입니다. 나는 문제가 독서 매개 변수에 있다고 느낀다. 그러나 나는 그것이 정확히 어디인지를 판별 할 수 없다 !! – Aan