2010년 1월 21일 목요일

C# Marshal

 Win32 응용프로그램과 .Net 응용프로그램을 연결시켜주는 놀라운 BCL 이다. 당분간 이 클래스를 사용할 일이 많을 것 같아 주요한 것 만 정리해 보았다.



1. DataType
Marshal 클래스의 메소드를 보면 IntPtr 이라는 데이터 타입이 눈에 들어온다.

IntPtr
포인터나 핸들을 나타내는데 사용되는 플랫폼별 형식이다. (cf. MSDN)






 IntPtr 형식은 그 크기가 플랫폼마다 고유한 정수로 디자인되었습니다. 즉, 이 형식의 인스턴스는 32비트 하드웨어 및 운영 체제에서는 32비트로, 64비트 하드웨어 및 운영 체제에서는 64비트여야 합니다.

IntPtr 형식은 포인터를 지원하는 언어에서 사용할 수 있으며, 포인터를 지원하는 언어와 포인터를 지원하지 않는 언어 사이에서 데이터를 참조하는 일반적인 방법이 됩니다.

핸들을 보관하는 데도 IntPtr 개체를 사용할 수 있습니다. 예를 들어, IntPtr의 인스턴스는 파일 핸들을 보관하기 위해 System.IO..::.FileStream 클래스에서 광범위하게 사용됩니다.

IntPtr 형식은 CLS 규격이지만, UIntPtr 형식은 그렇지 않습니다. 공용 언어 런타임에서는 IntPtr 형식만 사용됩니다. UIntPtr 형식은 IntPtr 형식과의 구조적 대칭을 유지하기 위해 주로 사용됩니다.



참고로 Win32 응용프로그램 즉, Unmanaged Code 데이터 타입에 대응되는 Managed Code 의 데이터 타입은 아래 표와 같다. 정리해두신 분이 있어 자료를 링크한다.














































































































 Wtypes.h의
 관리되지 않는 형식
 관리되지 않는
C 언어 형식
 관리되는 클래스 이름  설명 
 HANDLE void*  System.IntPtr 32비트 Windows 운영 체제의 경우 32비트, 64비트 Windows 운영 체제의 경우 64비트 
 BYTE unsigned char  System.Byte  8비트
 SHORT short System.Int16 16비트
 WORD unsigned short System.UInt16  16비트
 INT int System.Int32 32비트
 UINT unsigned int System.UInt32  32비트 
 LONG long System.Int32  32비트 
 BOOL long System.Int32  32비트 
 DWORD unsigned long System.UInt32  32비트 
 ULONG unsigned long System.UInt32   32비트
 CHAR char System.Char ANSI로 데코레이트
 LPSTR char* System.String 또는
 System.Text.StringBuilder
 ANSI로 데코레이트
 LPCSTR Const char* System.String 또는
 System.Text.StringBuilder
 
 ANSI로 데코레이트
 LPWSTR wchar_t* System.String 또는
 System.Text.StringBuilder
 유니코드로 데코레이트
 LPCWSTR Const wchar_t* System.String 또는
 System.Text.StringBuilder
 
 유니코드로 데코레이트
 FLOAT Float System.Single 32비트
 DOUBLE Double System.Double 64비트

출처 : (P/Invoke series_ No.01 ) _플랫폼 호출 데이터 형식


위 표에서 알 수 있듯이 IntPtr 은 관리되지 않는 코드(Unmanaged Code) 에서는 void * 타입이다.
관리되는 코드에서 IntPtr 을 보게된다면 이렇게 생각하면 될 것 같다.
"IntPtr, 관리되지 않는 메모리 블록에 대한 포인터"
관리되는 코드에서 편리하게 사용하기 위해, 또 혹시 모를 오류의 가능성을 피하기 위해 관리되지 않는 메모리 블록의 데이터를 관리되는 데이터 블록으로 변환해 주자. Marshal 의 메소드를 이용하면 된다.



2. Marshal.PtrToStructur

