블로그 이미지
Sunny's

calendar

1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30

Notice

2009. 4. 10. 10:51 .NET Framework

개발을 하다 보면, 하나의 프로그램 파일(예를 들어, “Form1.cs”)을 비교하면서 보고 싶은 수가 있습니다. 이때 사용할 수 있는 것이 메뉴 -> 창 -> 분할 기능입니다. 아래처럼 화면이 위에 하나, 아래에 하나 두 개가 생깁니다. 다른 방법은 편집기 창의 오른쪽 스크롤바 위에 있는 곳에 마우스를 두고, 커서 모양이 변하면 클릭한 상태에서 아래로 내리는 것입니다. 창을 왼쪽과 오른쪽으로 배치하려면, 메뉴 -> 창 -> 새 창을 선택해 새로운 창을 만든 다음 메뉴->창->새 세로 탭 그룹을 선택합니다.

clip_image004clip_image006clip_image002[5]

[Visual Studio 2008 한글 버전 화면]

posted by Sunny's
2009. 4. 10. 10:48 .NET Framework

개발자에게는 넓은 화면이 좋습니다. 큰 모니터 2개를 이용해 자유롭게 보면 좋지만, 그렇지 못하고 프로그램 창만 크게 하고 싶다면 전체 화면 기능을 생각해 볼 수 있습니다. SHIFT+ALT+ENTER를 누르면 전체 화면 형태로 바뀝니다. 원래 모양으로 돌아가려면 SHIFT+ALT+ENTER를 한 번 더 누르거나, 화면에 있는 전체 화면 버튼을 클릭합니다.

image

[Visual Studio 한글 버전 2008 화면]


posted by Sunny's
2009. 4. 10. 10:40 .NET Framework

.NET으로 윈도우 서비스를 만들때는 주의해야 할것이 하나 있다.

아래 도움말은 MSDN에서 나온것인데 그대로 따라해서 설치하면

사용자와 암호를 묻는 다이얼로그 박스가 나타나는데

로컬 시스템에 존재하는 어떤 계정을 입력해도

사용자를 찾을수 없다는 메시지를 출력하고 설치에 실패한다.

 

이때는 아래 붉은색으로 표기된 부분을 잘 살펴보고 해당되는 속성값을 살펴본다.

디폴트로 User로 되어있는것을 "Local Service"등, 다른것으로 바꾸어준다.

 

마지막으로 설치 프로젝트는 반드시 필요한것은 아니며

InstallUtil.exe 로 수동 등록시켜도 좋다.

 

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

 

서비스 응용 프로그램에 설치 관리자를 추가하려면

  1. 솔루션 탐색기에서 설치 구성 요소를 추가할 서비스에 대한 디자인 뷰에 액세스합니다.
  2. 디자이너 화면을 클릭합니다.
  3. 속성 창의 설명 영역에서 설치 관리자 추가 링크를 클릭합니다.

    새로운 클래스 ProjectInstaller와 두 설치 구성 요소인 ServiceProcessInstaller ServiceInstaller가 프로젝트에 추가되고 서비스에 대한 속성 값이 구성 요소에 복사됩니다.

  4. ServiceInstaller 구성 요소를 클릭하여 ServiceName 속성 값이 서비스에 있는 ServiceName 속성 값과 동일하게 설정되었는지 확인합니다.
  5. 서비스 시작 방법을 결정하려면 ServiceInstaller 구성 요소를 클릭한 다음 StartType 속성을 적절한 값으로 설정합니다.
결과
Manual 설치 후 수동으로 서비스를 시작해야 합니다. 자세한 내용은 서비스 시작을 참조하십시오.
Automatic 컴퓨터를 다시 부팅할 때마다 서비스가 자동으로 시작됩니다.
Disabled 서비스를 시작할 수 없습니다.
  1. 서비스가 실행되는 보안 컨텍스트를 결정하려면 ServiceProcessInstaller 구성 요소를 클릭하여 적절한 속성 값을 설정합니다. 자세한 내용은 서비스에 대한 보안 컨텍스트 지정을 참조하십시오.
  2. 사용자 지정 처리를 수행해야 하는 모든 메서드를 재정의합니다. 자세한 내용은 설치 구성 요소의 기본 메서드 재정의를 참조하십시오.
  3. 프로젝트의 각 추가 서비스에 대해 1단계부터 6단계까지 수행합니다.
    참고   프로젝트에의 각 추가 서비스의 경우 프로젝트의 ProjectInstaller 클래스에 추가 ServiceInstaller 구성 요소를 추가해야 합니다. 3단계에서 추가된 ServiceProcessInstaller 구성 요소는 프로젝트에서의 모든 개별 서비스 설치 관리자를 사용합니다.
  4. 설치 프로젝트와 사용자 지정 동작을 만들어 서비스를 배포하고 설치합니다. 설치 프로젝트에 대한 자세한 내용은 설치 프로젝트를 참조하십시오. 사용자 지정 작업에 대한 자세한 내용은 연습: 사용자 지정 작업 만들기를 참조하십시오.
  5.  

