참고 링크 : http://www.codeproject.com/Articles/22717/Using-PropertyGrid

(프로젝트 실행에 유의할 것 - 경로 재설정 필요)


VS의 폼 편집창에서 볼 수 있는 속성 윈도우

VS에서는 Property Grid라는 이름으로 지원한다.


실제 지원하는 부분은 아이콘부터 설명부분까지이고 아이템 선택하는 컨트롤은 다른 영역이다



이 PropertyGrid는 폼 편집창보다 코드상에서 처리를 좀 해주어야 한다.



- 기본 연결

PropertyGrid는 하나의 클래스와 연결할 수 있다

연결하는 클래스는 뭐든지 상관없지만 get/set으로 입출력을 선언해주어야 이 propertyGrid에 출력된다


연결 자체는 간단하다

propertyGrid1.SelectedObject = (created class);



- 구성 및 설정

get/set 선언에 일부 설정을 추가하면 위 스샷과 같이 나오게 된다


 [DisplayName("Choose your variant")]

        [Description("You can choose between Stone, scissors, paper")]

        [Category("Choosing")]

        [Editor(typeof(GameEditor), typeof(UITypeEditor))]

        public GameValues DisplayGameValues

        {

            get 

            {

                return m_GameValues;

            }

            set

            {

                m_GameValues = value;

            }

        }


DisplayName

메인으로 출력될 이름을 정한다. (스샷 기준으로 Text)

리스트란에 출력되고 설명 헤더로 추가된다

없을 경우에 선언한 함수명이 출력된다


Description

아래에 출력되는 설명을 정한다

없을 경우에는 공란이다


Category

목록에서 포함시킬 카테고리를 설정한다

미등록시 기타로 등록된다



기타 내용은 예제를 참고하면 좋다 (5번째 예제를 참고했다)

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

C DLL과 C# 연결 방법  (0) 2013.12.24
C# GC 빈도 낮추기  (0) 2013.12.20
c# - c dll 디버깅시 주의할 점  (0) 2013.12.20
c# 문자열에서 문자 개수 알아내기  (0) 2013.12.19
C# 타이머 사용 예제  (0) 2013.12.10
Posted by Vermond
:

 C#에서 c dll 함수를 호출하는 방법은 간단하다. 인자가 int, float 등의 형식이면 c#에서 그에 대응되는 값을 넣어주면 된다. 보통은 같은 명칭을 사용하며, unsigned int 같은 경우만 uint로 바꿔준다.

 문제는 포인터를 사용할 경우다. c#에서는 기본적으로 포인터를 사용할 수 없다. 그러나 c에서 배열을 사용하려면 포인터는 필수이다. 포인터를 사용할 수 있는 방법은 대략 3가지 정도가 있다.


1. 직접 포인터 선언해서 사용

c#에서도 제한적이지만 포인터를 직접 선언해서 사용할 수 있다. 포인터를 사용하려면 다음의 조건이 필요하다


- 포인터를 선언한 함수 혹은 클래스 상에 unsafe를 추가한다. 혹은 unsafe 블록을 생성한다. 포인터는 unsafe 내부에서만 사용 가능하다.

- 빌드 옵션에서 [안전하지 않은 코드 허용]을 체크한다. unsafe 사용시 이 옵션을 켜지 않으면 빌드되지 않는다





2. 그냥 사용 (마샬링)

대충 넘겨줘도 닷넷이 알아서 변환해주는 아주 간편한 기능이다

쓰기는 안되니 쓰기가 필요하다면 1번 방식을 사용하거나 텍스트로 데이터를 넘기도록 한다





3. IntPtr 사용

c#에서 포인터로 사용되는 놈이다. 2차원 이상의 배열을 넘겨줘야 한다면 이쪽이 가장 확실한 것으로 생각된다


예제는 아래의 링크로 대신한다 (베스트 답변 참고)

http://stackoverflow.com/questions/537573/how-to-get-intptr-from-byte-in-c-sharp




개인적으로 볼때 적합한 사용 방식은

