레이블이 Programming인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Programming인 게시물을 표시합니다. 모든 게시물 표시

4/14/2011

Convert CString to Char*

char* StringToChar(CString& str)
{
    long len =  str.GetLength();
    len = len*2;
    char *szTemp = new char[len+1];
    memset(szTemp, 0, len+1);
    USES_CONVERSION;
    strcpy(szTemp, T2A(str));
    return szTemp;
}


참고사이트


USES_CONVERSION 매크로 설명 [#1.6]

2/04/2011

C#– Windows 환경에 따른 Control Layout 불일치

Visual Studio로 Windows Form 개발을 하고 나서 다른 PC에서 실행시켜보면 폼에 그려놓았던 컨트롤 레이아웃이 원래 개발했던 PC와 다르게 나타나는 경우가 있다.

필자의 경우는 영문 Windows OS에서 개발한 프로그램이 한글 Windows OS과 레이아웃이 일치하지 않는걸 발견할 수 있었다.

지인이 알려준 바에 의하면 Windows OS 버전, 언어팩, 글꼴 등에 의해서 레이아웃 또는 해상도가 알아서 조정된다고 한다.

자동으로 수정되지 않도록 하기 위해서는 Form 컨트롤 속성 중에서 AutoScaleMode 속성을 None으로 설정해 주면 된다.

this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;

 

하지만 AutoScaleMode 속성이 None이 아닌 상황에서 Panel 컨트롤 등이 추가되면 해당 폼의 Designer.cs 에 자동적으로 AutoScaleDimensions 속성이 추가되므로 레이아웃 또는 해상도가 변경되는 것을 막기 위해 이 속성을 삭제해 주어야 한다.

Form1.Designer.cs
AutoScaleMode가 Font인 상황에서 Panel 컨트롤이 추가된 경우

// 
// panel1
// 
this.panel1.Location = new System.Drawing.Point(53, 79);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(200, 100);
this.panel1.TabIndex = 0;
// 
// Form1
// 
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;

 

위 코드를 아래와 같이 바꿔주면 다른 OS에서도 레이아웃이 변형되는 일 없이 나타날 것이다.

 
// Form1 
//this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;

 

 

MSDN 참고:
Windows Forms의 자동 배율 조정
ContainerControl.AutoScaleDimensions 속성
AutoScaleMode 열거형

6/01/2010

C# 형식지정

 String.Format 메소드등에서 쓰이는 형식을 지정할 때마다 헷갈려서 MSDN 링크해 놓는다.

형식항목의 구성요소와 형태
   {index[,alignment][:formatString]}

 

합성 형식 지정
숫자 형식 지정
날짜 및 시간 형식 지정
열거형 형식 지정
사용자 지정 형식 지정

Class 설계 System, Business Logic 그리고 Data

올바른 Class는 System, Business Logic 그리고 Data 순서로 설계되어야 한다는 걸 배웠다.


내가 처음에 작성한 잘못된 클래스 생성자는 아래와 같다.
  public PinPadOperation(SerialPort serialPort, string cardNum, string totalAmount);



클래스를 생성할 때 Serial Port와 Card Number 그리고 Total Amount를 받아온다.

이 클래스의 생성자가 잘못된 이유는 System과 Data를 한꺼번에 받아온다는데 있다.
이를 고쳐보면

  public PinPadOperation(SerialPort serialPort);   //생성자를 통한 System 변수 설정
  public bool CanUseSerialPort();  //System이 사용가능한지 체크
  public void SetPinPadData(string cardNum, string totalAmount);  //Input Data를 가지고 작업수행



이렇게 설계되었어야 정상이다.

즉, Business Logic에 필요한 System들을 먼저 설정하고 그것이 정상인지 체크한 후에
Data를 받아들여 Business Logic을 실행하는것이 올바른 클래스 설계라고 한다.

Thread C#

- 쓰레드에서 간단하게 Invoke 하기 - 
Thread를 사용하다 보면 하위 Thread에서 메인 Thread의 변수에 접근하기 위해 Invoke Method를 쓸 때가 종종 있다.

하지만 Invoke Method를 쓸 때 delegate와 그 delegate와 연결시킬 method가 필요한데, 이를 Event를 사용하면 소스코드가 한결 간단해진다.

그 예는 아래와 같다.


원본소스
private void StartThread()
{
    Thread thread = new Thread(new ThreadStart(SleepThread));
    thread.Start();
}

private void SleepThread()
{
    System.Threading.Thread.Sleep(800);

    this.Invoke(new SleppThreadDelegate(InvokeMethod));
}

public delegate void SleppThreadDelegate();

private void InvokeMethod()
{
    this.timer.Start();
}

이 소스를 아래와 같이 변경가능
private void StartThread()
{
    Thread thread = new Thread(new ThreadStart(SleepThread));
    thread.Start();
}

private void SleepThread()
{
    System.Threading.Thread.Sleep(800);

    this.Invoke(new EventHandler(delegate(object o, EventArgs a)
    {
        this.timer.Start();
    }));
}

http://blog.opennetcf.com/ctacke/2008/12/03/ControlInvokeWithoutExplicitDelegates.aspx




- 다중 매개변수를 갖는 쓰레드 돌리기 - 
// function that running in a thread
void DoSomething(string param1, string param2, string param3)
{
}
// The parameters.
string param1 = "Hey";
string param2 = "You";
stirng param3 = "There";

// The delegate to call.
ThreadStart ts = delegate() { DoSomething(param1, param2, param3) };

// The thread.
Thread t = new Thread(ts);

// Run the thread.
t.Start();

5/12/2010

visual studio settings

Visual Studio를 통해 개발하는 사람은 하루종일 코딩화면을 들여다 봐야하는데 흰색바탕이 여간 눈이 아픈게 아니다.
해서 Style을 바꿔 좀 눈을 편하게 해보려고 이리저리 뒤져 발견한 사이트를 소개한다.

http://studiostyles.info/

가서 마음에 드는 셋팅을 하나 골라잡고 적용시키자.
VS 2005, 2008, 2010  별로 따로 Setting을 제공하니 선택해서 받고나서~

VS 2008을 기준으로 적용법을 살펴보면
  1. Visual Studio 2008의 Tools -> Import and Export Settings... 선택
  2. 열린 창에서 Import selected environment settings를 선택
  3. 현재 설정을 저장할거면 Yes, 그냥 덮어씌울꺼면 No를 하고 Next
  4. Browse 버튼을 눌러 위 사이트에서 다운받은 것 선택하고 Next
  5. Finish
이제 눈을 좀 쉬게해주자~
50분 컴퓨터 10분 휴식 룰은 언제쯤 지켜보려나..ㅠ

3/31/2010

.config 파일을 언제 어디서 불러와야 할까?

말 그대로 config 파일을 언제 어디에서 불러와야 할까!?

  1. 어디에서!?
    처음프로젝트를 만들때에는 이파일 저파일에서 config에 저장되어있는 key값을 불러들였다. 이렇게 하면 나중에 유지보수시에 여러 불편함이 생기는걸 알게 되었다.하나의 key이름을 변경하면 config 파일을 불러온 모든 곳에서 수정을 해주는 등의 수고가 생기는 것이다.

    해서 별도의 Settings Class를 제작해 이곳에서 config 파일의 모든 key값을 불러들이고 다른 곳에서 Settings Class의 Properties를 통해서 접근하는것이 가독성과 유지보수면에서 유용할 것이라는 생각이 들었다.



  2. 언제!?
    MVP 패턴을 이용해 프로젝트를 진행하고 있었는데 이때에는 Presenter의 생성자에서 Settings Class 인스턴스를 생성해 설정값을 읽어들이고 그 값들을 바로 Business Logic에 활용하는 것이 이로울 것이라는 생각을 했다.

    Set할때는 Settings UI에서 Settings Class 인스턴스를 생성해 바꿔주거나 직접 config 파일을 열어 변경해주면 되겠다!!


Config file의 수정및 읽어들이는 방법은 App.config 읽고 쓰기 포스팅을 참조하자.


참고:이 지식들을 신뢰하지 말것..내 자신이 의심스러움 :(

3/05/2010

Credit Card Number Validation

Credit Card Number Validation
카드 번호로 카드 회사 구분하기

주어진 Credit Card 번호로 Card Issuer 결정하기.
Credit Card Number로 Card 발행업체를 알아보자.

위키의 내용을 참고해 만들었다.
위키를 보면 대부분의 major 카드 회사들은 유효한 카드 번호인지 확인하기 위해 Luhn algorithm을 쓴다.

아래소스는 Visa, Master, Amex, DinersClub, Discover, JCB, CUP 카드만을 체크할 수 있다.

//Enum
public enum CardIssuer { None, VISA, MASTER, AMEX, DINERSCLUB, DISCOVER, JCB, CUP }

//Card Issuer 결정하기
public static CardIssuer GetCardIssuer(string cardNum)
{
    if (IsValidVisaCard(cardNum))
        return CardIssuer.VISA;

    if (IsValidMasterCard(cardNum))
        return CardIssuer.MASTER;

    if (IsValidDiscoverCard(cardNum))
        return CardIssuer.DISCOVER;

    if (IsValidAmexCard(cardNum))
        return CardIssuer.AMEX;

    if (IsValidDinersClubCard(cardNum))
        return CardIssuer.DINERSCLUB;

    if (IsValidJcbCard(cardNum))
        return CardIssuer.JCB;

    if (IsValidCupCard(cardNum))
        return CardIssuer.CUP;

    return CardIssuer.None;
}

public static bool IsValidVisaCard(string cardNum)
{
    int cardNumLen = cardNum.Length;
    int cardPrefix = Int32.Parse(cardNum.Substring(0, 1));

    if (cardPrefix != 4)
        return false;

    if (cardNumLen != 13 && cardNumLen != 16)
        return false;

    if (!IsValidCardNumber(cardNum))
        return false;
    
    return true;
}

public static bool IsValidMasterCard(string cardNum)
{
    int cardNumLen = cardNum.Length;
    int cardPrefix = Int32.Parse(cardNum.Substring(0, 2));

    if (cardPrefix < 51 || cardPrefix > 55)
        return false;

    if (cardNumLen != 16)
        return false;

    if (!IsValidCardNumber(cardNum))
        return false;

    return true;
}

public static bool IsValidAmexCard(string cardNum)
{
    int cardNumLen = cardNum.Length;
    int cardPrefix = Int32.Parse(cardNum.Substring(0, 2));

    if (cardPrefix != 34 && cardPrefix != 37)
        return false;

    if (cardNumLen != 15)
        return false;

    if (!IsValidCardNumber(cardNum))
        return false;

    return true;
}

public static bool IsValidDinersClubCard(string cardNum)
{
    int cardNumLen = cardNum.Length;
    int cardPrefix = Int32.Parse(cardNum.Substring(0, 2));

    if (cardPrefix != 36)
        return false;

    if (cardNumLen != 14)
        return false;

    if (!IsValidCardNumber(cardNum))
        return false;

    return true;
}

public static bool IsValidDiscoverCard(string cardNum)
{
    int cardNumLen = cardNum.Length;
    int cardPrefix = Int32.Parse(cardNum.Substring(0, 7));

    if (cardPrefix < 6011000 || cardPrefix > 6011090)
        if(cardPrefix < 6011200 || cardPrefix > 6011490)
            if (cardPrefix < 6011740 || cardPrefix > 6011749)
                if (cardPrefix < 6011770 || cardPrefix > 6011790)
                    if (cardPrefix < 6011860 || cardPrefix > 6011990)
                        if (cardPrefix < 6500000 || cardPrefix > 6509990)
                            return false;

    if (cardNumLen != 14)
        return false;

    if (!IsValidCardNumber(cardNum))
        return false;

    return true;
}

//Global Payments processes JCB as a Private Label card type. Currently, JCB is supported in Private Label 0 or Private Label 1. This value is defined by the merchant's bank.
public static bool IsValidJcbCard(string cardNum)
{
    int cardNumLen = cardNum.Length;
    int cardPrefix = Int32.Parse(cardNum.Substring(0, 6));

    if (cardPrefix < 352800 && cardPrefix > 358999)
        return false;

    if (cardNumLen != 14)
        return false;

    if (!IsValidCardNumber(cardNum))
        return false;

    return true;
}

//CUP(china Union Pay)transactions are processed through an agreement with the Discover Network through Global Payments.
public static bool IsValidCupCard(string cardNum)
{
    int cardNumLen = cardNum.Length;
    int cardPrefix = Int32.Parse(cardNum.Substring(0, 8));

    if (cardPrefix < 62212600 || cardPrefix > 62292599)
        return false;

    if (cardNumLen != 14)
        return false;

    if (!IsValidCardNumber(cardNum))
        return false;

    return true;
}

//Luhn algorithm http://en.wikipedia.org/wiki/Luhn_algorithm
public static bool IsValidCardNumber(string cardNumber)
{
   const string allowed = "0123456789";
   int i;

   StringBuilder cleanNumber = new StringBuilder();
   for (i = 0; i < cardNumber.Length; i++)
   {
      if (allowed.IndexOf(cardNumber.Substring(i, 1)) >= 0)
         cleanNumber.Append(cardNumber.Substring(i, 1));
   }
   if (cleanNumber.Length < 13 || cleanNumber.Length > 16)
      return false;

   for (i = cleanNumber.Length + 1; i <= 16; i++)
      cleanNumber.Insert(0, "0");

   int multiplier, digit, sum, total = 0;
   string number = cleanNumber.ToString();

   for (i = 1; i <= 16; i++)
   {
      multiplier = 1 + (i % 2);
      digit = int.Parse(number.Substring(i - 1, 1));
      sum = digit * multiplier;
      if (sum > 9)
         sum -= 9;
      total += sum;
   }
   return (total % 10 == 0);
}

참고문서:
 Credit Card Number 위키 - http://en.wikipedia.org/wiki/Credit_card_number
 Luhn algorithm - http://en.wikipedia.org/wiki/Luhn_algorithm
 알고리즘 소스 - http://www.codeguru.com/csharp/.net/net_security/authentication/article.php/c12283/

2/27/2010

정규식 (Regular Expression)

Regular Expression Community Site - http://gskinner.com/RegExr/

IE에서만 돌아가는 것 같아 살짝 얹짢지만 -_ㅜ
자신이 만든 정규식도 쉽게 검사해 볼 수 있고
간편한 정규식들도 정의되어 있으니 활용해 볼 만한 사이트이다.

2/05/2010

Silverlight 3 Tutorial 2: Data Binding

Tutorial 2: Data Binding


Data Binding Mode:
[대상]: UI, [소스]: behind code
OneTime: 바인딩을 만들 때 소스 데이터와 함께 대상을 업데이트
OneWay: 바인딩을 만들어 데이터를 변경할 때 소스 데이터와 함께 대상을 업데이트
TwoWay: 대상과 소스 중 하나가 변경될 때 대상과 소스를 모두 업데이트,
or 자동 소스 업데이트를 비활성화하고 원할 때만 소스를 업데이트

TwoWay Binding에서는 소스가 변경되면 대상이 바로 업데이트 될 수 있도록 하기위해서
INotifyPropertyChanged interface를 구현해야한다.
public event PropertyChangedEventHandler PropertyChanged;

public void NotifyPropertyChanged(string propertyName)
{
    if (PropertyChanged != null)
    {
       PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}


예제 소스 전문. Tutorial code에서 TwoWay Binding을 위한 소스만 추가하였다.

MainPage.xaml [이런 거지같은.. SyntaxHighlighter이 xaml 파일 지원이 잘 안되네!!ㅠ]

    
        
            
            
            
            
            
            
            
        
        
            
            
        

        
        
        
        
        
        
        
        
        
        
        
        

MainPage.xaml.cs
using System.Windows;
using System.Windows.Controls;
using System.Collections.Generic;

namespace EasyGrid
{
    public partial class MainPage : UserControl
    {
        private Book b1;
        private Book b2;
        private Book currentBook;

        public MainPage()
        {
            InitializeComponent();

            Loaded += new RoutedEventHandler(MainPage_Loaded);
        }

        void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            Change.Click += new RoutedEventHandler(Change_Click);
            TestTwoWayBinding.Click += new RoutedEventHandler(TestTwoWayBinding_Click);
            // 1. Create an instance of the Book class that implements INotifyPropertyChanged.
            b1 = new Book();
            // 2. Brush1 is set to be a SolidColorBrush with the value Red.
            InitializeBleak(b1);

            currentBook = b2 = new Book();
            InitializeProgramming(b2);
            SetDataSource();
        }

        void Change_Click(object sender, RoutedEventArgs e)
        {
            if (currentBook == b1)
                currentBook = b2;
            else
                currentBook = b1;
            SetDataSource();
        }

        void SetDataSource()
        {
            // 3. Set the DataContext of the TextBox MyTextBox.
            LayoutRoot.DataContext = currentBook;

            //or Using these code line.
            //Title.DataContext = currentBook;
            //Author.DataContext = currentBook;
            //Chapters.DataContext = currentBook;
            //MultipleAuthor.DataContext = currentBook;
            //QuantityOnHand.DataContext = currentBook;
        }

        private void InitializeProgramming(Book b)
        {
            b.Title = "Programming Silverlight";
            b.Author = "Jesse Liberty, Tim Heuer";
            b.MultipleAuthor = true;
            b.QuantityOnHand = 20;
            b.Chapters = new List() { "Introduction", "Controls", "Events", "Styles" };
        }

        private void InitializeBleak(Book b)
        {
            b.Title = "Bleak House";
            b.Author = "Charles Dickens";
            b.MultipleAuthor = false;
            b.QuantityOnHand = 150;
            b.Chapters = new List()
            {
                "In Chancery",
                "In Fashion",
                "A Progress",
                "Telescoopic Philanthropy",
                "A Morning Adventure",
                "Quite at Home",
                "The Ghosts Walk",
                "Covering Sins",
                "Signs and Tokens",
                "The Law Writer"
            };
        }

        //만약 book class에서 INotifyPropertyChanged를 UI에서 Author는 바로 바뀌지 않는다.
        void TestTwoWayBinding_Click(object sender, RoutedEventArgs e)
        {
            currentBook.Author = "Two Way Testing";
        }
    }
}

book.cs

using System.ComponentModel;
using System.Collections.Generic;

namespace EasyGrid
{
    //INotifyPropertyChanged interface for data binding
    public class Book : INotifyPropertyChanged
    {
        private string bookTitle;
        private string bookAuthor;
        private int quantityOnHand;
        private bool multipleAuthor;
        private List myChapters;

        // implement the required event for the interface
        public event PropertyChangedEventHandler PropertyChanged;

        public string Title
        {
            get { return bookTitle; }
            set
            {
                bookTitle = value;
                NotifyPropertyChanged("Title");
            }       // end set
        }           // end property

        public string Author
        {
            get { return bookAuthor; }
            set
            {
                bookAuthor = value;
                NotifyPropertyChanged("Author");
            }       // end set

        }

        public List Chapters
        {
            get { return myChapters; }
            set
            {
                myChapters = value;
                NotifyPropertyChanged("Chapters");
            }
        }


        public bool MultipleAuthor
        {
            get { return multipleAuthor; }
            set
            {
                multipleAuthor = value;
                NotifyPropertyChanged("MultipleAuthor");
            }       // end set
        }


        public int QuantityOnHand
        {
            get { return quantityOnHand; }
            set
            {
                quantityOnHand = value;
                NotifyPropertyChanged("QuantityOnHand");
            }       // end set
        }


        // factoring out the call to the event
        public void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                //이 Line을 주석처리하면 TwoWay Binding에서 속성이 변경되도 즉시 반영되지 않는다.
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

다시한번 확인하고 넘어가자!
  • Data Binding Mode
  • INotifyPropertyChanged interface

참고자료:
Tutorial 2: http://silverlight.net/learn/tutorials/databinding-cs/
MSDN Data Binding: http://207.46.16.248/ko-kr/library/cc278072%28VS.95%29.aspx

Sliverlight 3 시작하기 + Tutorial 1: Silverlight User Interface Controls

참고자료 링크 클릭

Sliverlight 3 개발을 시작하려면?
  • vs 2008 설치
  • vs 2008 SP1 설치 download
  • blend 3 sketchflow [이건 설치를 해야하나 말아야하나. 일단 보류!]
  • silverlight tools for vs2008 SP1 설치 download
  • Deep Zoom Composer 설치 download
  • .NET RIA Services [이것도 좀 알아보자. 보류!]
http://silverlight.net/getstarted/ 에서 설치를 마치고
http://silverlight.net/learn/tutorials/controls-cs/ 에서 튜토리얼을 보자!

Tutorial 1: Silverlight User Interface Controls


어려운 내용이 없으니 간단히 소스코드만...
Hello 버튼은 아무것도 아니고 Rush CheckBox는 체크되면 대문자로 Un체크되면 소문자로 바뀐다.
Add Another 버튼을 누르면 새로운 버튼이 동적으로 생겨나는 예제이다.
처음으로 실버라이트를 접하기에 안성맞춤인 예제!

MainPage.xaml 파일

    
        
        
        
    


MainPage.xaml.cs 파일
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace EasyGrid
{
    public partial class MainPage : UserControl
    {
        private double newButtonPosition = 100.0;

        public MainPage()
        {
            InitializeComponent();
            Loaded += new RoutedEventHandler(MainPage_Loaded);
        }

        void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            Another.Click += new RoutedEventHandler(Another_Click);
            rushOrder.Checked += new RoutedEventHandler(rushOrder_Changed);
            rushOrder.Unchecked += new RoutedEventHandler(rushOrder_Changed);
        }

        void rushOrder_Changed(object sender, RoutedEventArgs e)
        {
            if (rushOrder.IsChecked == true)
            {
                rushOrder.Content = rushOrder.Content.ToString().ToUpper();
            }
            else
            {
                rushOrder.Content = rushOrder.Content.ToString().ToLower();
            }
        }

        void Another_Click(object sender, RoutedEventArgs e)
        {
            Button b = new Button();
            b.Content = "I Live";
            b.SetValue(Canvas.LeftProperty, 10.0);
            b.SetValue(Canvas.TopProperty, this.newButtonPosition);
            this.newButtonPosition += 30.0;
            b.Width = 100;
            b.Height = 20;
            b.Click += new RoutedEventHandler(new_button_click);
            myCanvas.Children.Add(b);
        }

        void new_button_click(object sender, RoutedEventArgs e)
        {
            Button btn = sender as Button;
            btn.Content = "Don't do that!";
            btn.IsEnabled = false;
        }

        private void Canvas_Loaded(object sender, RoutedEventArgs e)
        {
            myButton.Content = "Please Click Me";
        }
    }
}

참고자료:
silverlight start: http://silverlight.net/getstarted/
tutorial 1: http://silverlight.net/learn/tutorials/controls-cs/

2/04/2010

Replace Thread.Suspend() and Resume() method

Replace Thread.Suspend() and Resume() method
Thread Suspend() Resume() 메소드 대체하기

RiskNET Packet analysis 프로그램을 개발 중 데이터가 20만줄이 넘어가서 한번에 불러와 처리하기에는

시간이 너무 오래 걸리는 관계로 쓰레드를 사용하게 되었다.

간단하게 textbox에 있는 20만줄의 글을 ListView에 뿌려주는 일이었는데

thread 클래스를 사용중에 suspend() 와 resume() 메소드를 사용했더니 '경고'가 뜨는것이 아닌가!?

이유는 더이상 사용하지 않는 Method... 바로  Obsolete Attribute 때문이었다.

http://msdn.microsoft.com/ko-kr/library/system.threading.thread.suspend%28VS.80%29.aspx
http://msdn.microsoft.com/ko-kr/library/system.threading.thread.resume%28VS.80%29.aspx

비록 실행은 되지만 찜찜한 기분에 이리저리 구글링을 해 보니 다음 아티클을 찾을 수 있었다.

아티클 바로가기

위 아티클에서 핵심은 아래 두 소스와 같다.

private ManualResetEvent suspendChangedEvent = new ManualResetEvent(false);
private ManualResetEvent terminateEvent = new ManualResetEvent(false);
ManualResetEvent Class는 로컬에서 신호를 보내 Event Handle을 할 수 있도록 도와준다.
이걸로 신호가 Set 되면 해당 Thread를 종료하거나 중지 또는 재시작하는 로직을 구현할 수 있게 해준다.

suspendChangedEvent.WaitOne(0, true);
terminateEvent.WaitOne(0, true);
WaitHandle.WaitAny(new WaitHandle[] { suspendChangedEvent, terminateEvent })
WaitOne method는 해당 변수가 Set 되어있으면 true를 Reset 되어있으면 false를 반환한다.
WaitHandle.WaitAny 는 주어진 매개변수중 하나라도 신호를 받을 때까지 대기한다.


아래 코드 전문은 위의 아티클에서 가져와 주석을 첨가한것이다.


소스코드
SuspendableThread.cs
namespace ThreadTest
{
    abstract public class SuspendableThread
    {
        #region Data
        private ManualResetEvent suspendChangedEvent = new ManualResetEvent(false);
        private ManualResetEvent terminateEvent = new ManualResetEvent(false);
        private long suspended;
        private Thread thread;
        private System.Threading.ThreadState failsafeThreadState = System.Threading.ThreadState.Unstarted;
        #endregion Data

        public SuspendableThread() { }

        private void ThreadEntry()
        {
            failsafeThreadState = System.Threading.ThreadState.Stopped;
            OnDoWork();
        }

        //자식클래스에서 구현할 부분 (Thread에서 돌아가는 부분)
        protected abstract void OnDoWork();

        protected Boolean SuspendIfNeeded()
        {
            Boolean suspendEventChanged = suspendChangedEvent.WaitOne(0, true);
            
            //suspendChangeEvent가 Set 되어있는 경우 실행
            if (suspendEventChanged)
            {
                Boolean needToSuspend = Interlocked.Read(ref suspended) != 0;
                suspendChangedEvent.Reset();

                //suspended 가 0이 아닌경우에만 실행
                //Suspend method실행시 suspended = 1, Resume method 실행시 suspended = 0
                if (needToSuspend)
                {
                    /// Suspending...
                    /// WaitHandle.WaitAny method: 
                    ///   주어진 매개변수들중 하나라도 신호를 받으면 신호를 받은 매개변수의 인덱스 반환
                    if (1 == WaitHandle.WaitAny(new WaitHandle[] { suspendChangedEvent, terminateEvent }))
                    {
                        //terminateEvent 변수가 신호를 받으면 true 반환
                        return true;
                    }
                    /// suspendChagedEvent 변수가 신호를 받으면 여기부터 실행
                    /// 이러한 이유로 Suspend method를 실행하면 OnDoWork method의 루프가 한번 더 실행됨
                    /// ...Waking
                }
            }
            return false;
        }

        protected bool HasTerminateRequest()
        {
            //terminateEvent가 Set이 되었으면 true 반환 Set이 안되어있으면 false 반환
            return terminateEvent.WaitOne(0, true);
        }

        public void Start()
        {
            thread = new Thread(new ThreadStart(ThreadEntry));

            // make sure this thread won't be automaticaly
            // terminated by the runtime when the
            // application exits
            thread.IsBackground = false;

            thread.Start();
        }

        public void Join()
        {
            if (thread != null)
            {
                thread.Join();
            }
        }

        public Boolean Join(Int32 milliseconds)
        {
            if (thread != null)
            {
                return thread.Join(milliseconds);
            }
            return true;
        }

        /// Not supported in .NET Compact Framework
        public Boolean Join(TimeSpan timeSpan)
        {
            if (thread != null)
            {
                return thread.Join(timeSpan);
            }
            return true;
        }

        public void Terminate()
        {
            terminateEvent.Set();
        }
        
        public void TerminateAndWait()
        {
            terminateEvent.Set();
            thread.Join();
        }

        public void Suspend()
        {
            //suspended를 1로 바꿔줌
            while (1 != Interlocked.Exchange(ref suspended, 1)) { }
            suspendChangedEvent.Set();
        }

        public void Resume()
        {
            while (0 != Interlocked.Exchange(ref suspended, 0)) { }
            suspendChangedEvent.Set();
        }

        public System.Threading.ThreadState ThreadState
        {
            get
            {
                if (null != thread)
                {
                    return thread.ThreadState;
                }
                return failsafeThreadState;
            }
        }
    }
}


SuspendableThreadWork.cs
namespace ThreadTest
{
    public class SuspendableThreadWork : SuspendableThread
    {
        public SuspendableThreadWork()
        {
        }

        protected override void OnDoWork()
        {
            try
            {
                while (false == HasTerminateRequest())
                {
                    Boolean awokenByTerminate = SuspendIfNeeded();
                    
                    if (awokenByTerminate)
                    {
                        return;
                    }
                    // TODO: replace the following to lines
                    // 코드작성
                }
            }

            finally
            {
                // TODO: Replace the following line with thread
                // exit processing.
                // 코드작성
            }
        }
    }
}


참고자료:
본문 아티클: http://msmvps.com/blogs/peterritchie/archive/2006/10/13/_2700_System.Threading.Thread.Suspend_280029002700_-is-obsolete_3A00_-_2700_Thread.Suspend-has-been-deprecated_2E002E002E00_.aspx
WaitHandle.WaitAny Method: http://msdn.microsoft.com/ko-kr/library/tdykks7z%28VS.80%29.aspx
ManualResetEvent Class: http://msdn.microsoft.com/ko-kr/library/system.threading.manualresetevent%28VS.95%29.aspx

1/13/2010

Error Handle

Warning 1 The designer cannot process the code at line 39, please see the Task List for details. The code within the method 'InitializeComponent' is generated by the designer and should not be manually modified. Please remove any changes and try opening the designer again. C:\Documents and Settings\bkyungnam\Desktop\TestProgram\WindowsFormsApplication1\WindowsFormsApplication1\Form2.Designer.cs 40 0



이런 에러를 발견했다 -_-^ 이것때문에 하루종일 매달렸지만 원인은

non printing ascii code를 TextBox.Text 속성에 복사해서 붙여넣었기 때문이었다.
난 behind source쪽은 건드리지도 않았는데 계속 이런 에러를 받으니 속이 뒤집어지는 줄 알았다.

짧은 영어로나마 에러 피드백을 했다.

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=524784

고쳐지면 좋겠는데 말이지..ㅎ

에러 발생 소스코드를 보자
behind 소스이다.

Form2.Designer.cs file
namespace WindowsFormsApplication1
{
    partial class Form2
    {
        /// 
        /// Required designer variable.
        /// 
        private System.ComponentModel.IContainer components = null;

        /// 
        /// Clean up any resources being used.
        /// 
        /// 

true if managed resources should be disposed; otherwise, false.protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// 
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// 
        private void InitializeComponent()
        {
            this.textBox1 = new System.Windows.Forms.TextBox();
            this.SuspendLayout();
            // 
            // textBox1
            // 
            this.textBox1.Location = new System.Drawing.Point(12, 12);
            this.textBox1.Name = "textBox1";
            this.textBox1.Size = new System.Drawing.Size(100, 20);
            this.textBox1.TabIndex = 3;
            this.textBox1.Text = "12      "; //<--이것이 문제라는 말씀!!!
            // 
            // Form2
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(124, 50);
            this.Controls.Add(this.textBox1);
            this.Name = "Form2";
            this.Text = "Form2";
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.TextBox textBox1;
    }
}

문제의 아래 소스코드를 보자
this.textBox1.Text = "12      ";
위에서 눈에보이는
"12[공백][공백][공백]" 만 있는것이 아니라
"12[non printing ascii code][공백][공백][공백][non printing ascii code]"
이렇게 들어있단 말씀

이 값을 복사해서 넣으면 암만 error message를 읽어도 해결안되는 에러를 보게된다는 말씀!!
게다가 주석처리를 해도 에러는 여전히 생겼었다. -_-a
저 라인을 삭제하지 않는 이상 에러를 계속 보게 될 것이다. ㅠ
ㅠㅠ

1/06/2010

MVP Model (Model View Presenter Design Pattern)

MVP Model (Model View Presenter Design Pattern)

View와 Business Logic을 최대한 독립적으로 만들기 위한 Design Pattern
MVC(Model View Control) Model의 진화형

Program.cs file
static class Program
{
    /// 
    /// The main entry point for the application.
    /// 
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        // IView 
        ProcessForm view = new ProcessForm();

        // IService
        Service reqText = new Service();

        // Presenter (View, Service)
        ProcessPresenter presenter = new ProcessPresenter(view, reqText);

        // Run
        Application.Run((Form)presenter.view);
    }
}

IProcessView.cs file
public interface IProcessView
{
    void NotifyUpdate(string msg);

    event EventHandler Process;
}


ProcessForm.cs file
public partial class ProcessForm : Form, IProcessView
{
    public event EventHandler Process;

    public ProcessForm()
    {
        InitializeComponent();
    }

    private void processButton_Click(object sender, EventArgs e)
    {
        EventHandler handler = this.Process;
        if (handler != null) handler(this, new EventArgs());
    }

    public void NotifyUpdate(string msg)
    {
        this.labelProcess.Text = msg;
    }
}


ProcessPresenter.cs file
public class ProcessPresenter
{
    public IProcessView view;
    public IReq req;

    public ProcessPresenter(IProcessView view, IReq req)
    {
        this.view = view;
        this.req = req;

        this.view.Process += this.OnProcess;
    }

    private void OnProcess(object source, EventArgs args)
    {
        this.view.NotifyUpdate(this.req.ToString());
    }
}

12/29/2009

Error Handle

[Error Message]
File has invalid value ">>>>>>> .mine". Illegal characters in path [project name].

This error is caused by the Subversion "Resolved..." function.

[solution] Delete the /obj folder in project that is complaining and re-compile.

reference

12/18/2009

Visual Studio 2008 단축키

Visual Studio 2008 에서 자주 쓰이는 단축키 모음
Visual Studio 단축키, VS 단축키, VS 2008 단축키

원본문서

* Go to declaration... F12
* Debug: step over... F10
* Debug: run to cursor... ctrl + F10
* Debug: step into... F11
* Debug: step out... shift + F11
* Toggle a breakpoint... F9
* Go to next item in task list or search results... F8 (error 났을 때 다음거 보기)
* Go to previous item in task list or search results... shift + F8
* Switch to code view... F7 (form design mode -> form code view)
* Switch to designer view... shift + F7 (form code view -> form design mode)
* Run with debugging... F5
* Stop debugging... shift + F5
* Run without debugging... ctrl + F5
* Move to previous edit point (back)... ctrl + -
* Switch to the Task List... ctrl + alt K
* Switch to the Immediate window... ctrl + alt + I
* Switch to the Output window... ctrl + alt + O
* Find... ctrl + F
* Find in all files... ctrl + shift + F
* Replace... ctrl + H
* Incremental find (it's pure sex!)... ctrl + I
* Insert Book Mark... ctrl + K + K or ctrl + B + T
* find next book mark... ctrl + K + N or ctrl + B + N
* find previous book mark... ctrl + B + P
* add new item in present project... ctrl + shift + A

12/04/2009

소스변환 프로그램 VB, C#, C++, & Java

간편한 소스변환프로그램이다.

무료로 사용하면 한번에 코드 100줄까지 변환이 되는걸로 알고 있으니 학습용이 아니라면 구매해서 사용하는것이 좋을듯.

변환에 실패한 코드는 알아서 주석까지 달아주니 참으로 편리한 프로그램!!! must have!

http://www.tangiblesoftwaresolutions.com/

Convert Between VB, C#, C++, & Java with the Most Accurate & Reliable Source Code Converters

* Instant C# converts VB code to C#
* Instant VB converts C# code to VB
* C++ to C# Converter converts C++ code to C#
* C++ to VB Converter converts C++ code to VB
* C++ to Java Converter converts C++ code to Java
* Instant C++ (C# Edition) converts C# code to C++
* Instant C++ (VB Edition) converts VB code to C++
* Instant C++ (Java Edition) converts Java code to C++
* Java to VB & C# Converter converts Java code to VB or C#
* VB & C# to Java Converter converts VB and C# code to Java
* Clear VB formats and standardizes VB source code

11/09/2009

App.config 읽고 쓰기

configuration file에 키로 값을 설정해 놓고
필요할 때마다 불러서 쓰면 *.exe.config 설정값만 변경함으로써
프로그램을 좀 더 쉽게 관리할 수 있다.

예전에 COM port 통신 프로그램을 만들면서 포트와 관련된 설정값들을
Configuration 파일을 통해 관리함으로써 따로 디버그 필요없이 *.exe.config 파일만 변경해 사용했다.

app.config 파일을 추가하고 아래의 코드와 같이 <appsettings> 요소에 <add> 요소를 집어넣은 후
메인 소스 코드에서 간단하게 불러오거나 (AppSettingsReader)
읽어오고 쓰는 방법(Configuration)을 알아보자


*.exe.config 파일
<configuration>
  <appsettings>
    <add key="appConStr" value="server-localhost;uid='sa';pwd='';database=Cars"/>
    <add key="timesToSayHello" value="8"/>
  </appsettings>
</configuration>


*.cs 파일
using System;
using System.Configuration;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            //방법 1
            AppSettingsReader ar = new AppSettingsReader();
            
            //key를 가지고 설정된 value값을 가져온다.
            string str = (string)ar.GetValue("appConStr", typeof(string));
            int numbOfTimes = (int)ar.GetValue("timesToSayHello", typeof(int));

            //방법 2[읽고 쓰기] 
            //before using this code, Add System.Configuration reference
            System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

            //쓰기
            config.AppSettings.Settings["appConStr"].Value = "3";

            //읽기
            string value = ConfigurationManager.AppSettings["appConStr"];

            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("appSettings");
        }
    }
}


주의할점-
프로그램 개발시 디버그 모드(F5)에는 프로젝트의 Root 폴더에 있는 App.config 파일을 debug/bin 폴더로 복사해 사용한다.

디버그 모드에서 아무리 debug/bin 의 app.config 파일을 고치고 삽질을 해도 다음 디버그 모드때에는 root 폴더의 app.config 파일이 덮어씌우므로 변하지 않는것 처럼 보이는 것이다. Bin 폴더에서 직접 exe를 실행시켜 config 파일을 바꾸어 보면 다음에 프로그램을 실행시켜도 변경한 내용이 적용되어 있는걸 확인할 수 있다.

나처럼 안바뀐다고 성질부리지 말자 -_ㅠ

참조할 dll 파일 위치지정


그림과 같이 App.Config를 추가해 아래와 같은 코드를 넣어놓으면
실행파일이 있는 폴더의 하위 폴더인 MyLibraries 폴더나 MyLibraries/Tests 폴더 아무곳이나 참조하는 Dll파일이 있으면 프로그램이 실행된다.


실행파일과 함께있는 산만한 Dll파일들을 정리해보자.


주위할 점은 privatePath 속성에 세미콜론(;)으로 여러 폴더를 지정해 줄 때
세미콜론 뒤에 공백을 두면 안되는 것과 하위폴더는 \ 로 나타내자.



<configuration>
  <runtime>
    <assemblybinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <probing privatepath="MyLibraries;MyLibraries\Tests"/>
  </assemblybinding>
</runtime>
</configuration>

p.s: 흠.. SyntaxHighlighter Xml쪽은 좀 이상하게 나오는군.
그래서 Windows Live Writer로 갈아탔음 -_-+

11/06/2009

Custom Exception in C#

예외를 직접 만들어 써보자.


//custom exception
[Serializable]
public class CarIsDeadException : ApplicationException
{
    public CarIsDeadException() { }
    public CarIsDeadException(string message)
        : base(message) { }

    //to handle "inner exceptions"
    public CarIsDeadException(string message, System.Exception inner)
        : base(message, inner) { }

    //to handle the serialization of type.
    protected CarIsDeadException(
        System.Runtime.Serialization.SerializationInfo info,
        System.Runtime.Serialization.StreamingContext context)
        : base(info, context) { }
}

//using
public class Main
{
    public Main()
    {
        //using basic
        try
        {
            CarIsDeadException ex = new CarIsDeadException("error");
            throw ex;
        }
        catch(CarIsDeadException e)
        {
            string errorMessage = e.Message;
            System.Windows.Forms.MessageBox.Show(errorMessage);
            //using inner exception
            try
            { ... }
            catch (Exception e2)
            {
                throw new CarIsDeadException(e.Message, e2);
            }
        }
    }
}