posted by Sunny's
2009. 3. 16. 14:51 .NET Framework

특정 레지스트리, 하위 값 모두 가져오기.
응용해서 레지스트리의 값을 조회해서 COM PORT 모두 가져오기 입니다.

현재 시스템의 시리얼포트(Com port) 조회하기

관련 글 : http://i0nucleus.egloos.com/2006137 [MFC] 특정 레지스트리, 하위 값 모두 가져오기(COMPORT 검출)

Tool : Visual C# 2008(C#  Console)

레지스트리  HKEY_LOCAL_MACHINE\HARDWARE\\DEVICEMAP\\SERIALCOMM
조회를 해보면(RegEdit) 현재 시스템에 사용할 수 있는 Com Port을 볼 수 있습니다. (COM1, COM2.....)


[Source Code]

using System;
using Microsoft.Win32;

namespace ConsoleApplication00
{
    class Program
    {
        static void Main(string[] args)
        {
                //HKEY_LOCAL_MACHINE,"HARDWARE\\DEVICEMAP\\SERIALCOMM
                RegistryKey localmachine = Registry.LocalMachine;

                RegistryKey hardware = localmachine.OpenSubKey("HARDWARE");
                RegistryKey devicemap = hardware.OpenSubKey("DEVICEMAP");
                RegistryKey serialcomm = devicemap.OpenSubKey("SERIALCOMM");

                if (serialcomm != null)
                {
                    Console.WriteLine("Serial Port : {0} installed", serialcomm.ValueCount);
                    foreach (string PortName in serialcomm.GetValueNames())
                        Console.WriteLine("{0} : {1}", serialcomm.GetValue(PortName), PortName);
                }
                else
                    Console.WriteLine("Serial Comm : None");

                Console.ReadLine();
        }
    }
}



 


시리얼 포트를 확인 할 수 있습니다.
USB - Serial 아답터를 2개를 장착 후 프로그램 실행 결과 입니다. COM4, COM6 있습니다....
랩탑에서 실행하였습니다..
posted by Sunny's
2009. 3. 16. 14:38 .NET Framework

Welcome to my tutorial on Serial Port Communication in C#. Lately Ive seen a lot of questions on how to send and receive data through a serial port, so I thought it was time to write on the topic. Back in the days of Visual Basic 6.0, you had to use the MSComm Control that was shipped with VB6, the only problem with this method was you needed to make sure you included that control in your installation package, not really that big of a deal. The control did exactly what was needed for the task.

We were then introduced to .Net 1.1, VB programmers loved the fact that Visual Basic had finally evolved to an OO language. It was soon discovered that, with all it's OO abilities, the ability to communicate via a serial port wasn't available, so once again VB developers were forced to rely on the MSComm Control from previous versions of Visual Basic, still not that big of a deal, but some were upset that an intrinsic way of serial port communication wasn't offered with the .net Framework. Worse yet, C# developers had to rely on a Visual Basic control and Namespace if they wanted to communicate via serial port.

Then along comes .Net 2.0, and this time Microsoft added the System.IO.Ports Namespace, and within that was the SerialPort Class. DotNet developers finally had an intrinsic way of serial port communication, without having to deal with the complexities of interoping with an old legacy ActiveX OCX control. One of the most useful methods in the SerialPort class is the GetPortNames Method. This allows you to retrieve a list of available ports (COM1,COM2,etc.) available for the computer the application is running on.

Now that we have that out of the way, lets move on to programming our application. As with all application I create, I keep functionality separated from presentation, I do this by creating Manager classes that manage the functionality for a given process. What we will be looking at is the code in my CommunicationManager class. As with anything you write in .Net you need to add the references to the Namespace's you'll be using:

CODE

using System;
using System.Text;
using System.Drawing;
using System.IO.Ports;



In this application I wanted to give the user the option of what format they wanted to send the message in, either string or binary, so we have an enumeration for that, and an enumerations for the type of message i.e; Incoming, Outgoing, Error, etc. The main purpose of this enumeration is for changing the color of the text displayed to the user according to message type. Here are the enumerations:

CODE

#region Manager Enums
/// <summary>
/// enumeration to hold our transmission types
/// </summary>
public enum TransmissionType { Text, Hex }

/// <summary>
/// enumeration to hold our message types
/// </summary>
public enum MessageType { Incoming, Outgoing, Normal, Warning, Error };
#endregion



Next we have our variable list, 6 of them are for populating our class Properties, the other 2 are access throughout the class so they needed to be made global:

CODE

#region Manager Variables
//property variables
private string _baudRate = string.Empty;
private string _parity = string.Empty;
private string _stopBits = string.Empty;
private string _dataBits = string.Empty;
private string _portName = string.Empty;
private TransmissionType _transType;
private RichTextBox _displayWindow;
//global manager variables
private Color[] MessageColor = { Color.Blue, Color.Green, Color.Black, Color.Orange, Color.Red };
private SerialPort comPort = new SerialPort();
#endregion



NOTE:I always separate my code into sections using the #region ... #endregion to make it easier when scanning my code. It is a design choice so it's not necessary if you don't want to do it.

Now we need to create our class properties. All the properties in this class are public read/write properties. We have properties for the following items of the Serial Port:
  • Baud Rate: A measure of the speed of serial communication, roughly equivalent to bits per second.
  • Parity: The even or odd quality of the number of 1's or 0's in a binary code, often used to determine the integrity of data especially after transmission.
  • Stop Bits: A bit that signals the end of a transmission unit
  • Data Bits: The number of bits used to represent one character of data.
  • Port Name: The port with which we're communicating through, i.e; COM1, COM2, etc.
We also have 2 properties that aren't related to the port itself, but with where the data will be displayed, and what transmission type to use:

CODE

#region Manager Properties
/// <summary>
/// Property to hold the BaudRate
/// of our manager class
/// </summary>
public string BaudRate
{
   
get { return _baudRate; }
   
set { _baudRate = value; }
}

/// <summary>
/// property to hold the Parity
/// of our manager class
/// </summary>
public string Parity
{
   
get { return _parity; }
   
set { _parity = value; }
}

/// <summary>
/// property to hold the StopBits
/// of our manager class
/// </summary>
public string StopBits
{
   
get { return _stopBits; }
   
set { _stopBits = value; }
}

/// <summary>
/// property to hold the DataBits
/// of our manager class
/// </summary>
public string DataBits
{
   
get { return _dataBits; }
   
set { _dataBits = value; }
}

/// <summary>
/// property to hold the PortName
/// of our manager class
/// </summary>
public string PortName
{
   
get { return _portName; }
   
set { _portName = value; }
}

/// <summary>
/// property to hold our TransmissionType
/// of our manager class
/// </summary>
public TransmissionType CurrentTransmissionType
{
   
get{ return _transType;}
   
set{ _transType = value;}
}

/// <summary>
/// property to hold our display window
/// value
/// </summary>
public RichTextBox DisplayWindow
{
   
get { return _displayWindow; }
   
set { _displayWindow = value; }
}
#endregion



To be able to instantiate any class object we create we need Constructors. Constructors are the entry point to your class, and is the first code executed when instantiating a class object. We have 2 constructors for our manager class, one that sets our properties to a specified value, and one that sets our properties to an empty value, thus initializing the variables preventing a NullReferenceException from occurring. We also add an EventHandler in the constructor, the event will be executed whenever there's data waiting in the buffer:

CODE

#region Manager Constructors
/// <summary>
/// Constructor to set the properties of our Manager Class
/// </summary>
/// <param name="baud">Desired BaudRate</param>
/// <param name="par">Desired Parity</param>
/// <param name="sBits">Desired StopBits</param>
/// <param name="dBits">Desired DataBits</param>
/// <param name="name">Desired PortName</param>
public CommunicationManager(string baud, string par, string sBits, string dBits, string name, RichTextBox rtb)
{
    _baudRate
= baud;
    _parity
= par;
    _stopBits
= sBits;
    _dataBits
= dBits;
    _portName
= name;
    _displayWindow
= rtb;
   
//now add an event handler
    comPort
.DataReceived += new SerialDataReceivedEventHandler(comPort_DataReceived);
}

       
/// <summary>
/// Comstructor to set the properties of our
/// serial port communicator to nothing
/// </summary>
public CommunicationManager()
{
    _baudRate
= string.Empty;
    _parity
= string.Empty;
    _stopBits
= string.Empty;
    _dataBits
= string.Empty;
    _portName
= "COM1";
    _displayWindow
= null;
   
//add event handler
    comPort
.DataReceived+=new SerialDataReceivedEventHandler(comPort_DataReceived);
}
#endregion



The first think you need to know about serial port communication is writing data to the port. The first thing we do in our WriteData method is to check what transmission mode the user has selected, since binary data needs to be converted into binary, then back to string for displaying to the user. Next we need to make sure the port is open, for this we use the IsOpen Property of the SerialPort Class. If the port isn't open we open it by calling the Open Method of the SerialPort Class. For writing to the port we use the Write Method:

CODE

#region WriteData
public void WriteData(string msg)
{
   
switch (CurrentTransmissionType)
   
{
       
case TransmissionType.Text:
           
//first make sure the port is open
           
//if its not open then open it
           
if (!(comPort.IsOpen == true)) comPort.Open();
           
//send the message to the port
            comPort
.Write(msg);
           
//display the message
           
DisplayData(MessageType.Outgoing, msg + "\n");
           
break;                    
       
case TransmissionType.Hex:
           
try
           
{
               
//convert the message to byte array
               
byte[] newMsg = HexToByte(msg);
               
//send the message to the port
                comPort
.Write(newMsg,0,newMsg.Length);
               
//convert back to hex and display
               
DisplayData(MessageType.Outgoing, ByteToHex(newMsg) + "\n");
           
}
           
catch (FormatException ex)
           
{
               
//display error message
               
DisplayData(MessageType.Error, ex.Message);
           
}
           
finally
           
{
                _displayWindow
.SelectAll();
           
}
           
break;                
       
default:
           
//first make sure the port is open
           
//if its not open then open it
           
if (!(comPort.IsOpen == true)) comPort.Open();
           
//send the message to the port
            comPort
.Write(msg);
           
//display the message
           
DisplayData(MessageType.Outgoing, msg + "\n");
           
break;    
           
break;
   
}
}
#endregion



You will notice in this method we call three methods:
  • HexToByte
  • ByteToHex
  • DisplayData
These methods are required for this manager. The HexToByte method converts the data provided to binary format, then the ByteToHex converts it back to hex format for displaying. The last one, DisplayData is where we marshal a call to the thread that created the control for displaying the data, since UI controls can only be accessed by the thread that created them. First we'll look at converting the string provided to binary format:

CODE

#region HexToByte
/// <summary>
/// method to convert hex string into a byte array
/// </summary>
/// <param name="msg">string to convert</param>
/// <returns>a byte array</returns>
private byte[] HexToByte(string msg)
{
   
//remove any spaces from the string
    msg
= msg.Replace(" ", "");
   
//create a byte array the length of the
   
//string divided by 2
   
byte[] comBuffer = new byte[msg.Length / 2];
   
//loop through the length of the provided string
   
for (int i = 0; i < msg.Length; i += 2)
       
//convert each set of 2 characters to a byte
       
//and add to the array
        comBuffer
[i / 2] = (byte)Convert.ToByte(msg.Substring(i, 2), 16);
   
//return the array
   
return comBuffer;
}
#endregion



Here we convert the provided string to a byte array, then the WriteData method sends it out the port. For displaying we need to convert it back into string format, so we use the ByteToHex method we created:

CODE

#region ByteToHex
/// <summary>
/// method to convert a byte array into a hex string
/// </summary>
/// <param name="comByte">byte array to convert</param>
/// <returns>a hex string</returns>
private string ByteToHex(byte[] comByte)
{
   
//create a new StringBuilder object
   
StringBuilder builder = new StringBuilder(comByte.Length * 3);
   
//loop through each byte in the array
   
foreach (byte data in comByte)
       
//convert the byte to a string and add to the stringbuilder
        builder
.Append(Convert.ToString(data, 16).PadLeft(2, '0').PadRight(3, ' '));
   
//return the converted value
   
return builder.ToString().ToUpper();
}
#endregion



The last method that WriteData depends on is the DisplayData method. Here we use the Invoke Method of our RichTextBox, the control used to display the data, to create a new EventHandler which creates a new Delegate for setting the properties we wish for our message, then appending it to the value already displayed:

CODE

#region DisplayData
/// <summary>
/// method to display the data to & from the port
/// on the screen
/// </summary>
/// <param name="type">MessageType of the message</param>
/// <param name="msg">Message to display</param>
[STAThread]
private void DisplayData(MessageType type, string msg)
{
    _displayWindow
.Invoke(new EventHandler(delegate
{
  _displayWindow
.SelectedText = string.Empty;
  _displayWindow
.SelectionFont = new Font(_displayWindow.SelectionFont, FontStyle.Bold);
  _displayWindow
.SelectionColor = MessageColor[(int)type];
  _displayWindow
.AppendText(msg);
  _displayWindow
.ScrollToCaret();
}));
}
#endregion



NOTE: You will notice that we hyave added the STAThread Attribute to our method. This is used when a single thread apartment is required by a control, like the RichTextBox.

The next method we will look at it used when we need to open the port initially. Here we set the BaudRate, Parity, StopBits, DataBits and PortName Properties of the SerialPort Class:

CODE

#region OpenPort
public bool OpenPort()
{
   
try
   
{
       
//first check if the port is already open
       
//if its open then close it
       
if (comPort.IsOpen == true) comPort.Close();

       
//set the properties of our SerialPort Object
        comPort
.BaudRate = int.Parse(_baudRate);    //BaudRate
        comPort
.DataBits = int.Parse(_dataBits);    //DataBits
        comPort
.StopBits = (StopBits)Enum.Parse(typeof(StopBits),_stopBits);    //StopBits
        comPort
.Parity = (Parity)Enum.Parse(typeof(Parity),_parity);    //Parity
        comPort
.PortName = _portName;   //PortName
       
//now open the port
        comPort
.Open();
       
//display message
       
DisplayData(MessageType.Normal, "Port opened at " + DateTime.Now + "\n");
       
//return true
       
return true;
   
}
   
catch (Exception ex)
   
{
       
DisplayData(MessageType.Error, ex.Message);
       
return false;
   
}
}
#endregion



Next lets take a look at our event handler. This event will be executed whenever there's data waiting in the buffer. This method looks identical to our WriteData method, because it has to do the same exact work:

CODE

#region comPort_DataReceived
/// <summary>
/// method that will be called when theres data waiting in the buffer
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
   
//determine the mode the user selected (binary/string)
   
switch (CurrentTransmissionType)
   
{
       
//user chose string
       
case TransmissionType.Text:
           
//read data waiting in the buffer
           
string msg = comPort.ReadExisting();
           
//display the data to the user
           
DisplayData(MessageType.Incoming, msg + "\n");
           
break;
       
//user chose binary
       
case TransmissionType.Hex:
           
//retrieve number of bytes in the buffer
           
int bytes = comPort.BytesToRead;
           
//create a byte array to hold the awaiting data
           
byte[] comBuffer = new byte[bytes];
           
//read the data and store it
            comPort
.Read(comBuffer, 0, bytes);
           
//display the data to the user
           
DisplayData(MessageType.Incoming, ByteToHex(comBuffer) + "\n");
           
break;
       
default:
           
//read data waiting in the buffer
           
string str = comPort.ReadExisting();
           
//display the data to the user
           
DisplayData(MessageType.Incoming, str + "\n");
           
break;
   
}
}
#endregion



We have 3 small methods left, and these are actually optional, for the lack of a better word. These methods are used to populate my ComboBox's on my UI with the port names available on the computer, Parity values and Stop Bit values. The Parity and Stop Bits are available in enumerations included with the .Net Framework 2.0:
CODE

#region SetParityValues
public void SetParityValues(object obj)
{
   
foreach (string str in Enum.GetNames(typeof(Parity)))
   
{
       
((ComboBox)obj).Items.Add(str);
   
}
}
#endregion

#region SetStopBitValues
public void SetStopBitValues(object obj)
{
   
foreach (string str in Enum.GetNames(typeof(StopBits)))
   
{
       
((ComboBox)obj).Items.Add(str);
   
}
}
#endregion

#region SetPortNameValues
public void SetPortNameValues(object obj)
{
   
   
foreach (string str in SerialPort.GetPortNames())
   
{
       
((ComboBox)obj).Items.Add(str);
   
}
}
#endregion



That is how you do Serial Port Communication in C#. Microsoft finally gave us intrinsic tools to perform this task, no more relying on legacy objects. I am providing this class and a sample application to show how to implement what we just learned. What I am providing is under the GNU General Public License meaning you can modify and distribute how you see fit, but the license header must stay in tact. I hope you found this tutorial useful and informative, thank you for reading.

출처 : http://www.dreamincode.net/forums/showtopic35775.htm

Serial Port Communication in C#
posted by Sunny's
2009. 3. 11. 14:46 .NET Framework
posted by Sunny's