관리되지 않는 메모리 블럭의 데이터를 지정된 형식의 새로 할당된 관리되는 개체로 마샬링한다.
자세한 내용은 MSDN 참조 (Marshal.PtrToStructure 메서드 (IntPtr, Type))

[ComVisibleAttribute(true)]
public static Object PtrToStructure (
    IntPtr ptr,
    Type structureType
)

structureType 는 형식이 지정된 클래스나 구조체여야 한다. 즉, 참조 타입, 값 타입 모두 가능하다. 다만 레이아웃이 sequential 또는 Explicit 로 설정되어 있어야 한다. 값 형식이 전달될 경우 반환값은 boxing 된 인스턴스이다. 리턴값이 object 타입이므로 사용할 때는 사용하려는 타입으로 형변환 하여 사용해야 한다.



3. Marshal.Copy
관리되는 배열에서 관리되지 않는 메모리 포인터로 데이터를 복사 또는,
관리되지 않는 메모리 포인터에서 관리되는 배열로 데이터를 복사한다.
자세한 내용은 MSDN 참조 (Marshal.Copy 메서드)

메서드의 인수 중에서 복사될 곳을 가리키는 인수는 반드시 메모리 생성 되어 있어야 한다. 즉, 관리되는 배열이라면 new 연산자로 먼저 메모리 할당을 해야 하고, 관리되지 않는 배열이라면 Marshal.AllocHGlobal 등으로 메모리를 먼저 할당해주어야 한다. 그렇지 않으면 ArgumentNullException 이 발생한다.



4. Marshal.AllocHGlobal
프로세스의 관리되지 않는 메모리에서 메모리를 할당한다. 사용할 상황은 이렇다. 관리되는 코드의 데이터를 관리되지 않는 메모리 블록에 복사해야 한다. 그럴때 이 메소드를 사용한다.