1. 1차원 이하의 인자 전달만 필요하면 2번(마샬링)을 사용하여 편하게 작업한다

2. 2차원 이상의 인자 전달 혹은 한글 등을 제대로 전달해야 할때는 3번(IntPtr)을 사용한다

3. 포인터로 쓰기가 필요한 경우 직접 포인터를 작성하여 사용한다



아래 첨부된 파일은 간략한 예제 파일이다 (Visual Studio 2010에서 작성되었다)

버튼1 이벤트 : 직접 포인터 사용

버튼2 이벤트 : 마샬링 사용

버튼3 이벤트 : IntPtr 사용 (double 2중 배열)

버튼4 이벤트 : IntPtr 사용 (문자열 배열)


testDllCheck.7z


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

PropertyGrid 사용방법  (0) 2014.01.06
C# GC 빈도 낮추기  (0) 2013.12.20
c# - c dll 디버깅시 주의할 점  (0) 2013.12.20
c# 문자열에서 문자 개수 알아내기  (0) 2013.12.19
C# 타이머 사용 예제  (0) 2013.12.10
Posted by Vermond
:

C# GC 빈도 낮추기

Programming/C# 2013. 12. 20. 16:40 |

http://stackoverflow.com/questions/6005865/prevent-net-garbage-collection-for-short-period-of-time


채택된 답변 참고


실행될 코드는 finally 블록의 맨 첫번째에 넣어줘야 한다

try에 넣어놓으면 혹여나 예외로 catch로 빠졌을때 실행이 되지 않기 때문에

(물론 이경우는 GC 레벨이 낮아지지 않아서 중간에 GC가 실행될 것을 염두에 둬야 한다)


이 방법의 장점이라면 특정 코드 내에서 GC의 실행 빈도를 낮출 수 있다

그리고 보호할 모든 객체를 다 처리할 필요가 없다


단점은 이렇게 해도 메모리 부족해지면 GC가 수집을 수행하기 때문에 100% 막을 수는 없다는 것

프로그래머가 완벽하게 메모리 관리를 할려면 C#말고 다른걸 쓰는게 좋아 보인다

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

PropertyGrid 사용방법  (0) 2014.01.06
C DLL과 C# 연결 방법  (0) 2013.12.24
c# - c dll 디버깅시 주의할 점  (0) 2013.12.20
c# 문자열에서 문자 개수 알아내기  (0) 2013.12.19
C# 타이머 사용 예제  (0) 2013.12.10
Posted by Vermond
:

c# 프로젝트에서 디버깅 옵션의 비관리 코드 디버깅 사용

c 프로젝트에서 디버깅 - 디버거 형식을 혼압


으로 설정했을 때에 dll 디버깅이 된다.

(물론 당연하겠지만 두 프로젝트는 하나의 솔루션 내에서 열려 있어야 한다)


근데 이래도 안되는 경우가 있는데 방금 해결한 방법은 다음과 같다


- c 프로젝트 output을 dll로 설정한다

- 빌드한다

- 방금 빌드한 dll로 교체한다



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

C DLL과 C# 연결 방법  (0) 2013.12.24
C# GC 빈도 낮추기  (0) 2013.12.20
c# 문자열에서 문자 개수 알아내기  (0) 2013.12.19
C# 타이머 사용 예제  (0) 2013.12.10
C#에서 User Control 만들기  (0) 2013.11.12
Posted by Vermond
:

Visual Studio 2010에서 작성되었다

TimerSample.7z


위 프로젝트가 열리지 않을 경우 이 파일만 참고해도 무방하다

Form1.cs



C#에서 Timer는 3가지 종류가 있다


System.Windows.Forms.Timer

System.Threading.Timer

System.Timers.Timer


이 예제에서는 각각의 타이머에 대한 간략한 예제가 작성되어 있다

예제는 아주 간단해서 코드보다 주석이 더 길다


첫번째와 세번째 타이머는 비슷하고 두번째는 동작방식이 약간 다르다


각 타이머에 대한 차이 혹은 설명은 아래를 참고하도록 한다

