블로그 이미지
Every unexpected event is a path to learning for you.

카테고리

분류 전체보기 (2731)
Unity3D (814)
Programming (474)
Python (8)
TinyXML (5)
STL (13)
D3D (3)
MFC (1)
C/C++ (54)
C++/CLI (45)
C# (250)
WinForm (6)
WPF (5)
Math (10)
A.I. (1)
Win32API (11)
Algorithm (3)
Design Pattern (7)
UML (1)
MaxScript (1)
FMOD (4)
FX Studio (1)
Lua (2)
Terrain (1)
Shader (3)
boost (2)
Xml (2)
JSON (4)
Etc (11)
Monad (1)
Html5 (4)
Qt (1)
Houdini (0)
Regex (10)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (228)
협업 (57)
3DS Max (3)
Game (12)
Utility (136)
Etc (96)
Link (32)
Portfolio (19)
Subject (90)
iOS,OSX (51)
Android (14)
Linux (5)
잉여 프로젝트 (2)
게임이야기 (3)
Memories (20)
Interest (38)
Thinking (38)
한글 (30)
PaperCraft (5)
Animation (408)
Wallpaper (2)
재테크 (18)
Exercise (3)
나만의 맛집 (3)
냥이 (10)
육아 (16)
Total
Today
Yesterday
03-29 07:22

1
2
3
4
5
6
7
8
9
10
11
12
13
typedef BOOL __stdcall Callback(int a, int b);   //Hslee 콜백 등록!
Callback *_cb;   //C#의 콜백루틴 받아오는 포인터변수
 
void CallBackCall()  //콜백 루틴시키는 함수...(Callback함수와 연결됨)
{
    if(_cb != NULL)
        (_cb)(10,20);
}
 