[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public static IntPtr AllocHGlobal(
    int cb
)

cb 는 요청된 메모리의 바이트 수 이다. IntPtr 은 관리되지 않는 메모리 블록에 생성된 메모리를 가리키는 IntPtr 값이다.
여기서 중요한 것은!!!
" 관리되지 않는 메모리에 우리가 직접 메모리를 생성하였으므로 수동으로 직접 메모리를 해제시켜줘야 한다."
Marshal.FreeHGlobal 을 이용하면 된다.


Marshal 메소드 중에서 메모리 할당 API 는 Marshal.AllocHGlobal, Marshal.AllocCoTastMem 이렇게 2가지가 있다. AllocCoTastMem 메소드는 kernel32.dll 로 부터 LocalAlloc Win32 API 를 호출한다고 한다.



2010년 1월 19일 화요일

WPF Toolkit June 2009 Pie Chart



WPF 응용프로그램의 차트를 보고 참 매력적이라고 생각했다. 윈폼에서 조차도 차트를 그리려면 노가다를 해야 했고, 상용 컴포넌트도 그리 화려하지 않았던 기억이 있다. WPF Toolkit June 2009 컴포넌트를 이용하면 쉽게 차트를 그릴 수 있다. 외국 블로그 자료를 참조했다.





WPF Toolkit June 2009 Pie Chart




원문

Pie Chart in WPF



WPF ToolKit June 2009 에는 WPF 에서 차트 기능을 갖는 System.Windows.Controls.DataVisualization.Toolkit.dll 이 포함되어 있다.


Install WPF Toolkit June 2009

링크를 참조하여 다운로드 및 설치 하자 WPF Toolkit - Release: WPF Toolkit June 2009
설치 하는데 특별한 설정은 없다. 이 toolkit 이 다음 WPF 확장 버전에 포함된다고 하는데, 그렇다면 라이센스 문제는 없겠지?!


Adding WPF Toolkit Reference

설치가 완료 하였다면 프로젝트에서 툴킷을 사용해 보자. 툴킷의 기능을 사용하기 위해서는 프로젝트에 툴킷 어셈블리를 참조 추가 시켜야 한다.



솔루션 탐색기에서 "참조" 항목에서 마우스 오른쪽 버튼으로 클릭 후 "참조 추가" 를 선택한다.




브라우저 탭을 선택한 후 툴킷이 설치된 폴더로 이동하자. 보통 툴킷이 설치된 경로는 다음과 같다.
C:\Program Files\WPF Toolkit\v3.5.40619.1\
폴더에서 System.Windows.Contorls.DataVisualization.Toolkit.dll 을 선택하여 참조 추가 시킨다.




다음으로 다음 두 네임스페이스를 xmal 페이지에 불러온다.
System.Windows.Controls.DataVisualization.Charting
System.Windows.Controls.DataVisualization.toolkit

xaml 페이지에서 "xmlns= " 을 입력하면 인텔리센스의 도움으로 쉽게 추가시킬 수 있다.
네임스페이스의 이름은 사용자 임의로 작성할 수 있다. 위에서는 DV, DVC 라고 졌는데 아마 DataVisualization 의 앞글자만 딴 듯?! DVC 에서 C 는 Chart 를 의미하겠고?! 후후후




xaml 페이지에서 DVC 라고 치면 차트와 관련된 엘리먼트들을 볼 수 있다.


Creating Chart

차트를 만들 준비가 되었으니 본격적으로 만들어 보자. 일단, 차트의 틀을 만들어 보자.
Chart 엘리먼트는 xaml 에서 WPF Chart 컨트롤을 나타낸다.

< DVC:Chart></DVC:Chart>

아래의 코드 조각은 Chart 컨트롤을 선언 하여 컨트롤 변수의 이름 및 너비, 높이, 배경색, 전경색, 타이틀 이름, 범례 이름 프로퍼티를 설정한다. 각 프로퍼티의 의미는 출력 모습을 보면 짐작할 수 있다.

<DVC:Chart Name="mcChart" Width="400" Height="250"            Background="YellowGreen" Foreground="DarkBlue"            Title="Area Chart" LegendTitle="Month Rating" />
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->





Chart Type

Chart 엘리먼트의 Series 어트리뷰트를 사용하여 차트 타입을 생성한다. BarSeries, ColumnSeries, LineSeries, PieSeries, AreaSeries, ScatterSeries 를 만들 수 있다.




Pie Chart

아래의 코드는 Chart 엘리먼트의 Series 어트리뷰트를 PieSeries 로 설정하여 Pie Chart 를 생성한다. data source 의 Key, Value 필드를 바인딩 시켜주었다.

<DVC:Chart Canvas.Top="80" Canvas.Left="10" Name="mcChart"            Width="400" Height="250" Background="LightSteelBlue">    <DVC:Chart.Series>        <DVC:PieSeries Title="Experience"                       IndependentValueBinding="{Binding Path=Key}"                       DependentValueBinding="{Binding Path=Value}">        </DVC:PieSeries>    </DVC:Chart.Series>            </DVC:Chart>  

아래의 코드는 KeyValuePair 컬렉션을 생성하여 Chart Series 의 ItemSource 프로퍼티에 설정한다. 생성한 컬렉션은 다른 차트에서도 재사용 할 수 있다.

private void LoadPieChartData(){    ((PieSeries)mcChart.Series[0]).ItemsSource =        new KeyValuePair<string, int>[]{            new KeyValuePair<string, int>("Project Manager", 12),            new KeyValuePair<string, int>("CEO", 25),            new KeyValuePair<string, int>("Software Engg.", 5),            new KeyValuePair<string, int>("Team Leader", 6),            new KeyValuePair<string, int>("Project Leader", 10),            new KeyValuePair<string, int>("Developer", 4) };}
출력된 모습은 다음과 같다.




Generating Chart from a Collection
컬렉션으로 부터 Pie Chart 를 그릴 수 있다. 우선 Fruit 라는 클래스를 정의한다.

class Fruit{    public string Name { get; set; }    public Int16 Share { get; set; }}


FruitCollection 클래스는 생성자에서 Fruit 객체를 추가한다.
class FruitCollection : System.Collections.ObjectModel.Collection<Fruit>{    public FruitCollection()    {        Add(new Fruit { Name = "Mango", Share = 10 });        Add(new Fruit { Name = "Banana", Share = 36 });        Add(new Fruit { Name = "Apple", Share = 24 });        Add(new Fruit { Name = "Guava", Share = 4 });        Add(new Fruit { Name = "Orange", Share = 12 });        Add(new Fruit { Name = "Pear", Share = 10 });        Add(new Fruit { Name = "Pineapple", Share = 4 });    }}


xaml 코드에서 FruitCollection 을 호출하는 리소스를 추가하고,  ItempSource 프로퍼티를 사용하여 PieSeries 에 FruitCollection 을 바인딩 시켰다.

<Grid.Resources>    <local:FruitCollection x:Key="FruitCollection" /></Grid.Resources>
<
DVC:Chart Canvas.Top="80" Canvas.Left="10" Name="mcChart"            Width="400" Height="250"           Background="LightSteelBlue">    <DVC:Chart.Series>        <DVC:PieSeries Title="Experience"                       ItemsSource="{StaticResource FruitCollection}"                       IndependentValueBinding="{Binding Path=Name}"                       DependentValueBinding="{Binding Path=Share}">       </DVC:PieSeries>    </DVC:Chart.Series>
<
/DVC:Chart>


출력 결과는 다음과 같다.




원문 블로그 예제 소스
cfile7.uf.137B933B50AEC2E81E3D22.zip


이 외에도 원문 블로그에 보면 다른 차트 사용에 대한 간단한 샘플이 있다.



2010년 1월 17일 일요일

Windows Icon in WPF

Windows Icon in WPF


출처 : Windows Icon in WPF


WPF 의 Window 클래스에는 Icon 프로퍼티가 있습니다. 이 프로퍼티를 이용하면 메인 윈도우의 아이콘을 설정할 수 있습니다.

Visual Studio Image Editor
Visual Studio 에서 아이콘 편집기를 불러와 아이콘을 만들 수 있고 프로젝트에 추가할 수 있습니다.


솔루션 탐색기에서 프로젝트 이름 위에서 마우스 오른쪽 버튼을 클릭한 다음 "추가"  를 선택 합니다. 연결된 팝업 메뉴에서 "새 항목" 을 선택합니다.




설치된 템플릿 목록 중에서 "아이콘 파일" 을 선택합니다.




아이콘 에디터에서는 16x16, 32x32  2가지 크기의 아이콘을 지원합니다.




추가된 아이콘이 프로젝트에 추가되어 있는 것을 확인할 수 있습니다.


여기까지는 Visual Studio 이전 버전부터 쭉 있던 기능이라 그리 새로울 것도 없고, 또 실질적으로 사용할 아이콘을 visual studio 에서 만들지 않을것입니다. 전문적인 아이콘 제작 프로그램이 있고, 만드는 사람도 따로 있으니.


Icon Property of Window

여기서 알고자 하는 것은 Window 클래스의 Icon 프로퍼티 입니다. Icon 프로퍼티를 이용하여 Window 클래스의 아이콘을 설정할 수 있습니다. 즉 실행시간에 윈도우의 아이콘을 설정합니다. XAML 코드는 및 실행되었을 때 윈도우의 아이콘 모습은 다음과 같습니다.

<Window x:Class="WindowSample.MainWindow"        xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation        xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml        Title="WPF Window Sample" Height="350" Width="525"        Name="FirstWindow" Icon="Icon1.ico" >






Icon 프로퍼티에 외부 아이콘 소스를 불러 올 수 있습니다.
Uri iconUri = new Uri("pack://application:,,,/Icon1.ico", UriKind.RelativeOrAbsolute);this.Icon = BitmapFrame.Create(iconUri);




프로젝트 리소스로 첨부하였을 경우
 
프로젝트 리소스로 첨부하였을 경우 다음 두 가지 체크.
1). 리소스 파일(위 예에선 "MainIcon.ico" 파일) 속성에서 빌드 액션을 "Resource" 로 설정
2). xaml 에선 <window ... Icon="./Resources/MainIcon.ico"> 와 같이 사용

*) 참조