http://msdn.microsoft.com/en-us/magazine/cc164015.aspx (영어)

http://blog.daum.net/starkcb/117



간략하게 사용 용도를 설명한다면

첫번째 타이머는 간략하게 수행할 작업에 적합하며, 별다른 조취 없이 UI 쓰레드에 접근할 수 있기 때문에 편리하다.

그러나 많이 계산해야 되는 경우라면 사용하지 않는 편이 좋은데, 오랜 시간 동작한다면 그동안 UI가 먹통이 된다

(자세한 내용은 위 링크를 참고하도록 한다)


두번째 타이머는 UI 쓰레드와 다른 쓰레드에서 동작하기 때문에 UI가 먹통이 된다거나 하지는 않는다

그렇다면 단순히 쓰레드를 사용해도 되지 않느냐고 물을 수 있지만, 반복 작업에는 쓰레드 내부에 코드로 작성하는 것보다 이쪽이 훨씬 편리하다.

만약 반복 작업이 특정한 시간마다 이루어져야 된다면 이 타이머를 사용하는게 훨씬 간편하면서도 확실하다


세번째 타이머는 첫번째와 비슷하지만 시간 정확도가 훨씬 높다.

보다 정확하게 실행되어야 한다면 이 타이머를 사용하는 것이 좋다

이 타이머는 UI 쓰레드에서 실행될수도 있고 다른 쓰레드로 실행될 수도 있기 때문에 코드 안전성을 위한다면 UI 접근 코드는 invoke-delegate를 사용해주는 편이 좋다

Posted by Vermond
:

사용자가 직접 만들어서 사용할 수 있는 구성요소 중에서 UserControl은 Component에 비해서 작성하기가 쉽다.


 개인적으로 UserControl은 여러 메뉴가 복합적으로 사용되어야 할 때에 사용하면 편하다. 가령 이미지 밑에 텍스트가 따로 출력되는 버튼 아이템은 기본으로 제공되지 않기 때문에 UserControl로 만들어 사용하면 간편하다.


[추가]

프로젝트 오른쪽 클릭 - 추가 - 사용자 정의 컨트롤

(다른 방법도 있다)


이름을 입력하고 확인을 누른다


[배치]

일반적인 디자인 편집화면의 배치와 동일하다. 원하는 아이템을 추가하고 적절하게 배치하도록 한다.


크기 설정에는 조금 신경을 써줘야 한다. 기본적인 크기는 고정 크기이기 때문에 아이템을 추가해서 크기를 늘려도 내부 아이템 크기는 변하지 않는다. Dock 옵션 혹은 코드상에서 크기 수정을 하거나 해서 크기가 변하도록 하는 것이 한 방법이다.


[속성값 설정]

내부의 아이템에 직접 접근할 수 있도록 해야 한다. 그렇지 않으면 계속 고정된 값만 사용해야 한다. 버튼을 만들어놓고 텍스트 수정을 할 수 있는 방법을 마련하지 않으면 같은 텍스트만 사용해야 한다.


코드 내부에 다음의 코드를 추가한다

[Description("설명"), Category("분류")]

        public string myText

        {

            get { return label1.Text; }

            set { label1.Text = value; }

        }


설명과 분류는 GUI 편집 화면에서 보조로 사용하기 위한 것이다.

설정하지 않은 경우에 기타 분류로 취급된다. 그러나 편의를 위해서 간략한 설명을 추가하도록 하자.


데이터 입출력 부분은 get/set을 사용하면 간편하다. 필요에 따라서 추가 기능을 넣어야 될 경우도 있으나 여기서는 생략한다.


[사용]

프로젝트 내부에서 직접 사용하는 방법에 대해서만 설명한다.

사용하기 위해서는 먼저 빌드를 할 필요가 있다.

빌드가 끝나면 GUI 편집창의 도구 상자 최상단에 방금 작성한 아이템이 추가된다.

이후 일반 Components 같이 끌어다 사용하면 된다.

Posted by Vermond
:

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
: