c#에서 인코딩을 바꿔서 넣어줘야 한다

전 글의 1번 예제 중에서 이 부분을 수정했다

private IntPtr Prepare(string query)

    {

      IntPtr stmHandle;


      byte[] str = System.Text.Encoding.GetEncoding("euc-kr").GetBytes(query);


      fixed (byte* p_str = str)

      {

          if (sqlite3_prepare_v2(_db, p_str, str.Length,

            out stmHandle, IntPtr.Zero) != SQLITE_OK)

              throw new SQLiteException(sqlite3_errmsg(_db));

      }

      return stmHandle;

    }


원 코드는 query를 그대로 입력했다. 영문의 경우에는 문제가 없으나 한글은 문제가 생긴다. 가장 큰 이유는 한글은 2바이트로 작성되어 길이가 맞지 않는다는 점


예를 들어

string query = "abcd가나다";

query.length 는 7로 나온다

그러나 C쪽으로 가면 얘는 10바이트가 된다

3바이트 차이가 난다 (한글 문자 개수)


고로 인코딩을 사용해 직접 char 혹은 byte 배열로 보내줘야 한다.

길이도 원문 길이가 아니라 인코딩을 변환한 byte 배열 크기로 보내주면 문제 없다.




에러 문제


좀 귀찮다. 방법은 의외로 어렵지는 않았다.

내가 현재 vs2010을 사용하는데 이 프로젝트는 08년도 제작되었다. 그걸 따져본다면 vs2008 이전 버전으로 제작되었다는 말이다. 그래서 차이가 생긴게 아닌가 싶다.


일단 디버깅 안 되는 문제 자체는 프로젝트 옵션의 디버그에서 비관리 코드 디버깅 사용을 체크하니까 해결되었다. 그러나 이게 실질적인 문제는 아니라고 본다. (아래 서술함)


이놈의 dll 연결 함수가 죄다 string으로 되어 있다. 그러나  실제 소스를 확인하면 (당연하겠지만) 포인터로 되어 있다. 이게 문제다. 이전 버전은 모르겠지만 2010은 이런데 엄격한가보다. 그래서 죄다 오류를 띄운다.


조금 번거롭지만 다음의 과정을 전부 행해야 한다

1. dll 함수 중에서 입력 변수 혹은 반환 타입이 string으로 되어 있는 함수를 모두 체크한다

2. 전부 다 포인터로 변경한다. (나는 byte*을 자주 쓴다)

3. 이에 맞도록 데이터를 수정한다.

string->byte->byte* (입력시)

byte*->byte->string (출력시)


ExecuteQuery 함수 내부에 이런 것이 있다.


dTable.Columns.Add(sqlite3_column_origin_name(stmHandle, i));


요거 오류나는 부분 중의 하나다. 근데 실행 되긴 된다. sqlite3_column_origin_name의 반환 형식이 string이라서 실행은 된다. 다만 기본 상태에서는 디버깅이 되지 않고, 비관리 코드 디버깅 체크해도 이 부분에서 에러 뜨면서 걸린다. (디버깅 안하고 하면 실행되긴 된다)


이 부분을 다음과 같이 수정하니 일단 에러는 안 걸린다

byte* b_ori = sqlite3_column_origin_name(stmHandle, i);

          List<byte> b_array = new List<byte>();


          for (int j = 0; b_ori[j] != 0; j++)

          {

              b_array.Add(b_ori[j]);

          }


          string str = System.Text.Encoding.GetEncoding

("euc-kr").GetString(b_array.ToArray());


          dTable.Columns.Add(str);


더 좋은 방법이 있을 수도 있겠지만 일단 이런 식으로 해놨다. 반복 사용을 염두에 둔다면 이 부분만 빼서 함수로 만들어도 되니까.


여튼 string이 직접 dll과 연결되지 않도록 죄다 수정해야 한다. 입력은 맨 위의 예제같이, 출력은 바로 위 예제같이 다 수정해 준다.


수정이 전부 끝났는지 확인해보는 방법

프로젝트 옵션의 디버그에서 비관리 코드 디버깅 사용 해제해도 제대로 디버깅이 되면 수정이 제대로 끝난 것이다



여담 

- 사실 방법만 아니까 그리 어렵진 않다. 예제 코드도 생각보단 짧고 간단하다. 어차피 래핑 밖에 안되서 그럴지도 모르지만

- 웹이라서 그런건지는 모르겠는데 작성자 코드 스타일이 좀 내 맘에는 안 든다. 엔터가 많고, 한줄짜리 if문 뒤의 명령문은 중괄호 안친다. 그래서 좀 헷갈렸다

- 수정한거는 일단 첨부함

SQLite.cs

참고로 위 파일은 예제 파일에서 그냥 테스트해보고 올린거라 몇가지 사소한 문제가 있을 수 있다. 닷넷 버전때문에 dll 호출 구문을 다음과 같이 수정해야 할 수도 있다. (위 파일에는 적용되어 있지 않음)


[DllImport("sqlite3.dll", EntryPoint = "sqlite3_column_double")]

를 아래와 같이 수정한다

[DllImport("sqlite3.dll", CallingConvention = CallingConvention.Cdecl)]


'Programming > C#' 카테고리의 다른 글

c# - c dll 디버깅시 주의할 점  (0) 2013.12.20
c# 문자열에서 문자 개수 알아내기  (0) 2013.12.19
C# 타이머 사용 예제  (0) 2013.12.10
C#에서 User Control 만들기  (0) 2013.11.12
c#에서 SQLite 한글 사용하기 -1-  (0) 2013.11.05
Posted by Vermond
:

단순하게 쓸거면 다음의 사이트도 괜찮다

http://system.data.sqlite.org/index.html/doc/trunk/www/index.wiki


c#에서만 입출력하게 만들거면 위의거 써도 상관없다


문제는 지금 c와 c#에서 동시에 접근해야 하는데 이 경우 어느 한쪽이 깨져서 나온다는 점이다. c에서 넣은건 c#에서 깨지고 c#에서 넣은건 c에서 깨진다. 기본 제공되는 커맨드라인 툴을 사용해서 확인하면 c#이 깨진 걸로 나온다.


인코딩 변환 문제라고 의심해서 직접 c에서 단문을 한글로 쳐서 바이트 확인한 다음에 직접 바이트 배열 만들어서 변환한 다음에 넣어주었다. 그래도 여전히 문제가 생긴다.


http://www.hoons.net/Board/QACSHAP/Content/41967

자답은 좋은데 해결방식을 안써놨다 -_-;

그래도 방법이 이 수밖에 없을 듯 해서 검색해봤다.

다음의 사이트를 발견했다.

http://tech.pro/tutorial/852/csharp-tutorial-writing-a-dotnet-wrapper-for-sqlite

http://pkario.blogspot.com/2010/11/sqlite-c-wrapper.html


래핑에 대해서 샘플 코드를 기술해놓은 곳이다. 일단 첫번째 링크로 테스트 중이다. 

첫번째 링크의 문제

1. 디버그로 실행시 원인불명의 오류 발생 -_-;

일단 노디버그로 실행하면 되긴 된다

2. 한글 입력 처리 안됨

읽기는 된다


제대로 동작이 된다면 그에 대한 내용을 빨리 정리해두겠음

'Programming > C#' 카테고리의 다른 글

c# - c dll 디버깅시 주의할 점  (0) 2013.12.20
c# 문자열에서 문자 개수 알아내기  (0) 2013.12.19
C# 타이머 사용 예제  (0) 2013.12.10
C#에서 User Control 만들기  (0) 2013.11.12
c#에서 SQLite 한글 사용하기 -2-  (0) 2013.11.05
Posted by Vermond
: