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

카테고리

분류 전체보기 (2737)
Unity3D (817)
Programming (474)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (228)
협업 (58)
3DS Max (3)
Game (12)
Utility (136)
Etc (96)
Link (32)
Portfolio (19)
Subject (90)
iOS,OSX (53)
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
04-20 00:00

abstract(C# 참조)

Programming/C# / 2010. 9. 14. 16:50

abstract 한정자는 클래스, 메서드, 속성, 인덱서 및 이벤트에 사용할 수 있습니다. 클래스 선언에 abstract 한정자를 사용하면 해당 클래스가 다른 클래스의 기본 클래스로만 사용됨을 나타냅니다. abstract로 표시된 멤버나 abstract 클래스에 포함된 멤버는 해당 abstract 클래스에서 파생되는 클래스에 의해 구현되어야 합니다.

이 예제에서 Square 클래스는 ShapesClass에서 파생되므로 Area의 구현을 제공해야 합니다.

      abstract class ShapesClass
{
    abstract public int Area();
}
class Square : ShapesClass
{
    int x, y;
    // Not providing an Area method results
    // in a compile-time error.
    public override int Area()
    {
        return x * y;
    }
}

추상 클래스에 대한 자세한 내용은 추상 및 봉인 클래스와 클래스 멤버(C# 프로그래밍 가이드)를 참조하십시오.

설명

추상 클래스에는 다음과 같은 특징이 있습니다.

  • 추상 클래스는 인스턴스화할 수 없습니다.

  • 추상 클래스에는 추상 메서드 및 접근자가 포함될 수 있습니다.

  • 추상 클래스를 sealed(C# 참조) 한정자로 한정할 수 없습니다. 즉, 이 클래스는 상속되지 않습니다.

  • 추상 클래스에서 파생된 비 추상 클래스에는 상속된 모든 추상 메서드 및 접근자의 실제 구현이 포함되어야 합니다.

메서드 또는 속성 선언에 abstract 한정자를 사용하면 해당 메서드 또는 속성에 구현이 포함되지 않음을 나타냅니다.

추상 메서드에는 다음과 같은 특징이 있습니다.

  • 추상 메서드는 암시적으로 가상 메서드입니다.

  • 추상 메서드 선언은 추상 클래스에서만 허용됩니다.

  • 추상 메서드 선언에서는 실제 구현을 제공하지 않기 때문에 메서드 본문이 없습니다. 메서드 선언은 단순히 세미콜론으로 끝나며 시그니처 뒤에 중괄호({ })가 없습니다. 예를 들면 다음과 같습니다.

    public abstract void MyMethod();
    
  • 구현은 비추상 클래스의 멤버인 재정의 메서드 override(C# 참조)에 의해 제공됩니다.

  • 추상 메서드 선언에 static 또는 virtual 한정자를 사용하면 오류가 발생합니다.

추상 속성은 추상 메서드와 비슷하게 작동하지만 선언 및 호출 구문에 차이가 있습니다.

  • 정적 속성에는 abstract 한정자를 사용할 수 없습니다.

  • 상속된 추상 속성은 override 한정자를 사용하는 속성 선언을 포함하는 방법을 통해 파생 클래스에서 재정의될 수 있습니다.

추상 클래스는 모든 인터페이스 멤버에 대한 구현을 제공해야 합니다.

인터페이스를 구현하는 추상 클래스는 인터페이스 메서드를 추상 메서드에 매핑할 수도 있습니다. 예를 들면 다음과 같습니다.

interface I 
{
    void M();
}
abstract class C: I 
{
    public abstract void M();
}
예제

다음 예제에서 DerivedClass 클래스는 추상 클래스 BaseClass에서 파생되었습니다. 이 추상 클래스에는 추상 메서드 AbstractMethod와 두 개의 추상 속성 XY가 포함되어 있습니다.

// abstract_keyword.cs
// Abstract Classes
using System;
abstract class BaseClass   // Abstract class
{
    protected int _x = 100;
    protected int _y = 150;
    public abstract void AbstractMethod();   // Abstract method
    public abstract int X    { get; }
    public abstract int Y    { get; }
}

class DerivedClass : BaseClass
{
    public override void AbstractMethod()
    {
        _x++;
        _y++;
    }

    public override int X   // overriding property
    {
        get
        {
            return _x + 10;
        }
    }

    public override int Y   // overriding property
    {
        get
        {
            return _y + 10;
        }
    }

    static void Main()
    {
        DerivedClass o = new DerivedClass();
        o.AbstractMethod();
        Console.WriteLine("x = {0}, y = {1}", o.X, o.Y);
    }
}

출력

x = 111, y = 161
설명

앞의 예제에서 다음과 같은 문으로 추상 클래스를 인스턴스화하려고 하면

BaseClass bc = new BaseClass();   // Error

컴파일러에서 추상 클래스 'BaseClass'의 인스턴스를 만들 수 없다는 오류가 발생합니다.


출처 : http://msdn.microsoft.com/ko-kr/library/sf985hc5(VS.80).aspx

반응형

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

C#에서 다중 상속 비슷한 기능이 필요할 때..  (0) 2010.09.15
interface(C# 참조)  (0) 2010.09.14
이벤트 만들기 (초보자)  (0) 2010.09.14
STL map == C# Dictionary  (0) 2010.09.13
자동 업데이트 프로그램  (1) 2010.09.10
Posted by blueasa
, |

내개만든 객체를 다른 객체에 이벤트를 사용하게 하기 위해서는 6가지로 나누어 볼수 있읍니다..

 

 이벤트를 발생시키는 객체서는4가지입니다

 이중 1,2는 매개 변수가 없을때 기본생성자를 사용함으로 생락 가능

 

 구독에서는 5,6번으로 폼 이벤트 사용할때 주로 사용을 많이 해봤을것으로 압니다

 

 

 이해 안되면  매개 변수가 있으면 구독 4가지,없으면 2가지 그냥 외우면 됩니다..

그리고 나만의 예제 하나 만들어 보면 모든데 이해 될것으로 생각 됩니다.

 

  

이벤트 사용하기

1.    새로운 데이터 타입 생성 [생락가능]

매개 변수가 없는 이벤트를 생성시 기본 생성자 public delegate void EventHandler(object sender, EventArgs e)를 사용하면 됨으로 생략 ,여기서는 minEventHandler라는 새로은 데이터 타입

public delegate void minEventHandler(object sender,minEventTestArgs e);//델리게이트 선언

 

2. 이벤트 매개 변수를 위한 객체 생성 [생락가능]

     1번의 두 번째 매개 변수에 사용하기 위한 객체로서 매개 변수로 넘길 데이터가 없으면 그냥 EventArg를 사용해도 됨.

public class minEventTestArgs : EventArgs

        {

        public DateTime m_Timer{get;set;}

        public minEventTestArgs(DateTime Timer)

        {

            this.m_Timer = Timer;

        }

  

3. 이벤트 정의 a 1번의 인터페이스

public event minEventHandler minEventTest;  // 이벤트 정의

 

4. 이벤트 발생

public void OnMinEventTest(minEventTestArgs e)  // 이벤트 발생 구독자에게 통보

        {

            if (minEventTest != null)

                minEventTest(this, e);

 }

 

 

-----------------------------------------------------

5. 이벤트 핸들러 메소드

minTimer min;  //       

  private void Form1_Load(object sender, EventArgs e)

  {

            min = new minTimer();

            min.minEventTest += new minEventHandler(min_minEventTest);

 }

 

6. 이벤트 구독

Void min_minEventTest(object sender, minEventTestArgs e)

       {

            textBox1.Text = e.m_Timer.ToLongTimeString();

       }

 

 

=========================================================================================== 

여기서 부터 는  예제

1 minTimer라는 객체를 하나 만들고

이 객체는 1초마다 현재 시간을 알려주는 이벤트를 생성한는일을 함.

2 폼 에서는 minTimer객체 인터페이스를 만들고 이벤트를 구독한다

 

using System;

namespace WindowsFormsApplication1

{  

    public delegate void minEventHandler(object sender,minEventTestArgs e); //새로운 객체

    public class minTimer

    {

        System.Windows.Forms.Timer timer;               //시간을 읽어오는 타이머

      

        public event minEventHandler minEventTest;         //[2] 이벤트 정의

        public void OnMinEventTest(minEventTestArgs e)  //[3] 이벤트 발생 구독자에게 통보

        {

            if (minEventTest != null)

                minEventTest(this, e);

        }

 

        //

        public minTimer()

        {

            timer = new System.Windows.Forms.Timer();

            timer.Interval = 1000;

            timer.Enabled = true;

            timer.Start();

            timer.Tick += new EventHandler(timer_Tick);

        }

 

        //

        void timer_Tick(object sender, EventArgs e)

        {

            DateTime curTime = DateTime.Now;

            minEventTestArgs args = new minEventTestArgs(curTime);

            OnMinEventTest(args);

        }

    }

 

    // [1] 이벤트 인자를 위한 객체

    public class minEventTestArgs : EventArgs

    {

        public DateTime m_Timer{get;set;}

        public minEventTestArgs(DateTime Timer)

        {

            this.m_Timer = Timer;

        }

    }

}

 

-----------------------------------------------------------------------

폼에서

minTimer min; //       

        private void Form1_Load(object sender, EventArgs e)

        {

            min = new minTimer();

            min.minEventTest += new EventHandler(min_minEventTest);

         }

 

        void min_minEventTest(object sender, minEventTestArgs e)

        {

            textBox1.Text = e.m_Timer.ToLongTimeString();

        }

 

 

 

잘못된부분 있으면 정보 공유 차원에서라도

답글 부탁 합니다,


출처 : http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=18&MAEULNO=8&no=1831&page=4

반응형

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

interface(C# 참조)  (0) 2010.09.14
abstract(C# 참조)  (0) 2010.09.14
STL map == C# Dictionary  (0) 2010.09.13
자동 업데이트 프로그램  (1) 2010.09.10
간단한 자동 업데이트 프로그램 구현  (0) 2010.09.10
Posted by blueasa
, |

[MSDN] ms-help://MS.MSDNQTR.v80.ko/MS.MSDN.v80/MS.VisualStudio.v80.ko/dv_vccore/html/5f710bf1-88ae-4c4e-8326-b3f0b7c4c68a.htm
반응형

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

C + + 프로그래머를위한 C + + / CLI 소개  (0) 2010.10.05
C++/CLI article in MSDN  (0) 2010.10.02
C++/CLI에 대해서 알아두어야 할 것들  (0) 2010.09.13
C++/CLI Type  (2) 2010.09.13
Win32 API TYPE <-> C# TYPE  (0) 2010.07.20
Posted by blueasa
, |
初音ミクが 円周率 10,000桁 覚え たようです。
(하츠네 미쿠가 파이 10,000 자리 기억할 것 같습니다.)


중독된다~ =ㅁ=;;
반응형
Posted by blueasa
, |

예전 C++에서 사용한 STL의 map을 사용하고 싶었다..
  구글형한테 열심히 물어본결과 C#에는
Dictionary라는 map과 일치하는 라이브러리가 존재한단다..

  사용해보니 Key값과 Value값을 이용하는 아주 전형적인
map이다.
  내부 알고리즘은 안뜯어봐도 거기서 거기일듯 하다..
 
  한가지 다른건 STL map에서는 Key값을 모를때
iteraterfor문을 이용한 순차접근을 했다는것이고..
 
Dictionary에서는 KeyValuePair  foreach문을 이용한 순차접근을 해야한다는 것이다..

  다음은
DictionaryKey값을 모를때 순차접근을 위한 하나의 예이다..

  Dictionary<string,int> _DicSample;
  _DicSample= new Dictionary<string,int>();
  _DicSample.Add( "나이", 32 );
  _DicSample.Add( "키", 180 );

  foreach (KeyValuePair<string, int> each in _Dic )
  {
     string K = each.Key;
     int V = each.Value;
  }
  // 디버깅 해보면 foreach문이 총 2번돌고 K와 V값에는 "나이", 32 다음 "키" 180이 순차적으로
 들어간다.

  Key값을 알고있을때 Value값 찾는건 map과 동일한
  int age = _DicSample["나이"];
 // age에 32가 들어갈것이다.


출처 : http://incoinco.blog.me/70046275252

반응형
Posted by blueasa
, |

이 글을 이해하기 위해서는…

C++/CLI에 대한 기본적인 이해가 필요합니다.

C++/CLI는 unmanaged code와 managed code의 경계를 허물어 준다.

그렇기 때문에 unmanaged code 영역에서 사용하는 C++의 특성과 managed C++가 갖는 C++의 특성을 모두 가지고 있다. 하지만, 이 두가지 특성이 모두 managed code에 반영되는 것은 아니다.

C++/CLI로 클래스 라이브러리를 작성한다면 다음과 같은 사실을 감안하여 코드를 작성하는 것이 좋다.

네이티브 타입은 더 이상 공짜가 아니다

2005 부터 네이티브 타입은 private 한정자가 적용된다. 소스 수준에서 한정자를 변경하거나 컴파일 지시어 make_public 으로 한정자를 public 으로 변경해야 한다.

템플릿은 생성되지 않는다

템플릿 클래스, 템플릿 메소드 등은 타입에서 제외된다. 매니지드 클래스라 하더라도 템플릿으로 구현된 메소드는 클래스의 메소드에서 제거된다.

템플릿 클래스 타입을 만들고자 한다면 제너릭 클래스 타입을 정의해야 한다.

typedef는 타입이 아니다

C++에서 typedef는 새로운 타입을 생성하는 것이 맞다. 하지만, C++/CLI에서 생성하는 닷넷 클래스 라이브러리에서 typedef는 새로운 타입으로 노출되지 않는다.

하지만, C++/CLI에서 특정 타입의 포인터 타입에 대한 Type 클래스를 얻고자 한다면, typedef로 포인터 타입을 정의해야 한다.

네이티브 타입은 값 타입이다

네이티브 타입은 값 형식으로 정의된다.

새로운 네이티브 타입을 정의하지 말아라

새로 정의한 네이티브 타입을 다른 모듈에서 참조할 때는 여전히 헤더 파일과 라이브러리를 필요로 한다. 당연한 얘기지만, C++/CLI의 닷넷 클래스 라이브러리는 managed C++이 아닌 링커를 위한 라이브러리를 생성하지 않는다.

새로운 네이티브 타입은 오직 닷넷 클래스 라이브러리 내부에서 사용할 용도로만 정의해야 한다.

어셈블리에는 AssemblyInfo 속성이 필요하다

어셈블리는 AssemblyInfo 속성을 포함해야 한다.

그러나, 어셈블리에서 AssemblyInfo 속성 값들을 정의하지 않아도 빌드 에러가 발생하지 않으며, 심지어 오브젝트 뷰어에서 라이브러리로 구현한 클래스들을 확인할 수 있고, C#에서 클래스 라이브러리를 사용하는데 문제가 발생하지 않는다.

하지만, C++/CLI의 managed code에서 이 라이브러리를 사용하고자 할 때, 타입들이 정의되지 않았음을 알게될 것이다. 어셈블리의 AssemblyInfo 속성을 빼먹으면 그렇게 된다.

필요한 모든 클래스를 정의해라

C++/CLI로 닷넷 클래스 라이브러리를 작성하는 경우 기존에 작성해 둔 수 많은 클래스를 다시 정의해야 하는지 고민할 수 밖에 없다.

하지만, 잊어라. 네이티브 클래스는 닷넷의 세계에서 존재하지 않는다. 닷넷 기반으로 필요한 모든 클래스는 새로 정의해야 한다. 다만, 새로 정의하는 클래스에서 이미 구현되어 있는 메소드들을 호출할 수 있도록 C++/CLI가 많은 도움을 준다.

그러나, C++/CLI의 역할은 managed code에서 unmanaged code로의 호출을 지원하고 두가지 타입의 코드가 공존하는 어셈블리를 생성하기 위함에 있다. 기존에 구현되어 있는 클래스를 재사용하기 위한 도구가 아니다.

수많은 C++/CLI 예제에서 괜히 매니지드 클래스를 위한 래퍼 클래스를 일일이 만드는 것이 아니다.


출처 : http://stratosphere631.com/wp/?p=866

반응형

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

C++/CLI article in MSDN  (0) 2010.10.02
C++ Interop 사용(암시적 PInvoke)  (0) 2010.09.14
C++/CLI Type  (2) 2010.09.13
Win32 API TYPE <-> C# TYPE  (0) 2010.07.20
C#, Managed C++ 참고 자료  (0) 2010.06.25
Posted by blueasa
, |

C++/CLI Type

Programming/C++/CLI / 2010. 9. 13. 17:43

■ C++/CLI Data Type

C++/CLI 는 3가지 데이터 타입을 가지고 있다.

    - Refercence Type
    - Value Type
    - Native Type



Native Type
C++ 이 가지고 있는 타입으로써 int, float, class, struct, 등이 있다.
타입 인스턴스의 메모리는 스택에 할당된다.
new 연산자로 동적 메모리 생성 하면 힙에 할당 된며, 메모리 해제는 프로그래머의 책임이다.

Value Type & Reference Type
Managed 환경의 Data Type 으로 모두 System::Object 클래스로 부터 상속받아 구현된다.
System::Object 가 외부로 노출시킨 메소드는 다음과 같다.

 Method Name  Return Value  Accssibility
 Equals  bool  public
 GetType  Type  public
 ToString  System::String^  public
 GetHashCode  int  public
 Finalize  -  protected
 MembewiseClone  System::Object^  protected
 ReferenceEquals  bool  public static


Value Type 은 System::ValueType 으로 부터 상속 받는다. System::ValueType 은 System::Object 를 상속 받는다. Value Type 은 메모리를 항상 스택에 할당한다. 모든 Primitive Data Type 과 Struct 들은 Value Type 이다.





■ Primitive Types Mapping

 Data Type Name  Type C++/CLI Keyword
 16bit Integer  System::Int16  short
 32bit Integer  System::Int32  int
 64bit Integer  System::Int64  __int64, long long
 Double  System::Double  double
 Character [2 bytes]  System::Char  char
 Character [1 byte]  System.Byte  byte
 Boolean  System.Boolean  bool

※ 이 밖에도 많은 타입이 정의되어 있다.
※ Primitive Type 은 Value Type 으로서 Stack 에 메모리 할당 된다.
※ Native Code 와 C++/CLI 간의 Primitive Type 값 변환은 별도의 조작없이 바로 해주면 된다.

Primitive Type 의 선언과 사용 예





C++/CLI 에서 Primitive Data Type 은 Value Type 으로서 .NET 의 Primitive Data Type 을 사용하는 방법과 동일하다.





■ Class & Struct

 Native Data Type  Managed Data Type
 class  ref class
 struct  value struct
 enum  enum class
 std::string  String^
 std::map  Dictionary^
 std::vector  List^
 std::list  List^
 function pointer  delegate


C++/CLI 에서 클래스는 Reference Type (.NET Framework 에서 클래스는 Reference Type 이므로 당연한 소리)  이다. Reference Type 의 인스턴스는 결코 스택에 할당되지 않는다. Reference Type 의 인스턴스는 힙에 할당된다. 그러나 이 힙은 Managed Heap 이라 불리며 Native type 이 사용하는 힙과는 다르다. "new" 키워드는 Native Heap 에 메모리를 할당하며, "gcnew" 는 Managed Heap 에 메모리를 할당한다. gcnew 를 사용하여 선언하는 방법은 다음과 같다.



위 방법은 C++/CLI 에서 Managed 객체를 생성하는 방법이다. Managed Heap 에 생성된 인스턴스에 접근하기 위해서는 "객체 참조 (Object Reference)" 또는 "Handle" 이라 불리는 것(위의 코드에서 objRef)을 통하여 접근 가능한데 이들은 스택에 할당된다. 객체 참조를 통하지 않고서는 인스턴스에 접근할 수 없다. 본질적으로 객체 참조는 주소를 물고 있다. 하지만 Native Code 의 포인터와는 같지 않다. 객체 참조는 포인터와 다르게 포인터 연산을 할 수 없다. Managed Heap 에 인스턴스는 하나 이상의 Reference 를 갖는다. 따라서 다른 객체로 객체 참조 shallow copy 가 가능하다. 
 .NET Framework 의 CLR 은 매우 영리하며, Garbage Collection 이 있기 때문에 프로그래머가 메모리 해제에 대해서 걱정할 필요가 없다. 하지만 Database open 과 같이 사용자가 할당한 메모리에 대해서는 사용자가 책임지고 메모리 해제 작업을 해주어야 한다.  다음은 C++/CLI 의 클래스 예 이다.



※ ref class
ref class 로 선언하게 되면 Managed Code 가 되어 가비지 컬렉터의 관리를 받게 된다.
ref class 로 선언되지 않은 클래스는 가비지 컬렉터의 관리를 받지 않으며 Unmanaged Code 이다. 따라서 일반 클래스로 동적 메모리 생성을 하였다면 직접 메모리를 해제시켜 주어야 한다.


※ ref class 작성 예



※ Destructor (소멸자)
일반적인 클래스와 마찬가지로 ref class 역시 소멸자가 존재한다. 또한 사용하는 방법 역시 똑같다. 하지만 ref class 의 소멸자는 IDisposable 인터페이스를 구현한 후에 컴파일러가 소멸자의 호출을 Dispose() 호출로 번역한다. 또한 finalizer 호출이 있는데 이는 Gabage Collector 에 의해 호출되며 "!MyClass()" 와 같이 정의된다. finalizer 는 소멸자가 호출되었는지 확인한 다음에 호출되지 않았다면 소멸자를 호출시켜준다.





■ Declaring and Consuming a Managed Class

1. 전형적인 방법


위 코드에서 caret [^] 는 변수 sysDir 이 Reference 인스턴스를 가리키고 있는 객체 참조 임을 나타낸다. 객체 참조를 통하여 클래스의 public 메소드를 호출할 수 있고, 또다른 객체 참조로 복사할 수 있다. ^ 으로 선언한 객체 참조는 gcnew 키워드를 통하여 Managed Heap 에 메모리 할당 되며 이 메모리는 Garbage Collector 의 관리를 받는다.


2. shallow copy


Managed Heap 에 생성된 Reference 참조를 sysDir 객체 참조가 가리키고 있는데, sysDir2 역시 같은 곳을 가리키게 하는 방법이다.


3. Invoke method


객체 참조 sysDir 을 이용하여 public 메소드를 호출(Invoke) 하는 방법이다.


4. 객체 참조의 매개변수로의 전달


 메소드의 매개변수로 객체 참조가 전달 되었다. 이 메소드 안에서 똑같은 객체에 대해서 작업할 수 있다. 객체 참조가 전달 될 때 복사 생성자는 호출되지 않는다. 즉, 객체의 복사본은 생성되지 않는다. 이것은 C++ 의 포인터를 넘겨 주는 방법과 비슷하다. 만약 복사본을 생성해야 한다면 당신이 작성한 클래스는 System::IClonalbe 인터페이스를 상속 받아야 하고, Clone() 메소드를 구현해야 한다.


5. 객체 참조의 리턴


위의 코드결과 Directory 객체가 생성된다. 할당된 인스턴스를 가리키고 있는 객체 참조가 리턴된다. 리턴된 후에 dirObj 는 Managed Heap 에 있는 객체를 더이상 가리키지 않는다. 리턴되는 객체 참조를 할당 받고, 그것을 보존하는 것은 메소드를 호출하는 쪽의 책임이다.





■ Abstract Class

클래스에 abstract 키워드를 붙이면 Managed Class 를 추상 클래스로 만든다. 이 방법은 추상 메소드(순수 가상 메소드) 선언 없이 클래스를 추상화 시키는 편리한 방법이다. 또한 메소드는 abstract 키워드로 선언된다.









■ 생성자
C++/CLI 클래스의 생성자는 기본 인수(Default parameter)를 가질 수 없다.
namespace ManagedMemFileEx
{
	public ref class CCliMemFileEx
	{
    public:
        explicit CCliMemFileEx(System::UInt32 _nGrowBytes = 1024);
        virtual ~CCliMemFileEx();
    };
}

위와 같이 기본 인자를 가진 생성자를 정의하면 다음과 같은 에러 메시지를 출력 한다.

"오류 1 error C3222: '_nGrowBytes' : 제네릭 함수 또는 관리되는 형식의 멤버 함수에 대한 기본 인수를 선언할 수 없습니다."





■ 참조
1. C++/CLI Primer - Enter the World of .NET Power Programming (CodeProject)
2. Quick C++/CLI - Learn C++/CLI in less than 10 minutes (CodeProject)


출처 : http://six605.tistory.com/385

반응형
Posted by blueasa
, |

IME 관련

Programming/C/C++ / 2010. 9. 10. 17:14

이준곤(LeeChen)님이 작성하신 IME 관련 내용 풀 소스로 만들어본것입니다.

뭐 큰 변경은 없지만 잘잘한 것 조금 변경했습니다.

 

 

#pragma comment(lib,"imm32.lib")
#include <windows.h>


LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
HINSTANCE g_hInst;
HWND hWndMain;

LPCTSTR lpszClass=TEXT("Ime1");

void putstring(HWND hWnd);
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance
       ,LPSTR lpszCmdParam,int nCmdShow)
{
     HWND hWnd;
     MSG Message;
     WNDCLASS WndClass;
     g_hInst=hInstance;
    

     WndClass.cbClsExtra=0;
     WndClass.cbWndExtra=0;
     WndClass.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);
     WndClass.hCursor=LoadCursor(NULL,IDC_IBEAM);
     WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
     WndClass.hInstance=hInstance;
     WndClass.lpfnWndProc=(WNDPROC)WndProc;
     WndClass.lpszClassName=lpszClass;
     WndClass.lpszMenuName=NULL;
     WndClass.style=CS_HREDRAW | CS_VREDRAW;
     RegisterClass(&WndClass);

 

     hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,
          CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
          NULL,(HMENU)NULL,hInstance,NULL);

     ShowWindow(hWnd,nCmdShow);
     hWndMain=hWnd;
    

     while(GetMessage(&Message,0,0,0)) {
          TranslateMessage(&Message);
          DispatchMessage(&Message);
    putstring(hWnd);
     }
     return (int)Message.wParam;
}

 


#include <imm.h>

char Text[255];     // 텍스트를 저장하기위한 변수
char Cstr[10];      // 조합중인 문자!!
char CanText[200];   // 특수문자를 위한 변수
int CNumber=0;        // 현제의 특수문자 위치
int CanMax=0;         // 현제 특수문자 목록의 최대 겟수

//WinAPI창에 출력
void putstring(HWND hWnd){
 //더블버퍼링 준비(백버퍼생성)
 HDC hDC = GetDC(hWnd);
 
 HDC hDCMem;
 RECT rect;
 HBITMAP BitMem, OldBitMap;

 hDCMem = CreateCompatibleDC(hDC);
 GetClientRect(hWnd, &rect);
 BitMem = CreateCompatibleBitmap(hDC, rect.right-rect.left, rect.bottom - rect.top);
 OldBitMap = (HBITMAP)SelectObject(hDCMem, BitMem);
 FillRect(hDCMem, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH)); // 전체를 하얗게

 //문자열 작성
 char Text1[255]; 
 memset(Text1,0,255);
 
 TextOut(hDCMem,0,60,CanText,strlen(CanText)); // 특수문자가 있음 찍어주기;.
 strcpy(Text1,Text);
 if(Cstr[0] != 0 ){
   strcpy(Text1 + strlen(Text), Cstr);
 }
 strcpy(Text1 + strlen(Text1), "_");
 TextOut(hDCMem,0,0,Text1,strlen(Text1));
 //ReleaseDC(hWnd,hDCMem);

 //백버퍼를 메인버퍼로 옮김
 BitBlt(hDC, rect.left,rect.top,rect.right - rect.left,rect.bottom - rect.top,hDCMem,0,0,SRCCOPY);
    BitMem = (HBITMAP)SelectObject(hDCMem, OldBitMap);
 //사용한 핸들 반환
 DeleteDC(hDCMem);
    ReleaseDC(hWnd, hDC);
    DeleteObject(BitMem);


}
//특수문자 처리
void GetCandi(HWND hWnd, WPARAM wParam, LPARAM lParam,int Number)
{
 DWORD       dwBufLen;    // 버퍼길이
 LPCANDIDATELIST lpCandList;   // 특수문자 리스트
 char aa[255];
 int i;
 LPCANDIDATELIST m_CandList;
 HIMC m_hIMC = ImmGetContext(hWnd);

    switch (wParam) {
        case IMN_OPENCANDIDATE:   // 처음 열렸을때.;;;;
   memset(CanText,0,100); //  특수문자가 들어갈 변수 초기화
   if(!(dwBufLen = ImmGetCandidateList(m_hIMC, 0, NULL,0)))break;//lpCandList, 0)))break;
            // 리스트의 길이 받기..
   m_CandList = (LPCANDIDATELIST)new char[dwBufLen];  // 길이만큼 메모리 얻기
   lpCandList = m_CandList;
   ImmGetCandidateList(m_hIMC, 0, lpCandList, dwBufLen);
            // 할당받은 데로 리스트를 받는다.
            // 아까도 그랬지만 인자에 따라서 같은 함수가 용도가 달라짐;;...
   CanMax=lpCandList->dwCount;
             // 특수문자 목록의 겟수를 넣는다!
   for(i=Number;i<Number+9; i++)                               // 한번에 9개만 보이니까 9개만받는다.
   {   
    if(i>=lpCandList->dwCount) break;
     // 모두 알다시피 더크면 뽀로롱~ 나간다!
     LPSTR lpStr = (LPSTR)lpCandList + lpCandList->dwOffset[i];
     // 문자얻기;.
    strcpy(CanText + strlen(CanText), lpStr);
     // 특수문자 문자열에 넣는다;.
     // 근데 왜 두번이나 지나서 넣는거지? -_-;.
   }
     delete m_CandList;     // 만든걸 날린다!
     m_CandList=NULL;       // 널을 넣는다;.(안넣어도 무방하다;.)
     CNumber = 0;           // 현제의 특수문자 번호를 0으로 만든다;.
    break;
   case IMN_CHANGECANDIDATE:  // 딴 키를 눌러서 새로운 목록으로 바꾸기라면
    memset(CanText,0,100); // 또 다 날린다!
    if(!(dwBufLen = ImmGetCandidateList(m_hIMC, 0, NULL, 0)))break;// 길이를 얻는다
    m_CandList = (LPCANDIDATELIST)new char[dwBufLen]; // 또 메모리 할당한다;.
    lpCandList = m_CandList;// 역시 위와 마찬가지로 어느날 이렇게;;.
    ImmGetCandidateList(m_hIMC, 0, lpCandList, dwBufLen);
        // lpCandList에 목록을 얻는다;.
    for(i=Number;i<Number+9; i++)                               // 한번에 9개만 보이니까 9개만받는다.
    {
     if(i>=lpCandList->dwCount) break;   // 역시 더크면 뾰로롱 나간다~
        LPSTR lpStr = (LPSTR)lpCandList + lpCandList->dwOffset[i];  // 위처럼 lpStr에 문자를 넣고..
     strcpy(CanText + strlen(CanText), lpStr);

          }
    delete m_CandList;           // 역시 할당한것을 날리고
    m_CandList=NULL;             // 리스트에 널을 넣는다.
    break;                       // 빠져나온다..
      case IMN_CLOSECANDIDATE:         // 목록 리스트가 닫힐경우.
    CanText[0]=0;                // CanText젤 앞에 0을 넣어버린다;;.
    break;
 }
 ImmReleaseContext(hWnd, m_hIMC);
}

int GetText(HWND hWnd,UINT msg,WPARAM wparam, LPARAM lparam)
{
 int len;     // 그냥 여기저기서 써먹을 변수!
 HIMC m_hIMC=NULL;   // IME 핸들

 switch (msg){
  case WM_IME_COMPOSITION:   // 글씨조합중
  m_hIMC = ImmGetContext(hWnd); //현재윈도우핸들이 ime핸들을 얻는다.
  if(lparam & GCS_RESULTSTR) //조합이 완료되면
  {
   len = ImmGetCompositionString(m_hIMC,GCS_RESULTSTR,NULL,0);//현재 IME의(조합중인) 스트링 길이를 얻는다.
   if(len >0)
   {
    ImmGetCompositionString(m_hIMC,GCS_RESULTSTR,Cstr, len);//Cstr에 조합중인 문자열을 받아낸다,.
    Cstr[len] = 0; //젤 끝에 0을 붙여서 끝을 표시한다.
    //조합중인 문자는 완료된 상태이기때문에 최종 문자저장소에 넣는다.
    //strcpy(Text+strlen(Text),Cstr); //전체 내용(실제 보일 텍스트) 뒤에 붙여준다.
    strcpy(Text+strlen(Text),Cstr);
    memset(Cstr,0,10); //지움
   }
  }
  else if (lparam & GCS_COMPSTR){  // 조합중이면;.
   len = ImmGetCompositionString(m_hIMC, GCS_COMPSTR, NULL, 0);// 조합중인 길이를 얻는다.
   ImmGetCompositionString(m_hIMC, GCS_COMPSTR, Cstr, len);   // str에  조합중인 문자를 얻는다.
   Cstr[len] = 0;// 뒤에 0을 붙인다.
   // 이렇게 해두시고 글씨 찍을때 Text + Cstr 하셔서 찍어주시면 된다
   // 이건 쫌있다가 찍는 예제를 하나 보여드리죠!
  }
  ImmReleaseContext(hWnd, m_hIMC);// IME 핸들 반환!!
  return 0;
    case WM_CHAR:              // 한글 이외의 나머지 글은 이리로 들어옵니다. ^^;.
  if(wparam == 8 ){      // 만약 8번(빽스페이스)라면..
   if(strlen(Text) > 0){   // 길이가 0보다 길면
    //isDBCSLeadByte  //한글의 첫번째 바이트라면 true 두번째 바이트나 영어라면 false;로 체크
    if(strlen(Text)>1 && IsDBCSLeadByteEx(949,Text[strlen(Text)-1])) // 949 means Hangul code page
    {
     //if(!IsDBCSLeadByteEx(0,Text[strlen(Text)-1])) //만약 특수키체크(특수키 '\' '?'등등);
     //{
     // Text[strlen(Text)-1] = '\0';   // 한자를 지운
     //}else
     {
      Text[strlen(Text)-2] = '\0';   // 한자를 지운다;.
     }
    }
    else //영어
    {
     Text[strlen(Text)-1] = '\0';   // 한자를 지운다;.
    }
    memset(Cstr,0,10);         // 조합중문자를 초기화..(왜했지? 기억이.)
    // 만약 글자 조합중 일때 빽스페이스가 들어오면 이리 메세지로 안들어
    // 오고 조합중이란 메세지로 들어오니 염려 놓으시길;;..
   }
  }else{  // 빽스페이스가 아니면..
   len = strlen(Text);
   Text[len] = wparam & 0xff;   //  넘어온 문자를 문자열에 넣기..
   //Text[len+1] = 0;               //  뒤에 0붙이깃!!
  }
  return 0;
    case WM_IME_NOTIFY:  // 한자입력...
   GetCandi(hWnd,wparam,lparam,CNumber);
   return 0;
     case WM_PAINT:
   {
    PAINTSTRUCT ps;
       HDC hdc=BeginPaint(hWnd,&ps);
     EndPaint(hWnd,&ps);
    return 0;
   }
    case WM_KEYDOWN:    // 키다운..
    if(CanText[0]==0) break; 
        // 특수문자에 글씨가 없뜨면;;..
        // 그러니까 창이 안열여뜨면!
    if(wparam == VK_PROCESSKEY){
        // 프로세스키로 들어가는거면..
     // 특수문자 창이 열렸을경우 이렇게 // 들어가요;;..
     if((lparam & 0xff0000) == 4915200){ // 왼쪽이면
       if(CNumber >0)CNumber-=9;  
   break;
     }
     if((lparam & 0xff0000) == 5046272){ // 오른쪽이면;;..
     if(CNumber+9 < CanMax)CNumber+=9;// 구더하기..
   break;
     }
   }
   break;
 }
  return 1;
}

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
 if(GetText(hWnd, iMessage,wParam, lParam) == 0)return 0;

     switch(iMessage) {

      case WM_DESTROY:
          PostQuitMessage(0);

          return 0;
     }

     return(DefWindowProc(hWnd,iMessage,wParam,lParam));

}

[출처] IME 관련|작성자 찐남자

반응형

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

[C++] 형변환 (Typecasting) - const_cast, reinterpret_cast, static_cast, dynamic_cast  (0) 2010.09.28
GameLoop (번역)  (0) 2010.09.16
TLS (Thread Local Strorage)  (0) 2010.08.30
TCHAR을쓰면 바뀌는 함수들  (0) 2010.07.27
TCHAR printf  (0) 2010.07.12
Posted by blueasa
, |

프로그램밍한 후 컴파일해보면 잘되는것이 옛날 VS6 이나 VS7 처럼 사용한 DLL 를 같이 포함해서 다른 컴퓨터로 가져와 실행하면 안되는 경우가 있다.

바로 Side by side assembly라는 것때문이라는거 때문인데.. 윈도우 디렉토리 밑에 WinSxS(Windows Side by Side) 폴더에 추가되면서 복잡하게 연결되었다는것이다.

 

해결하는 방법은 몇가지 있는데

1. 배포하려는 컴퓨터에 재배포 패치를 설치해주는거(작업했던컴퓨터가 아니다.)

Microsoft Visual C++ 2005 재배포 가능 패키지(x86)
Microsoft Visual C++ 2005 SP1 재배포 가능 패키지(x86)
Microsoft Visual C++ 2008 재배포 가능 패키지(x86)

 

 

2. 컴파일하면 나오는 .manifest 파일 안에 DLL 버젼을 파악후

C:\Program Files\Microsoft Visual Studio 8\VC\redist\x86\Microsoft.VC80.CRT 에서 복사해서 같이 배포하는방법 참고로 그안에있는 .manifest 도 같이 포함해야한다.

ex)

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type="win32" name="Microsoft.VC80.DebugCRT" version="8.0.50727.4053" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
    </dependentAssembly>
  </dependency>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type="win32" name="Microsoft.VC80.DebugMFC" version="8.0.50727.4053" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
    </dependentAssembly>
  </dependency>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="x86" publicKeyToken="6595b64144ccf1df" language="*"></assemblyIdentity>
    </dependentAssembly>
  </dependency>
</assembly>

처럼 보면  Microsoft.VC80.DebugCRT 과  Microsoft.VC80.DebugMFC 사용되었기때문에

C:\Program Files\Microsoft Visual Studio 8\VC\redist\x86\Microsoft.VC80.CRT 폴더에 있는 파일과 C:\Program Files\Microsoft Visual Studio 8\VC\redist\x86\Microsoft.VC80.MFC 파일을 복사해주면된다. 만약 디버그 버젼을 배포한다면 redist 폴더 안에 Debug_NonRedist 폴더 에 있는 걸 복사해주면된다.

 

3. 인스톨쉴드(Install Shield),나 설치 프로젝트를 이용한다.

4. 최신 버젼 .net Framework를 설치한다.

5. MFC 라면  정적 라이브러리에서 MFC 사용으로 컴파일해서 DLL를 실행파일에 포함시킨다.

 

참고1.:  http://msdn.microsoft.com/ko-kr/library/ms235285(VS.80).aspx

           http://gs4096.blogspot.com/2008/06/vs2005.html

           http://www.serious-code.net/moin.cgi/RedistributingVisualCppRunTimeLibrary

참고2.: http://microdev.pe.kr/69

 참고2 - 내용-

 Side by Side Assembly는 dll hell을 해소하기 위해 VS2005부터 지원하기 시작한 개념으로,
한 PC에서도 서로 다른 버전의 dll을 사용하는 어플을 동시에 실행시킬 수 있게 한다.
예를 들어, 버전 1.0.1인 dll A를 사용하는 어플과 1.0.2인 dll A를 사용하는 어플이 있을 때,
dll A를 버전별로 별도로 관리해서 각 어플이 해당 dll을 올바로 런타임에 링크하게 한다.
이 방식은 어떻게 보면 linux에서 so파일을 쓰지만 사실상 버전별로 다른 so파일을 쓰는 것과 유사한 점이 있다.

VS2005부터는 빌드시에 항상 manifest파일이 생성되며 이는 별도 파일로 생성하거나 dll 내부에 포함시키고 있다.
각 manifest파일에는 자신이 빌드시에 사용한 하위 dll들의 버전 정보등이 포함된다.
실행시에는 dll loader가 manifest파일을 보고 어떤 버전의 dll을 쓸지 결정해서 loading한다.


Visual studio에서 제공하는 CRT등의 dll은
    %WINDIR%\WinSxS\x86_Microsoft.VC90.CRT_<version>
과 같은
형태의 디렉토리에 각각 저장되며
    %WINDIR%\WinSxS\Manifests\x86_microsoft.vc90.crt_<version>.manifest
에 인스톨 정보가 남게 된다. 그리고
    %WINDIR%\WinSxS\Policies\x86_policy.9.0.Microsoft.VC90.CRT_<version>.policy
위와 같은 policy 파일을 통해 redirection도 가능하다.

보통의 경우에 VS2005를 설치하지 않은 PC에서 실행하기 위해서는 redistributable package라는 것을 다운받아 설치하면 CRT등의 dll이 해당 디렉토리에 설치되게 된다. 하지만, debug모드용 dll들은 이런 package에 포함되지 않은 듯 하다. 그래서 수동으로 필요한 파일들을 커파해야 하며, dll과 manifest외에 위의 policy와 인스톨 정보도 함께 카피해야 정상적으로 로딩에 성공한다.
그외에 trouble shooting 자료도 참조할것.

 

원문)http://raballe.tistory.com/entry/Side-by-Side-Assembly

반응형
Posted by blueasa
, |

變/Portfolio "

사용자 삽입 이미지
 프로그램의 자동 업데이트 기능은 인터넷 보급율이 타의 추종을 불허하는 국내에서는 필수적인 요소가 되어 버렸다. V3, 알약 같은 백신은 물론이고, 곰플레이어 등 사용자 Application에도 모두 포함되어 있다.

2년 전쯤에 간단한 기능의 자동 업데이트 프로그램을 만든 적 있었는데; 지인들도 찾지 않는 내 유령 블로그에서 (사실 나도 거의 하지 않는다..) 가장 인기 게시물이었다; 그 프로그램과 관련해 질문도 많이 받고, 링크 복구 요청도 많이 받아... 마지막으로 다시 올린다.

아래 DLL과 자동 업데이트 프로그램은 Microsoft Visual Studio.NET 2005를 이용해 C#으로 개발하였으며, 사용한 모든 함수는 Microsoft .NET Framework 2.0에 포함되어 있다.

 일단 자동 업데이트 프로그램의 구성은 매우 심플하다.
(1) 프로그램 버전 체크를 위한 DLL과 Configuration 파일
- UpdateChecker.dll
- update.ini

(2) 프로그램 업데이트를 위한 자동 업데이트 프로그램과 Configuration 파일
- SmartUpdater.exe
- start.ini

 프로그램의 자동 업데이트 로직은 간단하다. (물론, 복잡하게 만들려면 복잡하게도 만들 수 있으나, 그건 각자의 특수성에 맞게 고민해야할 문제.)

STEP 1. 프로그램을 실행한다.

STEP 2. 업데이트 서버에 연결하여, 현재 프로그램의 버전과 업데이트 서버가 가지고 있는 업데이트 버전과 비교해서 최신 업데이트가 있으면, 자동 업데이트 프로그램을 실행하고, 현재 프로그램을 종료한다.

 물론, 간혹 이런 경우도 있다. 자동 업데이트 프로그램을 업데이트해야 되는 경우; 그 때는 실행하기 전 자동 업데이트 프로그램의 파일명을 rename해서 변경한 후, 실행하면 된다; 그리고 프로그램 업데이트 후, rename된 자동 업데이트 프로그램을 삭제하면 끝;

(1) 프로그램 버전 체크를 위한 DLL의 함수들
사용자 삽입 이미지

DLL의 함수는 달랑 3개다. (하나는 기본 생성자)

ReadConfigFile은 업데이트 서버의 주소와 버전 정보가 담긴 파일명이 저장된 Configuration 파일(update.ini)을 읽는다. 말이 거창하게 Configuration 파일이지, 실제로 파일을 열어보면 달랑 2줄의 내용이 들어있다.

라인 1: http://www.nohungry.net/UpdateServer/
라인 2: version.txt

라인 1은 Update 서버의 URL이고, (반드시 끝에 /를 붙여줘야 한다.)
라인 2는 버전 정보가 저장된 파일명이다.

IsNewUpdateExists는 인자(parameter)로 현재 프로그램의 버전과 업데이트 서버의 버전 정보 파일(http://www.nohungry.net/UpdateServer/version.txt)에 저장된 버전을 비교하여, 현재 프로그램의 버전이 구버전인 경우, true를 반환하고 아니면 false를 반환한다.

GetLastError는 UpdateCheck 시 발생한 에러 메시지를 반환한다. 예를 들면, 업데이트 서버를 연결할 수 없다거나, 새로운 업데이트 파일이 없다는 내용을 반환한다.

(2) 프로그램 업데이트를 위한 자동 업데이트 프로그램
 자동 업데이트 프로그램은 상기 업데이트 체크 DLL에서 새로운 업데이트가 존재할 경우, 호출되는 프로그램이다. 이 프로그램은 업데이트 서버에서 업데이트 파일들을 다운로드 받고, 설치하는 역할을 한다.

 자동 업데이트 프로그램의 Configuration 파일(start.ini) 역시 DLL과 마찬가지로 단순한 정보를 담고 있다.
라인 1: http://www.nohungry.net/UpdateServer/
라인 2: file_list.txt
라인 3: MyNewProgram.exe

라인 1은 업데이트 서버의 URL
라인 2는 업데이트 파일 목록이 저장된 파일명
라인 3은 업데이트 완료 후, 실행할 파일명

사실 업데이트 서버 URL이나 이런 것들은 보안을 생각한다면, 위에 예처럼 무식하게 텍스트 파일로 쓰는 것은 좋지 않다. 이러한 것들은 바이너리로 저장한다거나 아니면 Configuration 파일이 아닌 레지스트리에 쓴다거나 아니면 기타 각자의 아이디어를 이용하도록 하자.

앞서 언급한 DLL과 자동 업데이트 프로그램을 이용해, 내 프로그램에 자동 업데이트 기능을 구현해보자고 한다면, 다음과 같이 할 수 있다. (예외 처리나 기타 복잡한 내용은 빼고, 심플한 코드)

사용자 삽입 이미지

이 게시물에 언급한 모든 내용 및 소스 코드는 아래 링크에서 다운로드 가능합니다.
http://www.nohungry.net/Data/SmartUpdateChecker.zip

관련 게시물 주소
http://www.nohungry.net/tt1/34

이 소스를 그대로 쓰시든지 수정해서 상용으로 쓰시든지 모든 것이 자유입니다. 단, 수정 요청은 받지 않습니다.
또한, 이 소스를 이용해 발생한 어떠한 문제도 책임지지 않습니다.

끝으로 이 게시물의 소스를 다운로드 받아가시거나, 게시물 내용을 블로그에 퍼가시더라도... 댓글이나 출처는 꼭 남겨주세요!


출처 : http://www.nohungry.net/tt1/category/24
반응형
Posted by blueasa
, |