void RegCallback(Callback *pcb)  //C#의 콜백루틴 받아와 연결하는 함수
{
    _cb = pcb;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using System.Runtime.InteropServices;
 
namespace CallbackTest
{
    class Program
    {  
        [DllImport("CallbackTestDll.dll")]
        static extern void RegCallback1(Callback1 callback);
        delegate bool Callback1(int a, int b);
         
        static bool PrintWindow1(int a, int b)
        {
            Console.Write("a:"+a.ToString() + "b:" + b.ToString()+"\t");
            return true;
        }
 
        static void Main(string[] args)
        {
            Callback1 callback1 = new Callback1(PrintWindow1);
            RegCallback1(callback1);
        }
    }
}



C#의 delegate루틴을 C++에 넘겨준뒤. C++에서 콜백이 발생됬을경우 C#으로 넘기게된다.
여기서 주의할점.. C#은 콜백을 받아올때 가바지컬렉터 라는 놈이 관리를 하게된다..

Callback발생 -> 카비지컬렉터 -> C# 루틴

뭐 이런식으로 알고있다.. C#은 가비지컬렉터 수집을 자동으로 한다...
Callback이 사용자가 요청했을때만 들어온다면 상관없지만...

uRON(ETRI)의 로봇주행알고리즘 을 사용할경우 콜백이 미친듯이 들어와버리게된다..
그러면서 가비지컬렉터가 싸이면서.. 프로그램이 종료되게된다..

콜백이 미친듯이 들어오므로 가비지컬렉터수집을 사용자가 직접 해줘야 한다...

C#의 콜백 루틴 안에다가 
GC.Collect();

를 넣어주게되면 가비지컬렉터를 강제로 수집하게된다..

자세한사항은 MSDN 참고!



이방법을 구현하기위하 온갖 MSDN을 뒤지면서 나만의 방법으로 바꿔주는데 성공했다.

정말 힘들었던 작업....중 하나.. 정말 유용하게 쓰인다! 

나같은 Robot Programming을 하는 사람이라면.. 디바이스제어는 C++ 
Main Program은 Error가 적은 C#을 사용하용하는 사람들이 꽤 있을거 같다..


출처 : http://periar.tistory.com/entry/C-DLL-Callback-%EC%9D%84-C-%EB%A3%A8%ED%8B%B4%EC%9C%BC%EB%A1%9C-%EA%B0%80%EC%A0%B8%EC%98%A4%EA%B8%B0

반응형
Posted by blueasa
, |

C#에서 managed C++로 윈도우 핸들을 보내는 방법.

C++ part
public ref class TmMainWindow
{
    public:
        TmMainWindow(int windowHandle)
        {
            mWindowHandle = (HWND)windowHandle;
        }
    private:
        HWND mWindowHandle;
};


C# part
public partial class MainForm : Form
{
    private TmMainWindow mMainWindow;

    private void MainForm_Load(object sender, System.EventArgs e)
    {
        mMainWindow = new TmMainWindow(this.Handle.ToInt32()); 
        // 이부분이 윈도우 핸들을 넘기는 방법. 64bit os는 ToInt64일듯.
    }
};


위와 같이 하면 된다.
여담이지만, WeifenLuo 라이브러리를 쓰다가 constructor에서 윈도우 핸들값을 얻는 경우 값이 잘 못 나왔다. Load event 에서 window handle을 얻는 것은 괜찮았다. 이것 때문에 고생 좀 했다.



반응형
Posted by blueasa
, |

cli::array<t>^<t>

Programming/C++/CLI / 2011. 3. 24. 15:50

 C++/CLI 에서 배열은 하나의 Data type 이다어떠한 배열이든 cli::array 클래스의 인스턴스(참조 타입)이다.

메모리는 동적으로 CLR(Common Language Runtime) Heap 에 생성된다메모리의 크기는 배열 생성시에 결정되며 그 이후에는 크기를 변경할 수 없다.

 

 

1. 만약 배열의 Data Type  Value Type 이라면 배열 생성 시 Boxing 되어 들어간다.

(Boxing 과정은 프로그램의 Performance 를 하향 시킨다.)

2. 배열의 인덱스(첨자 0 부터 시작한다.

3. 배열은 배열의 요소에 접근 및 다루기 위한 메소드를 가지고 있다.

4. 배열에서의 모든 동작은 체크된다배열의 범위를 넘어가는 동작에 대하여 “Index out of range”

예외가 발생하게 된다.

5. 배열은 CLR Heap 에 할당된다. Value Type 의 배열은 Heap  Boxing 된 다음 그 참조를 리턴받는다.

 

 



■ 사용 예



int 타입의 배열 a 를 선언 및 생성 하였다. 또한 배열의 개수를 명시적으로 선언하지 않고, 초기화 값을 선언하였으므로 묵시적으로 1, 2, 3 의 값을 갖는 크기 3의 배열이 생성된다.




위 예는 명시적으로 배열의 크기를 100으로 선언하였다. 따라서 100 개의 요소를 갖는 배열이다. 또한 1,2,3 으로 초기값을 적어주었으므로 배열의 처음 3번째 요소까지 초기화가 이루어 진다.




cli::array 클래스에는 배열을 조작하기 위한  메소드와 프로퍼티가 정의되어 있다. Length, index 등 이 있으며 foreach 문에서 사용할 수 있다.


 



위의 예는 다차원 배열의 선언 및 사용 예이다. array<type, 차원>^ 과 같이 사용한다. 위의 예는 3차원 배열로서 4*5*2 크기를 갖는 배열이다.




String 클래스의 배열 역시 사용할 수 있다. 인상적인 것은 <> 안에 String^ 이 들어간다.




위의 예는 String 클래스의 배열을 생성 후 루프를 돌면서 초기화 하는 예제 이다.





■ 가변인자 사용 예

C++ 과 마찬가지로 가변 인자 를 지원한다. 다음은 사용 예 이다.





※ 만약 배열에 요소를 추가 하거나 삭제 하려 한다면 ArrayList 클래스를 참조한다.


 



■ 참조

1. cli::array (MSDN)
2. C++/CLI Primer - Enter the World of .NET Power Programming (CodeProject)
3. Quick C++/CLI - Learn C++/CLI in less than 10 minutes (CodeProject)


반응형
Posted by blueasa
, |
System.String → char * (marshal_context)






■ System.String → char *

 예전 C++/CLI 에서는 System.String 문자열을 char * 형으로 변환하기 위해선
메모리를 할당하고, 할당된 메모리에 문자열을 복사하기 위해 Marshal::StringToHGlobalAuto 메소드를 호출했다.
그런 후, HGlobal 포인터를 char * 에 캐스팅 해주었다.

const char* unmanagedString = NULL;
try
{
    String^ managedString = gcnew String("managed string");
    // Note the double cast.
    unmanagedString = (char*)(void*)Marshal::StringToHGlobalAnsi(managedString);
}
finally
{
    // Don't forget to release. Note the ugly casts again. 
    Marshal::FreeHGlobal((IntPtr)(void*)unmanagedString);
}

 

 Visual Studio 2008 에서는 새로운 Marshalling Library 를 통하여 문자열을 복사하는 새로운 방법이 추가 되었다.
이 라이브러리는 Managed Code 의 System.String 과 Native Code 에서 문자열을 나타내는데 자주 쓰이는 타입
(char *, wchar_t *, BSTR, CStringT<wchar_t>, ...) 간의 변환을 쉽게 할 수 있게 해준다.

 Marshalling Library 에서는 marshal_context 라고 하는 새로운 클래스를 포함한다. 이 클래스는 문자열 변환 시
기본의 명시적으로 메모리를 해제 시켜 줘야 하는 작업을 대신 해준다. 따라서 문자열 변환 작업 시의 메모리 해제 및 누수에
대한 걱정을 덜어준다. marshal_context 클래스를 사용하는 예제는 다음과 같다.

marshal_context^ context = gcnew marshal_context();
String^ managedString = gcnew String("managed string");
const char* unmanagedString = context->marshal_as( managedString );



 기본 방법에 비해 코드가 상당히 줄어들었다. 또한 형변환을 위한 캐스팅 연산도 직접 작성하지 않아도 된다.
무엇보다도 제일 중요한 점은 char * 의 메모리 해제 시켜주는 작업을 작성하지 않아도 된다.
marshal_context 클래스는 모든 string 에 대한 참조를 유지한다. 유효 범위(scope) 를 벗어 날 때 소멸자가
그것들을 메모리 해제 시켜준다.






■ Native String → System:String




반대로 변환 하는 방법 역시 비슷하다.



System::String^ 타입을 const char *, const wchar_t *, BSTR 으로 변환하기 위해 marshal_as 를 직접 사용할 수는 없다. 왜냐하면 이러한 변환들은 사용 후에 메모리 해제를 위한 비 관리(Unmanaged) resource 를 필요로 한다. 아래와 같이 context 객체를 사용해야 한다. (즉, marshal_context 클래스의 객체 context 를 사용함으로써 marshal_context 의 소멸자가 메모리 해제를 해준다.)



context 객체는 동적 생성된 객체를 유지하다가 소멸자에서 그 메모리를 해제 시킨다. 내부적으로 할당된 객체들은 Linked-List 로 유지된다. 위의 코드에서 Console::WriteLine(context._clean_up_list.Count); 는 3을 출력 한다.




■ Extend the Marshaling Library 사용

String 타입을 변환할 때 다음과 같은 에러 메시지를 발생할 수 도 있다.

오류 1 error C4996: 'msclr::interop::error_reporting_helper<_To_Type,_From_Type>::marshal_as': This conversion is not supported by the library or the header file needed for this conversion is not included.  Please refer to the documentation on 'How to: Extend the Marshaling Library' for adding your own marshaling method.

CString 타입을 사용하려 하니까 나타난 에러 메시지 인데, MFC 사용할 때 CString 이 ATL data type 이라는 것을 얼 추 추측하긴 했지만 위와 같은 에러 메시지로 확신하게 되었다.

에러 메시지 내용대로 MSDN 의 How to:Extend the Marshaling Library 문서를 확인해 보니 ATL data type 을 위해선 marshal_atl.h 헤더 파일을 include 시켜줘야 한다.








■ 참조

1. More Tales from the Unmanaged Side - System.String -> char* : marshal_context 사용 전의 문자열 변환 방법
2. Tales from the Unmanaged Side – System.String –> char* (pt. 2)  : marshal_context 이용한 방법
3. Using marshal_as for mixed-mode string conversions : 여러 string type 의 conversion
4. Overview of Marshaling in C++
5. How to:Extend the Marshaling Library 


반응형
Posted by blueasa
, |
반응형

'Programming > C++/CLI' 카테고리의 다른 글

cli::array<t>^<t>  (0) 2011.03.24
System.String → char * (marshal_context)  (2) 2010.12.20
Arrays in C++/CLI  (0) 2010.11.26
Native C++에서 Managed C++에 접근이 필요할 때  (0) 2010.11.09
C++/CLI Singleton  (0) 2010.10.22
Posted by blueasa
, |

Arrays in C++/CLI

Programming/C++/CLI / 2010. 11. 26. 16:00
The article exposes the new array syntax available in C++/CLI for the declaration and use of CLI arrays

Introduction

Managed arrays are allocated on the CLI heap as opposed to native arrays which are allocated on the unmanaged C++ heap, which essentially means that they are typical garbage collected .NET objects. And throughout this article the term array will refer to a managed array, and if at all a native array is mentioned, it will explicitly be termed as a native array. Some of you might have seen my article on using managed arrays with the old MC++ syntax and I am sure a few of you would have let out pained groans at the really peculiar syntax. Well, those people should be delighted to know that C++/CLI supports managed arrays using a far more intuitive syntax than which existed in the older syntax.

Basic features

Here are some of the basic features of managed arrays in C++/CLI :-

  • Syntax resembles that of C++ templates
  • System::Array is automatic base type for all managed arrays
  • Allocated on the CLR heap (means they get Garbage Collected)
  • Rank of the array need not be 1 (arrays with rank 1 are called single dimensional and those with rank >1 are called multi dimensional)
  • Easily supports jagged arrays (unlike in the older syntax, jagged arrays are easier to declare and use)
  • Implicit conversion to and explicit conversion from System::Array BCL class
  • The rank and dimensions of an array object cannot be changed, once an array has been instantiated

Pseudo-template of an array type

The declaration and usage of array types in C++/CLI seems to use an imaginary template type (there is no such template of course, it�s all VC++ compiler magic) :-

 Collapse
namespace stdcli::language
{
    template<typename T, int rank = 1>
        ref class array : System::Array {};
}

array is declared inside the stdcli::language namespace so as to avoid conflicts with existing source code

Single dimensional array usage

Arrays of a reference type

 Collapse
ref class R
{
public:
    void Test1(int x)
    {
        array<String^>^ strarray = gcnew array<String^>(x);
        for(int i=0; i<x; i++)
            strarray[i] = String::Concat("Number ",i.ToString());
        for(int i=0; i<x; i++)
            Console::WriteLine(strarray[i]);
    }
};

The syntax does look different from that used for native arrays; C++ coders who have used templates should find this a lot more intuitive than people who come from a non-C++ background, but eventually they'll get comfortable with it.

Arrays of a value type

 Collapse
ref class R
{
public:
    void Test2(int x)
    {
        array<int>^ strarray = gcnew array<int>(x);
        for(int i=0; i<x; i++)
            strarray[i] = i * 10;
        for(int i=0; i<x; i++)
            Console::WriteLine(strarray[i]);
    }
};

Unlike in the old syntax, array syntax for value types is exactly the same as that for managed types.

Multi dimensional array usage

Multi dimensional arrays are managed arrays that have a rank greater than 1. They are not arrays of arrays (those are jagged arrays).

 Collapse
ref class R
{
public:
    void Test3()
    {
        array<String^,2>^ names = gcnew array<String^,2>(4,2);
        names[0,0] = "John";
        names[1,0] = "Tim";
        names[2,0] = "Nancy";
        names[3,0] = "Anitha";
        for(int i=0; i<4; i++)
            if(i%2==0)
                names[i,1] = "Brown";
            else
                names[i,1] = "Wilson";
        for(int i=0; i<4; i++)
            Console::WriteLine("{0} {1}",names[i,0],names[i,1]);
    }    
};

Jagged arrays

Jagged arrays are non-rectangular, and are actually arrays of arrays. The new template-style array syntax simplifies the declaration and use of jagged arrays, which is a major improvement over the old syntax where jagged arrays had to be artificially simulated by the developer.

 Collapse
ref class R
{
public:
  void Test()
  {
    array<array<int>^>^ arr = gcnew array<array<int>^> (5); 

    for(int i=0, j=10; i<5; i++, j+=10)
    {
      arr[i] = gcnew array<int> (j);
    }

    Console::WriteLine("Rank = {0}; Length = {1}",
      arr->Rank,arr->Length);
    /*
      Output :-
        Rank = 1; Length = 5
    */

    for(int i=0; i<5; i++)
      Console::WriteLine("Rank = {0}; Length = {1}",
        arr[i]->Rank,arr[i]->Length);
    /*
      Output :-
        Rank = 1; Length = 10
        Rank = 1; Length = 20
        Rank = 1; Length = 30
        Rank = 1; Length = 40
        Rank = 1; Length = 50
    */
  }
};

Using a typedef to simplify jagged array usage

 Collapse
typedef array<array<int>^> JaggedInt32Array;
typedef array<array<String^>^> JaggedStringArray;

ref class R
{
public:
    void Test()
    {
        JaggedInt32Array^ intarr = gcnew JaggedInt32Array(10);
        JaggedStringArray^ strarr = gcnew JaggedStringArray(15);        
    }
};

Directly initialize an array

The new syntax allows painless direct initialization of arrays.

 Collapse
ref class R1
{
public:
  void Test()
  {
    //Single dimensional arrays

    array<String^>^ arr1 = gcnew array<String^> {"Nish", "Colin"};
    array<String^>^ arr2 = {"Nish", "Smitha"};
    
    //Multi dimensional arrays

    array<Object^,2> ^ multiobarr = {{"Nish", 100}, {"Jambo", 200}};
  }
};

Arrays as function arguments

 Collapse
ref class R
{
public:
  void ShowStringArray(array<String^>^ strarr)
  {
    for(int i=0; i<strarr->Length; i++)
      Console::WriteLine(strarr[i]);
  }
  void Show2DInt32Array(array<int,2>^ arr)
  {    
    for(int i=0; i<arr->GetLength(0); i++)
    {
      Console::WriteLine("{0} times 2 is {1}",arr[i,0],arr[i,1]);
    }
  }
};

void _tmain()
{
  R^ r = gcnew R();
  r->ShowStringArray(gcnew array<String^> {"hello", "world"});
  array<int,2>^ arr = { {1,2}, {2,4}, {3,6}, {4,8} };
  r->Show2DInt32Array(arr);
}

//Output :-


/*
  hello
  world
  1 times 2 is 2
  2 times 2 is 4
  3 times 2 is 6
  4 times 2 is 8
*/

Returning arrays from functions

 Collapse
ref class R
{
public:
    array<String^>^ GetNames(int count)
    {
        array<String^>^ arr = gcnew array<String^>(count);
        for(int i=0; i<count; i++)
        {
            arr[i] = String::Concat("Mr. ",(i+1).ToString());
        }
        return arr;
    }

    void ShowNames(array<String^>^ arr)
    {
        for(int i=0; i<arr->Length; i++)
            Console::WriteLine(arr[i]);
    }
};

void _tmain()
{
    R^ r = gcnew R();
    array<String^>^ arr = r->GetNames(7);
    r->ShowNames(arr);
}

Array covariance

You can assign an array of type R to an array of type B, where B is a direct or indirect parent of R, and R is a ref class.

 Collapse
ref class R1
{
    //...

};

ref class R2 : R1
{
    //...

};

void _tmain()
{
    array<R1^>^ arr1 = gcnew array<R1^>(4);
    array<R2^>^ arr2 = gcnew array<R2^>(4);    
    
    array<R1^>^ arr3 = arr2;    
    array<R1^>^ arr4 = gcnew array<R2^>(4);    
}

Parameter arrays

C++/CLI has support for parameter arrays. There can only be one such parameter array per function and it also needs to be the last parameter.

 Collapse
ref class R
{
public:
    void Test(String^ s, [ParamArray] array<int>^ arr )    
    {
        Console::Write(s);
        for(int i=0; i<arr->Length; i++)
            Console::Write(" {0}",arr[i]);
        Console::WriteLine();
    }
};

void _tmain()
{
    R^ r = gcnew R();
    r->Test("Nish");
    r->Test("Nish",1);
    r->Test("Nish",1,15);
    r->Test("Nish",1,25,100);
}

Right now the only supported syntax uses the ParamArray attribute, but the eventual syntax will also support the simpler style shown below :-

  • void Test(String^ s, ... array<int>^ arr )

Calling System::Array methods

Since every C++/CLI array is implicitly a System::Array object, we can use System::Arraymethods on CLI arrays.

 Collapse
ref class R
{
public:
  bool CheckName(array<String^>^ strarr, String^ str)
  {
    Array::Sort(strarr);
    return Array::BinarySearch(strarr,str) < 0 ? false : true;
  }
};

void _tmain()
{
  R^ r = gcnew R();
  array<String^>^ strarr = {"Nish","Smitha",
    "Colin","Jambo","Kannan","David","Roger"};  
  Console::WriteLine("Nish is {0}",r->CheckName(strarr,"Nish") ? 
    gcnew String("Present") : gcnew String("Absent"));
  Console::WriteLine("John is {0}",r->CheckName(strarr,"John") ? 
    gcnew String("Present") : gcnew String("Absent"));
}

I've used System::Sort and System::BinarySearch in the above example.

Here's another snippet that clearly demonstrates the implicit conversion to System::Array.

 Collapse
ref class R
{
public:
    void ShowRank(Array^ a)
    {
        Console::WriteLine("Rank is {0}",a->Rank);
    }
};

void _tmain()
{
    R^ r = gcnew R();    
    r->ShowRank( gcnew array<int>(10) );
    r->ShowRank( gcnew array<String^,2>(10,2) );
    r->ShowRank( gcnew array<double,3>(10,3,2) );    
    r->ShowRank( gcnew array<int> {1,2,3} );
    r->ShowRank( gcnew array<int,2> {{1,2}, {2,3}, {3,4}} );
}

Arrays of non-CLI objects

You can declare C++/CLI arrays where the array type is of a non-CLI object. The only inhibition is that the type needs to be a pointer type. Consider the following native C++ class :-

 Collapse
#define Show(x) Console::WriteLine(x)

class N
{
public:
   N()
   {
      Show("N::ctor");
   }
   ~N()
   {
      Show("N::dtor");
   }
};

Now here's how you can declare an array of this type :-

 Collapse
ref class R
{
public:   
   void Test()
   {
      array<N*>^ arr = gcnew array<N*>(3);
      for(int i=0; i<arr->Length; i++)   
         arr[i] = new N();
   }
};

Put this class to use with the following test code :-

 Collapse
void _tmain()
{
   R^ r = gcnew R();
   r->Test();
   Show("Press any key...");
   Console::ReadKey();
}

/* Output:

N::ctor
N::ctor
N::ctor
Press any key...

*/

There, that worked. Of course the destructors for the array elements did not get called, and in fact they won't get called even if a Garbage Collection takes place and the array object is cleaned up. Since they are native objects on the standard C++ heap, they need to have delete called on them individually.

 Collapse
ref class R
{
public:   
   void Test()
   {
      array<N*>^ arr = gcnew array<N*>(3);
      for(int i=0; i<arr->Length; i++)   
         arr[i] = new N();
      for(int i=0; i<arr->Length; i++)   
         delete arr[i];
   }
   //...


/* Output

N::ctor
N::ctor
N::ctor
N::dtor
N::dtor
N::dtor
Press any key...

*/

Ok, that's much better now. Or if you want to avoid calling delete on each object, you can alternatively do something like this :-

 Collapse
ref class R
{
public:   
   void Test()
   {
      N narr[3];
      array<N*>^ arr = gcnew array<N*>(3);
      for(int i=0; i<arr->Length; i++)
         arr[i] = &narr[i];   
   }   
};

This yields similar results to the above snippet. Alternatively you could init the array members in its containing class's constructor and delete them in the destructor, and then use the containing class as an automatic variable (C++/CLI supports deterministic destruction).

Direct manipulation of CLI arrays using native pointers

Here's some code that shows how you can directly manipulate the contents of an array using native pointers. The first sample is for a single dimensional array and the second is for a jagged array.

Natively accessing a single-dimensional array

 Collapse
void Test1()    
{
    array<int>^ arr = gcnew array<int>(3);
    arr[0] = 100;
    arr[1] = 200;
    arr[2] = 300;

    Console::WriteLine(arr[0]);
    Console::WriteLine(arr[1]);
    Console::WriteLine(arr[2]);

    /*
    Output :-
      100
      200
      300
    */

    // Modifying the array using a native int* 

    // that points to a pinned pointer in GC'd heap

    pin_ptr<int> p1 = &arr[0];
    int* p2 = p1;
    while(*p2)
    {           
        (*p2)++;
        p2++;
    }

    Console::WriteLine(arr[0]);
    Console::WriteLine(arr[1]);
    Console::WriteLine(arr[2]);

    /*
    Output :-
      101
      201
      301
    */
} 

Natively accessing a jagged array

 Collapse
void Test2()
{
    array<array<int>^>^ arr = gcnew array<array<int>^>(2);
    arr[0] = gcnew array<int>(2);
    arr[1] = gcnew array<int>(2);
    arr[0][0] = 10;
    arr[0][1] = 100;
    arr[1][0] = 20;
    arr[1][1] = 200;

    Console::WriteLine(arr[0][0]);
    Console::WriteLine(arr[0][1]);
    Console::WriteLine(arr[1][0]);
    Console::WriteLine(arr[1][1]);

    /*
    Output:
      10
      100
      20
      200
    */


    // Copying the managed jagged array to

    // a native array of pointers and accessing

    // the members using the native array

    pin_ptr<int> p1 = &arr[0][0];
    pin_ptr<int> p2 = &arr[1][0];
    int* p3[2];
    p3[0] = p1;
    p3[1] = p2;

    Console::WriteLine(p3[0][0]);
    Console::WriteLine(p3[0][1]);
    Console::WriteLine(p3[1][0]);
    Console::WriteLine(p3[1][1]);

    /*
    Output:
      10
      100
      20
      200
    */

    // Assigning the native array of pointers

    // to a native int** and modifying the array

    int** p4 = p3;
    for(int i=0; i<2; i++)
        for(int j=0; j<2; j++)
            p4[i][j] += 3;          

    Console::WriteLine(arr[0][0]);
    Console::WriteLine(arr[0][1]);
    Console::WriteLine(arr[1][0]);
    Console::WriteLine(arr[1][1]);

    /*
    Output:
      13
      103
      23
      203
    */
}

Essentially we use a pinning pointer to the GC'd heap and then treat the casted native pointer as if it were pointing to a native array. Gives us a really fast method to manipulate array content!

Conclusion

Array syntax in C++/CLI is definitely an aesthetic improvement over the older MC++ syntax, and it also brings in a consistency of syntax that was severely lacking earlier. The template-style syntax should give a natural feel for C++ coders though it might take a little while before you fully get used to it. As usual, I request you to freely post any comments, suggestions, criticism, praise etc. that you might have for me.


출처 : http://www.codeproject.com/KB/mcpp/cppcliarrays.aspx

반응형
Posted by blueasa
, |
툴작업을 하다보면 Native C++에서 Managed C++에 접근해야 할 필요가 있다.
정확히 말해서 두 영역간의 소통이 필요할때가 있다.

예로 현재 작업 중인 툴에서 C#에 만들어진 Log 폼 다이얼로그에 로그를 찍고 싶을 때, Native C++에서 어떻게 작업을 해야할까?
Native C++에서는 Managed C++ 코드를 사용하거나 함수를 호출할수도 없다.
해결 방법 중 하나는 클래스 상속과 다형성을 이용하는 방법이다.

먼저 Native C++에서 밑의 코드와 같이 정의해준다

// 로그 클래스
class CLog
{
public:
        virtual void Print( const char* str ) = 0;
};

// 로그를 사용할 클래스
class CFramework
{
public:
        void SetLogger( ae_CLog* log ) { m_pLogger = log; }
private:
        CLog* m_pLogger;
}

그 다음 랩핑 클래스에서 위에서 정의한 CLog 클래스를 상속 받아 자식 클래스를 하나 만든다

public class ManagedLogger : public CLog
{
public:
        virtual void Print( const char* str )
        {
                // 이곳에 C#에서 수행할 작업을 코딩한다.
                // 이곳은 Unamanaged 영역이므로, 바로 Managed 코드를 못 쓴다.
                // 그러니 Managed 클래스에서 Static 함수를 만들어 여기서 호출해준다
                // 예) CFrameworkWrapper::WriteLog( str );
        }
};

주의할점은 주석에 적어놓았다. Managed 코드와 UnManaged 코드는 혼용될수 없으므로, 오로지 함수로만 통신을 해야한다.
자식 클래스를 정의 하였으면, 이제 이것을 사용해보자.

void CFrameworkWrapper::Create()
{
        m_pFrameWork = new CFramework();
        m_pFrameWork->SetLogger( new ManagedLogger() );
}

Native C++의 CFramework를 선언해주고, SetLogger 함수에 ManagedLogger 클래스의 객체 포인터를 넘겨주고 있다. ManagedLogger는 CLog 클래스를 상속받은 클래스 이므로, CLog 클래스로도 ManagedLogger 클래스를 가리킬수 있다. 이젠, 가상함수를 통해 Native C++ 영역에서 ManagedLogger의 함수를 호출할수 있는 것이다.


반응형
Posted by blueasa
, |

C++/CLI Singleton

Programming/C++/CLI / 2010. 10. 22. 16:12
public ref class MySingleton sealed
{
public:
	static MySingleton (void);
private: MySingleton (void);
public: static property MySingleton ^ mySingleton
{ MySingleton ^ get()
{ return m_mySingleton;
} } private: static MySingleton ^ m_mySingleton;
};

출처 : mine


ref class MyClass {
    // If you use a getter for 'instance' you can avoid 'initonly' keyword
    static MyClass^ instance = gcnew MyClass();

public:
    ...

    static property MyClass^ Instance
    {
        MyClass^ get()
        {
            return instance;
        }
    }
    ...
};

출처 : http://www.ureader.com/msg/14523461.aspx




반응형
Posted by blueasa
, |

※ C#에서 호출시 C++/CLI 에서 리턴값, 파라미터값은 다음과 같이 처리합니다.

 

 [ String - BSTR (LPCTSTR) ]

// ex: Set

bool SetTestString(String^ strTestString)
{
   axTestCtrl1->TestString= strTestString;
   return true;

}

// ex: Get
String^ GetTestString()
{
   return axTestCtrl1->TestString;
}

short, int, long ]

 

: short, int, long 형은 그냥 주고 받으면 됩니다.

// ex: Set

bool SetShortVal(short nShortVal)
{
   axTestCtrl1->ShortVar = nShortVal;
   return true;
}

// ex: Get
short GetShortVal()
{
   return axTestCtrl1->ShortVal;
}

struct ]

// ex: 참조 가능한 구조체 선언

ref struct EocsTestStruct
{
   String^ eocsstrVal;
   short eocsnVal;
   long eocslnVal;
}

 

// ex: 구조체를 파라미터로 받아서 Set

bool SetEocsTestStruct(EocsTestStruct^% EocsTest)

{

   try

  {
      axTestCtrl1->ShortVar = nShortVal;

      axTestCtrl1->eocsstrVal= EocsTest->eocsstrVal;

      axTestCtrl1->eocsnVal= EocsTest->eocsnVal;
      axTestCtrl1->eocslnVal= EocsTest->eocslnVal;
      return true;

   }

   catch (Exception^ e) 
   {
       MessageBox::Show(e->Message);
       return false;
   }
}

...

... ING ... : 다른 케이스도 작업하다가 정리할 예정입니다.

...

반응형
Posted by blueasa
, |

gcnew로 생성하지 않기

 

C++/CLI는 클래스를 생성할 때 ‘gcnew’를 사용하지 않고 생성할 수도 있습니다.

 

리스트 1. ‘gcnew’를 사용하지 않고 클래스 생성하기 >

#include "stdafx.h"

#include <stdio.h>

 

using namespace System;

 

ref class ManagedTest

{

public:

           ManagedTest() { Console::WriteLine(L"New ManagedTest"); }

           ~ManagedTest() { Console::WriteLine(L"delete ManagedTest"); }

          

           void func() { Console::WriteLine(L"Call func() - {0}", nNumber ); }

 

           int nNumber;

};

 

void foo1()

{

           ManagedTest MTest;

           MTest.nNumber = 1;

           MTest.func();

}

 

void foo2()

{

           ManagedTest^ MTest = gcnew ManagedTest();

           MTest->nNumber = 2;

           MTest->func();

}

 

int main(array<System::String ^> ^args)

{

           foo1();

           foo2();

          

           getchar();

           return 0;

}


결과 >


<리스트 1> ManagedTest MTest; 는 비 관리 C++처럼 GC가 아닌 스택 영역에 생성하는 것으로 착각할 수도 있겠지만 전혀 아닙니다클래스를 생성하면 언제나 GC 영역에 만들어집니다

위의 코드는 그냥 ‘gcnew’ 사용을 우리가 생략하고 컴파일러가 대신 써 준다고 생각하시면 됩니다.

 

void foo1()

{

           ManagedTest MTest;

           MTest.nNumber = 1;

           MTest.func();

}

은 컴파일러에 의해서 아래의 코드로 바뀝니다.

void foo1()

{

           ManagedTest^ MTest = gcnew ManagedTest();

           MTest->nNumber = 1;

           MTest->func();

           delete MTest;

}

 

위의 코드를 보시면 아시듯이 gcnew를 사용하지 않고 클래스를 생성하면 우리가 직접 delete를 쓰지 않아도 되는 편리함을 얻을 수 있습니다.

gcnew를 사용하지 않는 것은 C#에서 ‘using’을 간략화 시킨 것으로 생각하면 좋습니다.


< C# using 문 사용 예 >

using (Graphics g = this.CreateGraphics())

{

    g.DrawLine(Pens.Black, new Point(0,0), new Point(3,5));

}

 

 

 

 

value 클래스

 

관리 클래스는 복사 생성자와 대입 연사자를 가지지 못하므로 아래의 코드는 컴파일 에러가 발생합니다.

 

리스트 2. >

#include "stdafx.h"

#include <stdio.h>

 

using namespace System;

 

ref class C {

    int i;

};


void func(C c) {}


int main()

{

    C c;

    C d;

    func(c);   // 에러

    d = c;     // 에러

}

 

그러나 클래스를  ‘ref’가 아닌 ‘value’ 클래스로 정의하면 위의 코드는 컴파일 할 수 있습니다.

 

#include "stdafx.h"

#include <stdio.h>

 

using namespace System;

 

value class C {

    int i;

};

void func(C c) {}

int main()

{

    C c;

    C d;

    func(c);   // 에러

    d = c;     // 에러

}

 

value 클래스는 클래스간 복사를 할 수 있는 능력이 있습니다이 복사는 비트 단위의 복사로 이른바 ‘memcpy’와 같은 복사입니다.

value 클래스는 복사를 할 수 있으므로 value 클래스의 멤버는 절대 복사 가능한 멤버만 가질 수 있습니다그래서 아래와 같은 value 클래스 C는 컴파일 에러가 발생합니다.

 

ref class A

{

  int i;

};

 

value class C

{

  A a;

};

 

 

 value 클래스의 특징으로는 ref 클래스가 GC에서 만들어지는 것과 달리 스택에 만들 수 있습니다.

value class C

{

};

 

C c;

 

위 코드에서 클래스는 스택에 만들어집니다(물론 gcnew를 사용하면 GC에 만들어집니다)

 

value 클래스의 특징은 좀 더 있는데 위에 설명한 것들과 포함해서 아래와 같이 정리할 수 있습니다.

 


value 클래스의 특징

 

1. 기본 생성자를 가질 수 없다.

2. 복사 생성자를 가질 수 없다.

3. 대입 연산자를 가질 수 없다.

4. 소멸자를 가질 수 없다.

5. finalize를 가질 수 없다.

6. 클래스간 복사를 할 수 있다.

7. 복사 불가능한 것을 멤버로 가질 수 없다(ref 클래스 등).

8. 스택에 생성할 수 있다.

9. 다른 클래스를 계승할 수 없다( interface는 가능하다)

 

 

 


관리 클래스를 파라메터로 넘기기

 

ref class A

{

           int i;

};

 

void foo1( A a )

{

}

 

함수 foo1의 파라미터 정의는 클래스 A value 클래스일 때만 사용할 수 있습니다그러므로 아래와 같이 foo1의 파라미터를 정의해야 합니다.

void foo1( A^ a )

{

}

 

 

 

 

그 외….

 

C++/CLI에서 참조는 ‘%’을 사용합니다이것은 비 관리의 ‘&’와 구별이 됩니다.

%는 아래와 같은 경우에 유용하게 사용할 수 있습니다.

void foo( A^ a )

{

}

 

A a;

// foo( a );  // 에러

foo( %a ); // 성공


참조는 C#에서는 'ref', VB.NET에서는 'ByRef'와 같다고 생각하시면 됩니다.


// 값을 참조로 넘기는 경우

void valuebyref(int%i)
{
   i=5;
}

// 참조형을 참조로 넘기기
void refbyref(String^%s)
{
   s="newstring";
}

void main()
{
   int i=1;

   valuebyref(i);

   String^s="basestring";
   refbyref(s);
}
( 위 코드는 http://adversaria-june.blogspot.com/2006/08/ccli_26.html 에서 인용했습니다 )

 



구조체는 관리나 비 관리나 다른 점은 없습니다.


 

참조와 구조체는 너무 짧게 끝나버렸네요^^;


출처 : http://vsts2010.net/323

http://vsts2010.net/323

반응형
Posted by blueasa
, |