TEKKEN 6 BR 커맨드 리스트 & 콤보 공략 사이트
'Game' 카테고리의 다른 글
| 공방작렬! 수라 온라인 플레이 영상 최초 공개 (0) | 2010.10.20 |
|---|---|
| Tekken Tag Tournament 2 발표! (0) | 2010.09.28 |
| 메탈 기어 솔리드 라이징 E3 트레일러 (0) | 2010.06.23 |
| [플래시] 스나이퍼 게임 (0) | 2010.03.23 |
| 인디 2D격투게임 퀄리티의 끝을 보여주다. 뱅가드 프린세스 (0) | 2010.03.23 |
| 공방작렬! 수라 온라인 플레이 영상 최초 공개 (0) | 2010.10.20 |
|---|---|
| Tekken Tag Tournament 2 발표! (0) | 2010.09.28 |
| 메탈 기어 솔리드 라이징 E3 트레일러 (0) | 2010.06.23 |
| [플래시] 스나이퍼 게임 (0) | 2010.03.23 |
| 인디 2D격투게임 퀄리티의 끝을 보여주다. 뱅가드 프린세스 (0) | 2010.03.23 |
| Metacognition (0) | 2010.07.13 |
|---|---|
| 창의성의 아이러니 (0) | 2010.07.13 |
| [펌] 특수문자,수학기호 읽는법 (1) | 2010.05.14 |
| Source Insight 간단한 실행방법 (0) | 2010.05.14 |
| 브레인스토밍(brainstorming)-브레인스토밍(brainstorming)의 정의, 브레인스토밍(brainstorming) 방법 (1) | 2010.05.04 |
세가지의 라이브러리나 어셈블리를 혼합해서 사용 할 경우 기본 셋팅으로는 디버깅 시 C++ 라이브러리 쪽으로 진입이 불가능 하다.
C# 프로젝트 속성 -> 디버그 탭 -> 디버거 사용 -> '비관리 코드 디버깅 사용'
C++ 프로젝트 속성 -> 디버깅 -> 디버거 형식 -> '혼합'
으로 수정 해준다.
| C++/CLI 빌드 시, LNK2019 에러 #2 (0) | 2010.06.07 |
|---|---|
| C++/CLI 빌드 시, LNK2019 에러 #1 (0) | 2010.06.07 |
| C#과 C++/CLI의 Finalize, IDisposable Pattern 차이 (1) | 2010.06.01 |
| LNK2019 error @16 외부 기호 @4 함수)에서 확인하지 못했습니다. (2) | 2010.06.01 |
| C#에서 Native C++ 프로젝트 사용하기 (0) | 2010.05.31 |
암만 봐도 복잡하기 짝이 없는 패턴. 하지만 이보다 더 단순한 패턴을 내 머리로 만들어낼 궁리는 안한다(나올 가능성도 거의 없겠지만). 다음은 상기 사항에 대한 C++/CLI 쪽 pattern. 이 역시 MSDN에 명시된 내용이다.// 기반 클래스에서의 구현 pattern
public class Base: IDisposable
{
public void Dispose()
{
Dispose(true);
// GC가 Finalize를 호출하지 않도록 함(중복호출 배제)
GC.SuppressFinalize(this);
}
// disposing 플래그를 통해 Finalize에서 managed 리소스
// 를 정리하지 않도록(해당 리소스는 GC가 정리할 것임)
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// Managed 리소스 정리
}
// Unmanaged 리소스 정리
}
// C# 소멸자. Finalize 메서드임
~Base()
{
// 단순히 Dispose(false).
Dispose (false);
}
}
// 파생 클래스에서의 구현 pattern
public class Derived: Base
{
protected override void Dispose(bool disposing)
{
if (disposing)
{
// managed 리소스의 정리
}
// Unmanaged 리소스 정리// 부모 개체의 리소스를 정리하도록
base.Dispose(disposing);
}
// 파생 클래스에서는 소멸자 정의를 하지 않음(부모 소멸자// 에서 재정의된 Dispose를 호출할 것이므로)
}
MSDN에는 몇몇 설명으로 위 C++/CLI의 패턴을 설명하다 마무리 짓는데, 상당히 난감해진다. 패턴은 왜 달라지는지, 달라지면서 없어진 GC.SupressFinalize(), Dispose(bool)은 어디로 갔는지 등에 대한 설명은 없거나 부실하다. 게다가 파생 클래스에 대한 언급은 아예 없어 과연 위 내용이 올바른 내용인가하는 의심까지 들 정도.ref class A {
// Dispose()에 해당하는 소멸자. delete를 통해 명시적 호출 가능.// Native C++의 가상 소멸자와 동일한 행동 양식
// (스택 기반 semantic 개체 생성 시, 자동 호출됨)
~A() {
// managed 리소스 제거// ...
// finalizer를 통한 unmanaged 리소스 제거
this->!A();}
// Finalize에 해당하는 Finalizer
!A() {// unmanaged 리소스 제거
}
};
1. C++/CLI에서의 소멸자는 virtual 키워드가 없더라도 무조건 가상 함수이다.위의 결론은 김형준님의 C++/CLI의 Dispose Pattern에 대한 고찰과 유사한 실험 및 생성된 IL 코드 분석을 통해 이루어졌다.
2. finalizer의 가시성 범위는 accessor가 있건 없건 private이다.
3. destructor와 finalizer가 IDisposable::Dispose와 Finalize()를 완전 대체하지는 않는다. 컴파일러는 IL 코드 내에 Dispose()와 Finalize()를 따로 삽입하며, 각기 내부에서 destructor와 finalizer를 적절히 호출한다.
4. destructor가 호출되면 finalizer는 호출되지 않는다. 이는 IL 코드 내 Dispose() 구현에서 GC.SupressFinalizer()를 호출하기 때문이다.
5. 위 코드를 기반으로 한 컴파일된 IL 코드는 C# 버전과 거의 흡사하다(Dispose(bool)을 통한 파생 클래스에서의 리소스 정리 등).
6. 위와 같은 내용을 기반으로, 파생 클래스에서 역시 위 패턴과 동일하게 작성하면 된다(destructor 또는 Finalizer 등에서 base 클래스의 destructor/finalizer 명시적 호출 등 부가적 행동 불필요).
| C++/CLI 빌드 시, LNK2019 에러 #1 (0) | 2010.06.07 |
|---|---|
| C# + CLI + C++ 혼합 디버깅 (0) | 2010.06.01 |
| LNK2019 error @16 외부 기호 @4 함수)에서 확인하지 못했습니다. (2) | 2010.06.01 |
| C#에서 Native C++ 프로젝트 사용하기 (0) | 2010.05.31 |
| 마샬링(Marshaling) (0) | 2010.05.27 |
| C# + CLI + C++ 혼합 디버깅 (0) | 2010.06.01 |
|---|---|
| C#과 C++/CLI의 Finalize, IDisposable Pattern 차이 (1) | 2010.06.01 |
| C#에서 Native C++ 프로젝트 사용하기 (0) | 2010.05.31 |
| 마샬링(Marshaling) (0) | 2010.05.27 |
| System::String 관련 (0) | 2010.05.26 |
Lib 프로젝트 생성
Native C++에 해당하며, 실제 프로그램 로직등은 이곳에 속해있다.
간단하게 Framework 클래스를 만들어보자.
DLL 프로젝트 생성
프로젝트 속성에서 공용 언어 런타임 지원을(/clr) 설정해준다.
위에 작성한 프로젝트를 빌드 후 나오는 Lib 파일을 불러오고, 헤더를 추가해준다.
랩핑 클래스를 작성하고, 랩핑할 클래스의 객체를 선언 후 사용하면 된다.
밑의 코드에서 CFramework의 Create함수를 랩핑하고 있다.
C# 프로젝트 생성
C#의 Windows 응용프로그램 프로젝트를 생성해준다.
폼 디자이너에서 적당히 폼을 만들어주고 PictureBox 컨트롤을 배치해준다. 이 컨트롤에 실제 화면이 그려지게 된다.
그 다음 솔루션 탐색기에서 참조 추가를 이용해 위에 작성한 프로젝트의 DLL ( 미리 빌드 해놓자 )을 찾아서 추가해준다.
DLL이 성공적으로 추가 되면, 랩핑 클래스를 사용할수 있게 된다.
랩핑 클래스에서 선언한 네임 스페이스를 선언한 후 랩핑 클래스 객체를 생성하자.
그 다음 Create 함수에 PictureBox 핸들을 인자로 넘겨주면, Native C++쪽의 CFramework에서 이 핸들을 쓸수 있게된다.
정상적으로 작업이 수행되면, Native C++쪽에서 만들어지는 화면이 C#의 PitureBox에 그려지게 된다
| C#과 C++/CLI의 Finalize, IDisposable Pattern 차이 (1) | 2010.06.01 |
|---|---|
| LNK2019 error @16 외부 기호 @4 함수)에서 확인하지 못했습니다. (2) | 2010.06.01 |
| 마샬링(Marshaling) (0) | 2010.05.27 |
| System::String 관련 (0) | 2010.05.26 |
| 혼합 모드에서 디버깅 (0) | 2010.05.26 |
| C# 디자인패턴 (0) | 2010.12.15 |
|---|---|
| Dependency를 관리하는 방법 (0) | 2010.10.21 |
| Design Pattern Examples in C# (0) | 2010.07.23 |
| GoF의 디자인패턴 (0) | 2010.07.23 |
| FSM - 유한 상태 기계 (Finite State Machine) (0) | 2010.07.09 |
개요
Win32 API를 불러올 때, 함수의 명칭, 인자, 리턴 값을 가지고 불러오게 되어 있다. 하지만, C#에서 타입들이 모두 객체(Object)의 형식이며, 일반적인 C 의 데이터 형과 상이한 모양을 가진다. 이러한 문제들을 해결할 수 있는 것이 PInvoke 기능이다.
PInvoke( Platform Invocation Service)는 관리화 코드에서 비관리화 코드를 호출할 방법을 제공한다. 일반적인 용도는 Win32 API의 호출을 위해 사용한다.
|
namespace PinvokeExample { using System; using System.Runtime.InteropServices; // 반드시 입력해야 한다. public class Win32 { [DllImport(“user32.dll”)] public static extern int FindWindow(string a, string b); … } } |
위 예제는 FindWindow라는 user32.dll의 C함수를 사용하는 모습을 보여주고 있다. 실제 FindWindow의 선언은 다음과 같다.
|
HWND FindWindow(LPCSTR swClassName, LPCSTR swTitle); |
HWND는 윈도우 핸들을 표현하는 32비트 정수 이므로, int형으로 치환되고 LPCSTR 형은 NULL로 끝나는 문자열을 표현한다. 이때 PInvoke는 string을 자동으로 LPCSTR로 치환해 주는 역할을 하게 된다.
이 문서에서는 이처럼 Win32 API 함수의 여러 유형들을 어떻게 C#에서 사용 할 것인지에 대하여 알아보자.
WIN32 데이터형의 치환
Win32 API에서 일반적으로 사용하고 있는 데이터형은 모두 C#의 데이터 형으로 치환될 수 있다.
|
Win32 API TYPE |
C# |
|
BOOL, BOOLEAN |
bool |
|
BYTE |
byte |
|
CALLBACK |
delegate |
|
COLORREF |
int |
|
DWORD |
int |
|
DWORD_PTR |
long |
|
DWORD32 |
uint |
|
DWORD64 |
ulong |
|
FLOAT |
float |
|
HACCEL |
int |
|
HANDLE |
int |
|
HBITMAP |
int |
|
HBRUSH |
int |
|
HCONV |
int |
|
(모든 HANDLE 타입) Hxxxx |
int |
|
LPARAM |
long |
|
LPCSTR |
[in] string [out] StringBuilder |
|
LPBOOL |
ref bool |
|
이외 LP* 형 |
ref 형식 |
|
UINT |
uint |
|
Uxxxx |
unsigned 타입들.. |
|
WORD |
Short |
|
WPARAM |
Uint |
Structure 의 전달
예를 들어 POINT 형의 경우,
|
typedef struct t_Point { int x; int y; } POINT; |
이것은 기본적으로 다음과 같이 선언될 수 있다.
|
[순차적] [StructLayout(LayoutKind.Sequential)]public struct Point { public int x; public int y;}
[명시적] [StructLayout(LayoutKind.Explicit)]public struct Point { [FieldOffset(0)] public int x; [FieldOffset(4)] public int y;} |
일차적으로 할당되는 메모리 레이아웃이 동일하다면, C#에서 바로 받아 들이 수 있다.
|
// BOOL SetWindowPos(POINT pos); 이런 함수가 있다고 가정하면… ^^ [DllImport (“user32.dll”)] public static extern bool SetWindowPos(Point pos); |
사용할 함수 이름 바꾸기
여기서 함수의 이름을 바꿔서 사용하고 싶다면 다음과 같이 변경하면 된다.
|
// BOOL SetWindowPos(POINT pos); [DllImport (“user32.dll”, EntryPoint = “SetWindowPos”)] public static extern bool ShowAt(Point pos); |
레퍼런스형 전달하기
LPPOINT형은 POINT의 포인터 형이므로 ref Point와 같이 사용 할 수 있다. 실제 사용하는 형식은 다음과 같다.
C 언어의 포인터의 경우 레퍼런스로 사용하려고 하면, ref 키워드를 사용하는 방법이 있다.
|
// BOOL SetWindowPos(HWND hWnd, LPRECT lpRect); [DllImport(“user32.dll”)] public static extern bool SetWindowPos(int hWnd, ref Rect lpRect); |
Out형 함수 인자 사용하기
MSDN 같은 곳에서 함수의 선언을 살펴보면 다음과 같은 형식의 함수를 볼 수 있을 것이다. 이러한 형식은 레퍼런스 형으로 결과를 함수의 인자에 보내겠다는 말이다. 이러한 형식은 Win32 API에서 많이 쓰이고 있고, 포인터를 사용하므로, 많은 주의를 기울여야 한다.
BOOL GetWindowRect(HWND hWnd, // handle to window LPRECT lpRect // window coordinates ); Parameters
hWnd [in] Handle to the window. lpRect [out] Pointer to a RECT structure that receives the screen coordinates of the upper-left and lower-right corners of the window. |
여기서 LPRECT는 앞 절에서 설명한 Structure의 전달을 참고하여 치환 될 수 있다.
여기서 lpRect는 RECT의 포인터이며, GetWindowRect 함수 내에서 이 포인터에 직접 값을 쓰게 되어 있다. 즉 이 포인터는 값을 기록하기 위한 인자이지, 값을 전달하기 위한 인자는 아닌 것이다. 이것은 또 다른 C# 레퍼런스 연산자인 out 키워드를 사용하여 쉽게 해결 할 수 있다.
|
public static extern bool GetwindowRect(int hWnd, out Rect lpRect); |
실제 사용하는 모습은 다음과 같다.
|
public static extern bool GetWindowRect(int hWnd, out Rect lpRect); … public static void UseFunction() { Rect _rect; // 값을 대입하지 않아도 된다. Win32.GetWindowRect(hwnd, out _rect); … } |
참고로 ref 키워드는 입력과 출력 둘 다 사용 할 수 있다. 그러나 ref를 사용하는 변수가 값이 설정되어 있다는 가정을 하고 있으므로, 이전에 반드시 어떠한 값을 입력해야 한다.
실제 사용 예는 다음과 같다.
|
public static extern bool GetWindowRect(int hWnd, ref Rect lpRect); … public static void UseFunction() { Rect _rect = new Rect(); // 꼭 값을 대입해야 한다. _rect.top = 20; _rect.left = 30; _rect.bottom = 50; _rect.right = 60; Win32.GetWindowRect(hwnd, ref _rect); … } |
여기서 잠깐
대중없이 Rect라는 구조체가 나오는데 이는 API에서 RECT형을 C#으로 바꾸어 사용하는 structure이다. 앞의 예제들은 다음과 같은 선언을 하였다고 가정한다.
[StructLayout(LayoutKind.Explicit)]public struct Point { [FieldOffset(0)] public int top;[FieldOffset(4)] public int left; [FieldOffset(8)] public int bottom; [FieldOffset(12)] public int right; } |
CALLBACK 함수의 선언
C 언어에서 콜백 함수는 함수 포인터로 존재하게 된다. 이것은 함수 인스턴스의 포인터로, 함수 자체를 전달하게 되는 방식이다. 대표적으로 사용되는 부분은 EnumWindows 함수이다.
|
// BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARMAM IParam) |
이 함수는 현재 열려 있는 모든 윈도우 핸들을 열거하기 위한 함수로 실제 처리하는 부분은 함수 포인터, 즉 콜백함수인 lpEnumFunc에서 처리하게 되어 있다. WNDENUMPROC 타입의 선언은 다음과 같다.
|
// typedef BOOL (CALLBACK* WNDENUMPROC)(HWND, LPARAM); public delegate bool Callback(int hWnd, long lParam); |
이러한 콜백 함수 역할을 하는 C#의 프리미티브는 delegate이다. CALLBACK은 delegate로 지환된다.
결과적으로 다음과 같이 사용하게 된다.
|
namespace ada.appshare { … public delegate bool Callback(int hwnd, int lParam); … internal class Win32 { … internal static extern int EnumWindows(CallBack x, int y); [DllImport("user32.dll")] public static bool EnumWindowsCallback(int hWnd, int lParam) System.Console.WriteLine(“” + hWnd); return true; } … } public static void { Win32.Callback call Win32.EnumWindows(call, 0); } } |
[출처] C#에서 Win32 API 사용하기|작성자 대빵맨
| Windows Message를 수신하기 위한 WndProc의 이용 (0) | 2010.06.03 |
|---|---|
| codeproject의 C++을 알고있는 사람들을 위한 C# 퀵강좌 (0) | 2010.06.03 |
| 창 핸들값 구하는 API 함수 (0) | 2010.05.28 |
| C# 자식폼에서 부모폼으로 값 넘기기 (2) | 2010.05.28 |
| C# Namespace 정리 (0) | 2010.05.27 |
[출처] [C#.NET][API] 창 핸들값 구하는 API 함수 |작성자 JJANG
| codeproject의 C++을 알고있는 사람들을 위한 C# 퀵강좌 (0) | 2010.06.03 |
|---|---|
| C#에서 Win32 API 사용하기 (0) | 2010.05.28 |
| C# 자식폼에서 부모폼으로 값 넘기기 (2) | 2010.05.28 |
| C# Namespace 정리 (0) | 2010.05.27 |
| Windows Forms 컨트롤 사용 방법 시리즈 – Visual C# (0) | 2010.05.27 |
private void button3_Click(object sender, EventArgs e)
{
Form2 chfm = new Form2();
chfm.ShowDialog(this);
}private void button1_Click(object sender, EventArgs e)
{
((Form1)(this.Owner)).temp = textBox1.Text;
}public Form2()
{
InitializeComponent();
}
public Form1 fm;private void button3_Click(object sender, EventArgs e)
{
Form2 chfm = new Form2();
chfm.fm = this;
chfm.ShowDialog();
}private void button1_Click(object sender, EventArgs e)
{
fm.temp = textBox1.Text;
}| C#에서 Win32 API 사용하기 (0) | 2010.05.28 |
|---|---|
| 창 핸들값 구하는 API 함수 (0) | 2010.05.28 |
| C# Namespace 정리 (0) | 2010.05.27 |
| Windows Forms 컨트롤 사용 방법 시리즈 – Visual C# (0) | 2010.05.27 |
| JIT (0) | 2010.05.26 |