천객만래 [千客萬來] (It has an interminable succession of visitors)

'c#'에 해당되는 글 35건

  1. 2016.01.08 [개발] C# 인쇄하기
  2. 2015.03.31 [개발/mysql] MySQL 5 C# sample code using ObjectDataSources
  3. 2015.03.03 [개발/C#/ASP.NET] 하드웨어 유일키 생성
  4. 2015.03.03 [개발/ASP.NET/C#] 하드웨어 유일키 얻기 2
  5. 2015.01.22 [ASP.NET] [GDI+] LineChart 그래프를 만들어보자. (ASP.NET using C#)
  6. 2011.01.19 [개발] VC++, C#, 웹페이지의 존재여부를 확인하기 위한 팁입니다.
  7. 2010.12.10 [개발/asp.net] 서버컨트롤에 열거형 값 바인딩하기
  8. 2010.11.23 [개발/asp.net] 웹페이지의 DataGrid 내용만 엑셀로 다운로드
  9. 2010.11.05 [개발] 스레드(Thread) 사용
  10. 2010.11.01 [개발] C# 프로그래머 참조 - 문서 주석에 대한 권장 태그
  11. 2010.11.01 [개발] C# 프로그래머 참조 - 문서 주석에 대한 권장 태그 <c>
  12. 2010.11.01 [개발] C# 프로그래머 참조 - 문서 주석에 대한 권장 태그 <code>
  13. 2010.11.01 [개발] C# 프로그래머 참조 - 문서 주석에 대한 권장 태그 <example>
  14. 2010.10.29 [개발] C# 프로그래머 참조 - 문서 주석에 대한 권장 태그 <exception>
  15. 2010.10.29 [개발] C# 프로그래머 참조 - 문서 주석에 대한 권장 태그 <include>
  16. 2010.10.29 [개발] C# 프로그래머 참조 - 문서 주석에 대한 권장 태그 <list>
  17. 2010.10.29 [개발] C# 프로그래머 참조 - 문서 주석에 대한 권장 태그 <para>
  18. 2010.10.29 [개발] C# 프로그래머 참조 - 문서 주석에 대한 권장 태그 <param>
  19. 2010.10.29 [개발] C# 프로그래머 참조 - 문서 주석에 대한 권장 태그 <paramref>
  20. 2010.10.29 [개발] C# 프로그래머 참조 - 문서 주석에 대한 권장 태그 <permission>

[개발] C# 인쇄하기





인쇄하기

GDI+ 인쇄 관련 클래스들을 보자

클래스설명
PageSetupDialog페이지 설정을 처리하는 대화상자. 용지 크기 및 공급, 방향, 여백 등을 설정
PrintDialog컴퓨터에 설치된 프린터를 선택하는 대화상자. 프린터 속성과 인쇄범위 매수 설정
PrintPreviewDialog프린터에 인쇄할 내용 미리보기 대화상자.
PageSettings인쇄될 특정 페이지에 대한 속성 설정.
PrintDocument인쇄될 내용을 담고 있는 개체
PrinterSettings프린터의 색(흑백/컬러), 급지 방식, 가로 인쇄 등의 프린터 속성 설정

인쇄에 관련된 여러 예제들이 있지만 모두 합쳐서 작업해보면 깔끔할 것 같다.

 

응용작업

일기장 프로그램을 만들어서 프린트 할 수 있도록 하는 작업을 해보도록 하자. 윈도우 응용 프로그램으로 새 프로젝트를 만들고 폼에 컨트롤들을 배치한다.

form_layout.gif

 

 

 

 

 

 

 

 

 

 

 

이 폼 레이아웃에서 특별한 점은 없으나 가장 상위의 날짜 입력부분에 들어가는 컨트롤이 DateTimePicker 라는 점이다. 여기에 들어가는 컨트롤들에 대한 아이디는 본인의 임의대로 지정할 수 있으니 편하게 지정하기 바란다.

먼저 네임스페이스와 생성자 이전까지를 본다.

 

  1. 8 using System.Drawing.Imaging;

    9 using System.Drawing.Printing;  // 추가한다.

    10

    11 namespace DiaryPrint

    12 {

    13     public partial class frmDiary : Form

    14     {

    15         private Font m_MainFont = null;

    16         private Font m_SubFont = null;

    17         private Font m_SmallFont = null;

    18         private PageSettings m_PageSetting = null;

    19         private Bitmap m_BackBmp = null;

    20         private Bitmap[] m_Weather = new Bitmap[4];

    21

    22         public frmDiary()

 

다음으로 생성자 내부의 작업을 수행한다.

  1. 24             InitializeComponent();

    25

    26             string FilePath = Application.StartupPath + "\\";

    27             m_MainFont = new Font("돋움", 15, FontStyle.Bold);

    28             m_SubFont = new Font("돋움체", 13);

    29             m_SmallFont = new Font("바탕체", 9);

    30             m_BackBmp = new Bitmap(GetType(), "LetterBackground.jpg");

    31             // 날씨아이콘

    32             for (int i = 0; i < 4; i++)

    33             {

    34                 string strIcon = string.Format("Weather0{0}.gif", i + 1);

    35                 m_Weather[i] = new Bitmap(GetType(), strIcon);

    36             }

    37             cb_Weather.SelectedIndex = 0;

폼 레이아웃에 나와있는 페이지 설정, 미리보기, 인쇄하기 버튼에 대한 이벤트 작성이다.

  1. 40         private void btn_PageSetup_Click(object sender, EventArgs e)

    41         {

    42             try

    43             {

    44                 PageSetupDialog psd = new PageSetupDialog();

    45                 if (this.m_PageSetting == null)

    46                     this.m_PageSetting = new PageSettings();

    47                 psd.PageSettings = this.m_PageSetting;

    48                 psd.ShowDialog();

    49             }

    50             catch (InvalidPrinterException pex)

    51             {

    52                 MessageBox.Show(pex.Message);

    53             }

    54             catch (Exception ex)

    55             {

    56                 MessageBox.Show(ex.Message);

    57             }

    58         }

    59

    60         private void btn_Preview_Click(object sender, EventArgs e)

    61         {

    62             try

    63             {

    64                 PrintDocument pd = new PrintDocument();

    65                 pd.PrintPage += new PrintPageEventHandler(pd_PrintPage);

    66

    67                 if (this.m_PageSetting != null)

    68                 {

    69                     pd.DefaultPageSettings = this.m_PageSetting;

    70                 }

    71

    72                 PrintPreviewDialog ppd = new PrintPreviewDialog();

    73                 ppd.Document = pd;

    74                 ppd.ShowDialog();

    75             }

    76             catch (Exception ex)

    77             {

    78                 MessageBox.Show(ex.Message);

    79             }

    80         }

    81

    82         private void btn_Print_Click(object sender, EventArgs e)

    83         {

    84             try

    85             {

    86                 PrintDocument pd = new PrintDocument();

    87                 pd.PrintPage += new PrintPageEventHandler(pd_PrintPage);

    88

    89                 if (this.m_PageSetting != null)

    90                 {

    91                     pd.DefaultPageSettings = this.m_PageSetting;

    92                 }

    93

    94                 PrintDialog pdlg = new PrintDialog();

    95                 pdlg.Document = pd;

    96

    97                 if (pdlg.ShowDialog() == DialogResult.OK)

    98                 {

    99                     pd.Print();    // 인쇄

    100                 }

    101             }

    102             catch (Exception ex)

    103             {

    104                 MessageBox.Show(ex.Message);       

    105             }

    106         }

다음으로 가장 핵심 프로세스인 이벤트  pd_PrintPage와 메서드 PaintDocument이다.

  1. 108         protected void pd_PrintPage(object sender, PrintPageEventArgs ppe)

    109         {

    110             Graphics g = ppe.Graphics;

    111             PaintDocument(g);

    112             ppe.HasMorePages = false;

    113         }

    114

    115         private void PaintDocument(Graphics g)

    116         {

    117             g.FillRectangle(Brushes.White, 100, 50, 600, 800);  // 전체 사각형

    118             g.DrawImage(m_BackBmp, 100, 50);    // 배경이미지 출력

    119             g.DrawImage(m_Weather[cb_Weather.SelectedIndex], 380, 120); // 날씨아이콘 출력

    120             g.DrawString(cb_Weather.SelectedItem.ToString(), this.m_MainFont, Brushes.White, 375, 160);   // 날씨적기

    121             g.DrawString(this.dtp_Date.Text, this.m_SubFont, Brushes.Brown, 380, 236);  // 날짜출력

    122

    123             StringFormat sf = new StringFormat();  // 글자포맷

    124             sf.Alignment = StringAlignment.Near;    // 세로정렬

    125             sf.LineAlignment = StringAlignment.Center; // 가로정렬

    126             Rectangle rect = new Rectangle(100, 280, 500, this.m_MainFont.Height * 3); // 제목 적는 영역

    127             g.DrawString(this.txt_Title.Text, this.m_MainFont, Brushes.Black, rect, sf); // 글적기

    128

    129             rect = new Rectangle(240, 350, 500, this.m_SubFont.Height * 10);  // 내용 적는 영역

    130             g.DrawString(this.txt_Contents.Text, this.m_SubFont, Brushes.Black, rect);  // 글 적기

    131         }

닷넷에서 제공하는 프린트에 관련된 핵심 클래스는 다 확인할 수 있으므로 꼭 해보자. 여기에 필요한 이미지는,

LetterBackground.jpgWeather01.gifWeather02.gifWeather03.gifWeather04.gif 총 다섯개 이미지 이다. 받아서 사용해보길 바란다.



PrintDiary.alz


Posted by SB패밀리


MySQL 5 C# sample code using ObjectDataSources



Introduction

I created this example because I could not find a simple explanation for using MySQL 5 with ObjectDataSources in ASP.NET 2.0.

Let me say, I am really impressed with MySQL. I was able to install it easily on my Windows XP machine and get it running in about an hour. I am a long time MS SQL user, and was very frustrated with trying to use Oracle and Firebird. I realize, the problem is that I am spoiled from MS SQL Server, but hey I''m busy and I like easy to use tools :)

If you''re getting started with MySQL and ASP.NET, then I recommend these steps:

  1. Go to the MySQL website, download and install “Current Release (recommended).
  2. Download and install: MySQL Administrator (to administer your MySQL server, the first download just installs only the server).
  3. Download and install: Connector/Net 1.0 (you need this to get your ASP.NET pages to talk to your MySQL server).
  4. You can also download: MySQL Query Browser – (a graphical client to work with your MySQL databases and run queries).
  5. Read and follow this guide: A Step-by-Step Guide to Using MySQL with ASP.NET.

Using the code

To install the code:

  1. You must have MySQL 5 up and running.
  2. Install MySQL Connector/Net 1.0.
  3. Create a MySQL 5 database named Test.
  4. Create a table in that database called Message:
    CREATE TABLE test.message (
    
        Entry_ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
        Name VARCHAR(45),
        Email VARCHAR(45),
        Message VARCHAR(200),
        PRIMARY KEY (Entry_ID)
        )
        AUTO_INCREMENT=32
        CHARACTER SET latin1 COLLATE latin1_swedish_ci;
  5. Create these four MySQL stored procedures in the Test database:
    PROCEDURE `test`.`DeleteMessage`(IN param1 INT)
    BEGIN
    Delete From test.message
    WHERE Entry_ID = param1;
    END
    PROCEDURE `test`.`InsertMessage`(IN param1 VARCHAR(50), IN param2 
        VARCHAR(50), IN param3 VARCHAR(200))
    BEGIN
    INSERT INTO message(Name, Email, Message)
    VALUES(param1,param2,param3);
    END
    PROCEDURE `test`.`ShowAll`()
    BEGIN
    SELECT 
      message.Entry_ID,
      message.Name, 
      message.Email, 
      message.Message
    FROM
      test.message;
    END
    PROCEDURE `test`.`UpdateMessage`(IN paramkey INT, IN param1 VARCHAR(50), 
        IN param2 VARCHAR(50), IN param3 VARCHAR(200))
    BEGIN
    UPDATE    message
    SET              Name = param1, Email = param2, Message = param3
    WHERE     (message.Entry_ID = paramkey);
    END
  6. Unzip "MySQL" and configure IIS to point to it. Make sure you configure the web server to use ASP.NET 2.0.
  7. Open "web.config" and change the line:
    <add name="MySQLConnectionString" connectionString="server=localhost; 
       user id=myuser; password=mypass; database=test; pooling=false;" 
       providerName="MySql.Data.MySqlClient"/>

    to connect to your MySQL database.

  8. Browse to the default.aspx page through IIS.

This is the class that uses Generics to supply the data that is consumed by the ObjectDataSource control:

using System;
using System.Collections.Generic;
using System.Data;
using MySql.Data.MySqlClient;
using System.Configuration;
using System.ComponentModel;

[DataObject(true)]
public static class MessagesDB
{
    private static string GetConnectionString()
    {
        return ConfigurationManager.ConnectionStrings
        ["MySQLConnectionString"].ConnectionString;
    }

    [DataObjectMethod(DataObjectMethodType.Select)]
    public static List<MessageItem> GetMessages()
    {
        MySqlCommand cmd = new MySqlCommand("ShowAll", 
                           new MySqlConnection(GetConnectionString()));
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Connection.Open();
        MySqlDataReader dr = 
           cmd.ExecuteReader(CommandBehavior.CloseConnection);

        List<MessageItem> MessageItemlist = new List<MessageItem>();
        while (dr.Read())
        {
            MessageItem MessageItem = new MessageItem();
            MessageItem.Entry_ID = Convert.ToInt32(dr["Entry_ID"]);
            MessageItem.Message = Convert.ToString(dr["Message"]);
            MessageItem.Name = Convert.ToString(dr["Name"]);
            MessageItem.Email = Convert.ToString(dr["Email"]);
            MessageItemlist.Add(MessageItem);
        }
        dr.Close();
        return MessageItemlist;
    }

    [DataObjectMethod(DataObjectMethodType.Insert)]
    public static void InsertMessage(MessageItem MessageItem)
    {
        MySqlCommand cmd = new MySqlCommand("InsertMessage", 
                           new MySqlConnection(GetConnectionString()));
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.Add(new MySqlParameter("param1", MessageItem.Name));
        cmd.Parameters.Add(new MySqlParameter("param2", MessageItem.Email));
        cmd.Parameters.Add(new MySqlParameter("param3", MessageItem.Message));
        cmd.Connection.Open();
        cmd.ExecuteNonQuery();
        cmd.Connection.Close();
    }

    [DataObjectMethod(DataObjectMethodType.Update)]
    public static int UpdateMessage(MessageItem MessageItem)
    {
        MySqlCommand cmd = new MySqlCommand("UpdateMessage", 
                           new MySqlConnection(GetConnectionString()));
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.Add(new MySqlParameter("paramkey", MessageItem.Entry_ID));
        cmd.Parameters.Add(new MySqlParameter("param1", MessageItem.Name));
        cmd.Parameters.Add(new MySqlParameter("param2", MessageItem.Email));
        cmd.Parameters.Add(new MySqlParameter("param3", MessageItem.Message));
        cmd.Connection.Open();
        int i = cmd.ExecuteNonQuery();
        cmd.Connection.Close();
        return i;
    }

    [DataObjectMethod(DataObjectMethodType.Delete)]
    public static int DeleteMessage(MessageItem MessageItem)
    {
        MySqlCommand cmd = new MySqlCommand("DeleteMessage", 
                new MySqlConnection(GetConnectionString()));
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.Add(new MySqlParameter("param1", MessageItem.Entry_ID));
        cmd.Connection.Open();
        int i = cmd.ExecuteNonQuery();
        cmd.Connection.Close();
        return i;
    }

The class above uses the class "MessageItem" to pass the parameters to and from the ObjectDataSource control:

using System;

public class MessageItem
{
    int _Entry_ID;
    string _Message;
    string _Name;
    string _Email;

    public MessageItem()
    {
    }

    public int Entry_ID
    {
        get
        {
        return _Entry_ID;
        }
        set
        {
        _Entry_ID = value;
        }
    }

    public string Message
    {
        get
        {
            return _Message;
        }
        set
        {
            _Message = value;
        }
    }

    public string Name
    {
        get
        {
            return _Name;
        }
        set
        {
            _Name = value;
        }
    }

    public string Email
    {
        get
        {
            return _Email;
        }
        set
        {
            _Email = value;
        }
    }
}

This is the .aspx file that contains the ObjectDataSource control as well as a GridView for editing data and a DetailsView for inserting a record:

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
   TypeName="MessagesDB" OldValuesParameterFormatString="original_{0}" 
   SelectMethod="GetMessages" DataObjectTypeName="MessageItem" 
   DeleteMethod="DeleteMessage" InsertMethod="InsertMessage" 
   UpdateMethod="UpdateMessage">
</asp:ObjectDataSource>
<br />
<asp:GridView ID="GridView1" runat="server" 
      AutoGenerateColumns="False" 
      DataSourceID="ObjectDataSource1" 
      DataKeyNames="Entry_ID">
 <Columns>
   <asp:BoundField DataField="Entry_ID" HeaderText="Entry_ID" 
           SortExpression="Entry_ID" Visible="False" />
   <asp:CommandField ShowEditButton="True" />
   <asp:CommandField ShowDeleteButton="True" />
   <asp:BoundField DataField="Name" 
         HeaderText="Name" SortExpression="Name" />
   <asp:BoundField DataField="Email" 
         HeaderText="Email" SortExpression="Email" />
   <asp:BoundField DataField="Message" 
         HeaderText="Message" SortExpression="Message" />
 </Columns>
</asp:GridView>
<br />
<strong><span style="text-decoration: underline">
      Insert New Record:</span></strong><br />

<asp:DetailsView ID="DetailsView1" runat="server" 
    AutoGenerateRows="False" BorderStyle="None"
    CellSpacing="5" DataSourceID="ObjectDataSource1" 
    DefaultMode="Insert" GridLines="None"
    Height="50px" Width="300px">
  <Fields>
    <asp:BoundField DataField="Name" HeaderText="Name" />
    <asp:BoundField DataField="Email" HeaderText="Email" />
    <asp:BoundField DataField="Message" HeaderText="Message" />
    <asp:CommandField ButtonType="Button" 
         ShowInsertButton="True" ShowCancelButton="False" />
  </Fields>
</asp:DetailsView>

Note

The assembly "MySql.Data.dll" is in the "/bin" directory so the "MySql.Data.MySqlClient" will work.

I hope this helps!



MySQL_CS_samplesource.zip



Posted by SB패밀리

하드웨어 유일키 생성



using System;
using System.Management;
using System.Security.Cryptography;
using System.Security;
using System.Collections;
using System.Text;
namespace Security
{
    /// <summary>
    /// Generates a 16 byte Unique Identification code of a computer
    /// Example: 4876-8DB5-EE85-69D3-FE52-8CF7-395D-2EA9
    /// </summary>
    public class FingerPrint  
    {
        private static string fingerPrint = string.Empty;
        public static string Value()
        {
            if (string.IsNullOrEmpty(fingerPrint))
            {
                fingerPrint = GetHash("CPU >> " + cpuId() + "\nBIOS >> " + 
   biosId() + "\nBASE >> " + baseId()
                            //+"\nDISK >> "+ diskId() + "\nVIDEO >> " + 
   videoId() +"\nMAC >> "+ macId()
                                     );
            }
            return fingerPrint;
        }
        private static string GetHash(string s)
        {
            MD5 sec = new MD5CryptoServiceProvider();
            ASCIIEncoding enc = new ASCIIEncoding();
            byte[] bt = enc.GetBytes(s);
            return GetHexString(sec.ComputeHash(bt));
        }
        private static string GetHexString(byte[] bt)
        {
            string s = string.Empty;
            for (int i = 0; i < bt.Length; i++)
            {
                byte b = bt[i];
                int n, n1, n2;
                n = (int)b;
                n1 = n & 15;
                n2 = (n >> 4) & 15;
                if (n2 > 9)
                    s += ((char)(n2 - 10 + (int)'A')).ToString();
                else
                    s += n2.ToString();
                if (n1 > 9)
                    s += ((char)(n1 - 10 + (int)'A')).ToString();
                else
                    s += n1.ToString();
                if ((i + 1) != bt.Length && (i + 1) % 2 == 0) s += "-";
            }
            return s;
        }
        #region Original Device ID Getting Code
        //Return a hardware identifier
        private static string identifier
  (string wmiClass, string wmiProperty, string wmiMustBeTrue)
        {
            string result = "";
            System.Management.ManagementClass mc = 
  new System.Management.ManagementClass(wmiClass);
            System.Management.ManagementObjectCollection moc = mc.GetInstances();
            foreach (System.Management.ManagementObject mo in moc)
            {
                if (mo[wmiMustBeTrue].ToString() == "True")
                {
                    //Only get the first one
                    if (result == "")
                    {
                        try
                        {
                            result = mo[wmiProperty].ToString();
                            break;
                        }
                        catch
                        {
                        }
                    }
                }
            }
            return result;
        }
        //Return a hardware identifier
        private static string identifier(string wmiClass, string wmiProperty)
        {
            string result = "";
            System.Management.ManagementClass mc = 
  new System.Management.ManagementClass(wmiClass);
            System.Management.ManagementObjectCollection moc = mc.GetInstances();
            foreach (System.Management.ManagementObject mo in moc)
            {
                //Only get the first one
                if (result == "")
                {
                    try
                    {
                        result = mo[wmiProperty].ToString();
                        break;
                    }
                    catch
                    {
                    }
                }
            }
            return result;
        }
        private static string cpuId()
        {
            //Uses first CPU identifier available in order of preference
            //Don't get all identifiers, as it is very time consuming
            string retVal = identifier("Win32_Processor", "UniqueId");
            if (retVal == "") //If no UniqueID, use ProcessorID
            {
                retVal = identifier("Win32_Processor", "ProcessorId");
                if (retVal == "") //If no ProcessorId, use Name
                {
                    retVal = identifier("Win32_Processor", "Name");
                    if (retVal == "") //If no Name, use Manufacturer
                    {
                        retVal = identifier("Win32_Processor", "Manufacturer");
                    }
                    //Add clock speed for extra security
                    retVal += identifier("Win32_Processor", "MaxClockSpeed");
                }
            }
            return retVal;
        }
        //BIOS Identifier
        private static string biosId()
        {
            return identifier("Win32_BIOS", "Manufacturer")
            + identifier("Win32_BIOS", "SMBIOSBIOSVersion")
            + identifier("Win32_BIOS", "IdentificationCode")
            + identifier("Win32_BIOS", "SerialNumber")
            + identifier("Win32_BIOS", "ReleaseDate")
            + identifier("Win32_BIOS", "Version");
        }
        //Main physical hard drive ID
        private static string diskId()
        {
            return identifier("Win32_DiskDrive", "Model")
            + identifier("Win32_DiskDrive", "Manufacturer")
            + identifier("Win32_DiskDrive", "Signature")
            + identifier("Win32_DiskDrive", "TotalHeads");
        }
        //Motherboard ID
        private static string baseId()
        {
            return identifier("Win32_BaseBoard", "Model")
            + identifier("Win32_BaseBoard", "Manufacturer")
            + identifier("Win32_BaseBoard", "Name")
            + identifier("Win32_BaseBoard", "SerialNumber");
        }
        //Primary video controller ID
        private static string videoId()
        {
            return identifier("Win32_VideoController", "DriverVersion")
            + identifier("Win32_VideoController", "Name");
        }
        //First enabled network card ID
        private static string macId()
        {
            return identifier("Win32_NetworkAdapterConfiguration", 
    "MACAddress", "IPEnabled");
        }
        #endregion
    }
}

 

 

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

결과물


 

CPU >> BFEBFBFF000006FB
BIOS >> Phoenix Technologies, LTD6.00 PGOEM20070919000000.000000+000IntelR - 42302e31
BASE >> Biostar Group기반 보드 
DISK >> ST3320620AS(표준 디스크 드라이브)3720011194255
MAC >> 00:E0:4D:51:45:1C

 

 

 

CPU >> BFEBFBFF000006FB
BIOS >> Phoenix Technologies, LTD6.00 PGOEM20070919000000.000000+000IntelR - 42302e31
BASE >> Biostar Group기반 보드 
암호화 : 129D-6375-4122-54E7-D304-D826-D1E8-684C



Posted by SB패밀리




Contacting a Registration Server to obtain a unique registration key based on unique machine ID

 

Introduction
Sometimes in the industry, it is required to collect some unique machine information and send it to a server for the purpose of creating a unique registration key based on the hardware information. This is required in the case when the software requires a per PC registration. Thus we can collect the machine information of the PC in which the software was installed, and issue a registration key which will be valid only for that machine.

Background 
Using WMI functionality, it is possible to collect machine specific hardware information. 
In .NET, one can use System.Management.ManagementClass for this purpose. (This is explained in this article.)

The problem arises when we try to send this information to the server. Because of the firewall that is present in OSes starting from WinXP, if we try to send data from our application to an external server, the firewall pops up a warning to the user informing her/him that the application is trying to send data and asks the user whether she/he wants to proceed or block the application. (Also this approach will fail if the local network is connected to the Internet through a firewall, which is configured to block anything other than HTTP traffic.)

The solution thus comes in the form of HTTP (i.e. we have to send the data through HTTP).
In .NET, this is easily achieved through System.Net.WebRequest or by using a Web Service. This article uses the WebRequest approach.

Using the Code 
In the class ContactRegistationServer (UserRegistration project), you will notice that we are creating a WebRequest and passing the hardware information through QueryString.

WebResponse registrationKey = null;
String url_string = "http://localhost/Registration/Registration.aspx"
    + "?CPU=" + System.Web.HttpUtility.UrlEncode(hardwareInfo.cpuID)
    + "&BIOS=" + System.Web.HttpUtility.UrlEncode(hardwareInfo.biosID)
    + "&MB=" + System.Web.HttpUtility.UrlEncode(hardwareInfo.baseID)
    + "&DISK=" + System.Web.HttpUtility.UrlEncode(hardwareInfo.diskID)
    + "&MAC=" + System.Web.HttpUtility.UrlEncode(hardwareInfo.macID)
    + "&VIDEO=" + System.Web.HttpUtility.UrlEncode(hardwareInfo.videoID);
try
{
    WebRequest requestRegistration = WebRequest.Create(url_string);
    registrationKey = requestRegistration.GetResponse();
}
catch (Exception ex)
{
    System.Windows.Forms.MessageBox.Show("Failed connecting to server");
    return;
}
On the server (Refer project 'TestPage' Registration.aspx.cs), the QueryString received from the client is retrieved and a unique registration key is produced and returned to the user.

//Call the Foolproof Registration Key algorithm :)
TheFoolProofRegistrationKey regKey = new TheFoolProofRegistrationKey();
String key = regKey.getRegistrationKey(Request.QueryString["CPU"]);
Response.Write(key);
Notes: If You Decide to Download and Run the Program
If you decide to download and try the application, please make sure to create a virtual folder of the name "Registration" on your local Web server. This is required as the WebRequest is using the following URL: http://localhost/Registration/Registration.aspx (or else copy the files to a folder by the name Registration under the server root folder).

Just for the use of a novice, I have attached a few screen shots on how to add the virtual directory on IIS.


And finally you should have something as follows:

Points of Interest 
For testing purposes, I also tried to connect to the server from a different PC: (e.g.: http://10.10.42.135/Registration/Registration.aspx) and it still worked - the firewall did not complain:). 
I did not try to connect to a server outside our network, but I guess that should also work...

 

To collect machine specific information, use the code in this article.









Posted by SB패밀리






1. Introduction
닷넷은 GDI+의 지원으로 더욱더 강력한 웹페이지를 만들어 낼수 있다고 생각한다. 이번 아티글은 동적으로 저장된 데이터를 가지고 바로 Line으로 표현하는 LineChart를 만들어 보고자 한다. 



2. Code

Line Chart클래스의 클래스이다. 현재 Current페이지의 ContentType 를 Image/jpeg로 설정한후 바로 브라우저에 그래픽을 뿌려지게 된다. 내부의 코드를 따로 설명하지 않아도 주석을 보면 코드를 충분히 이해 할수 있을것이다.

namespace에 using System.Drawing.Imaging;를 선언한다.



class LineChart

{



    public Bitmap b;

    public string Title="Default Title";

    public ArrayList chartValues = new ArrayList();//데이터저장

    public float Xorigin=0, Yorigin=0;

    public float ScaleX, ScaleY;

    public float Xdivs=2, Ydivs=2;



    private int Width, Height;

    private Graphics g;



    //데이터 구조체

    struct datapoint 

    {

        public float x;

        public float y;

        public bool valid;

    }



    //생성자,초기설정

    public LineChart(int myWidth, int myHeight)

    {

        Width = myWidth; Height = myHeight;

        ScaleX = myWidth; ScaleY = myHeight;

        b = new Bitmap(myWidth, myHeight);

        g = Graphics.FromImage(b);

    }



    public void AddValue(int x, int y) //데이터를 저장한다.

    {

        datapoint myPoint;

        myPoint.x=x;

        myPoint.y=y;

        myPoint.valid=true;

        chartValues.Add(myPoint);

    }



    public void Draw() //그리기

    {

        int i;

        float x, y, x0, y0;

        string myLabel;

        Pen YellowPen = new Pen(Color.Yellow,1);

        Brush YellowBrush = new SolidBrush(Color.Yellow);

        Font axesFont = new Font("arial",10);



        //먼저 이미지 사이즈와 초기화 지역을 잡는다.

        HttpContext.Current.Response.ContentType="image/jpeg";

        g.FillRectangle(new

            SolidBrush(Color.Black),0,0,Width,Height);

        int ChartInset = 50;

        int ChartWidth = Width-(2*ChartInset);

        int ChartHeight = Height-(2*ChartInset);

        g.DrawRectangle(new

            Pen(Color.Yellow,1),ChartInset,ChartInset,ChartWidth,ChartHeight);



        //위에서 설정한 Chart제목을 그린다.

        g.DrawString(Title, new Font("arial",14), YellowBrush,Width/3, 10);



        //X축 좌표 그리기

        for(i=0; i<=Xdivs; i++) 

        {

            x=ChartInset+(i*ChartWidth)/Xdivs;

            y=ChartHeight+ChartInset;

            myLabel = (Xorigin + (ScaleX*i/Xdivs)).ToString();

            g.DrawString(myLabel, axesFont, YellowBrush, x-4,

                y+10);

            g.DrawLine(YellowPen, x, y+2, x, y-2);

        }

        //Y축 좌표 그리기

        for(i=0; i<=Ydivs; i++) 

        {

            x=ChartInset;

            y=ChartHeight+ChartInset-(i*ChartHeight/Ydivs);

            myLabel = (Yorigin + (ScaleY*i/Ydivs)).ToString();

            g.DrawString(myLabel, axesFont, YellowBrush, 5, y-6);

            g.DrawLine(YellowPen, x+2, y, x-2, y);

        }



        //시작점을 0,0으로 설정한다.

        g.RotateTransform(180);

        g.TranslateTransform(0,-Height);

        g.TranslateTransform(-ChartInset,ChartInset);

        g.ScaleTransform(-1, 1);



        //데이터를 그래프로 표혀한다.

        datapoint prevPoint = new datapoint();

        prevPoint.valid=false;

        foreach(datapoint myPoint in chartValues) 

        {

            if(prevPoint.valid==true) 

            {

                x0=ChartWidth*(prevPoint.x-Xorigin)/ScaleX;

                y0=ChartHeight*(prevPoint.y-Yorigin)/ScaleY;

                x=ChartWidth*(myPoint.x-Xorigin)/ScaleX;

                y=ChartHeight*(myPoint.y-Yorigin)/ScaleY;

                g.DrawLine(YellowPen,x0,y0,x,y);

                g.FillEllipse(YellowBrush,x0-2,y0-2,4,4);

                g.FillEllipse(YellowBrush,x-2,y-2,4,4);

            }

            prevPoint = myPoint;

        }



        //바지막으로 객체를 저장하여 브라우저에 뿌려준다.

        b.Save(HttpContext.Current.Response.OutputStream, ImageFormat.Jpeg);

    }



    //소멸자

    ~LineChart() 

    {

        g.Dispose();

        b.Dispose();

    }

}



아래는 클래스를 생성하여 적용하는 예제이다. Title과 x,y의 Scale을 설정한다. 그리고 데이터를 ArrayList배열에 추가하면 간단한 차트 그래프가 완성된다. 

private void Page_Load(object sender, System.EventArgs e)

{

    //객체 생성하기

    LineChart c = new LineChart(640, 480);

    

    //차트의 크기를 설정한다.

    c.Title="Hoons Line Chart (ASP.NET GDI+)";

    c.Xorigin=0; c.ScaleX=500; c.Xdivs=5;

    c.Yorigin=0; c.ScaleY=1000; c.Ydivs=5;

    

    //임의의 데이터를 넣는다.

    c.AddValue(50,50);

    c.AddValue(100,100);

    c.AddValue(200,150);

    c.AddValue(450,450);

    

    //메모리에 그려서 브라우저로 전달한다.

    c.Draw();

}

Posted by SB패밀리

웹페이지의 존재여부를 확인하기 위한 팁입니다.
[VC++]
Check.cpp

CServer downloadServer;
CString strDownLoadStatus = downloadServer.RequestServer(strUrl.GetBuffer(0));

 

웹페이지의 존재여부를 확인하기 위한 팁입니다.
[C#]

주어진 URL에 해당하는 웹서버의 HTTP status code을 이용하여 확인한다.

 boolean exists(String URLName){
   try {
     HttpURLConnection.setFollowRedirects(true)
     HttpURLConnection con =
        (HttpURLConnection) new URL(URLName).openConnection();
        con.setRequestMethod("HEAD");
     if (con.getResponseCode() == HttpURLConnection.HTTP_OK)
        return true;
     }
   catch (Exception e) { }
     return false;
   }

Posted by SB패밀리

쌈꼬쪼려 소백촌닭

출처 : http://blog.naver.com/tear230/100020088426

ColorType이라는 열겨형 객체가 아래와 같이 선언되어 있고,

 enum ColorType { Red = 1, Green = 2, Blue = 4, Yellow = 8 };

 DropDownList1이라는 드롭다운리스트 컨트롤이 아래와 같이 선언되어 있다고 할경우

 <asp:DropDownList runat="server" DataTextField="Key" DataValueField="Value"
id="DropDownList1">

 DropDownList1에 ColorType을 아래코드처럼 바인딩 하려고 하면 에러가 발생합니다.

 DropDownList1.DataSource = ColorType;

이럴경우 해쉬테이블로 만들어 반환하는 메서드를 만들어서 사용한다.

public static Hashtable BindToEnum( Type enumType )
{  
    string[] names = Enum.GetNames( enumType );   //열거형의 이름 배열

    Array values = Enum.GetValues( enumType );   // 열거형의 값의 배열  
    Hashtable ht = new Hashtable();
    for (int i = 0; i < names.Length; i++)   

        ht.Add(names[i], (int)values.GetValue(i));
    return ht;
}

바인딩할때는...

//this.DropDownList1.DataValueField = "Value";
//this.DropDownList1.DataTextField = "Key";

this.DropDownList1.DataSource = BindToEnum( typeof( ColorType) );
this.DropDownList1.DataBind();

Posted by SB패밀리

현재 페이지에 표시된 DataGrid의 내용을 버튼클릭시 다운로드 하는 소스입니다.
필요해서 한번 해봤는데 되네요..

 

DataListRepeater 등 모든 서버컨트롤이나 HTML컨트롤에도 사용 가능합니다! *^^*

 

private void Button1_Click(object sender, System.EventArgs e)
{   
    System.Web.HttpContext.Current.Response.Buffer = true;
    System.Web.HttpContext.Current.Response.AddHeader
        ("Content-Disposition", "attachment;filename=20050614.xls");
   System.Web.HttpContext.Current.Response.ContentType="application/unknown";

 

    // 이부분은 web.config의 <globalization requestEncoding="utf-8"   
    // responseEncoding="utf-8" /> 인코딩 부분과 같도록 맞춰주시면 됩니다.
   

    // 2005.09.26 추가 : 인코딩 문자열을 자동으로 맞추려면

    // Request.ContentEncoding.HeaderName 로 인코딩 문자열을 받아서 사용한다.

    System.Web.HttpContext.Current.Response.Write       
        ("<meta http-equiv=Content-Type content='text/html; charset=utf-8'>");

 

    System.IO.StringWriter sWriter = new System.IO.StringWriter();   
    System.Web.UI.HtmlTextWriter htmlWriter
           = new System.Web.UI.HtmlTextWriter(sWriter);


    DataGrid1.RenderControl(htmlWriter);   


    System.Web.HttpContext.Current.Response.Write(sWriter.ToString());   
    System.Web.HttpContext.Current.Response.End();
}

참조 : http://blog.naver.com/tear230/100013986512

DataGrid를 이용할줄 안다면 GridView도 응용해서 이용할수 있습니다.
Posted by SB패밀리

스레드 사용

Greg Ewing
Clarity Consulting Inc.

요약: 이 기사에서는 스레딩의 다른 모델(단일, 아파트 및 자유)과 각 모델의 사용에 대해 설명합니다. 스레드를 이용하는 응용 프로그램을 작성하는 데 도움을 줄 수 있도록 스레드를 사용하는 C# 코드 샘플도 소개합니다. 또한 다중 스레딩 코드에 포함된 중요한 문제에 대해서도 설명합니다(9페이지/인쇄 페이지 기준).

목차

소개
스레딩에 대한 배경 지식
예제 응용 프로그램
다중 스레드 코드의 문제
결론

소개

다중 스레드 MSMQ(Microsoft Message Queuing) 트리거 응용 프로그램을 작성하는 일은 일반적으로 까다로운 작업이었습니다. 그러나 .NET Framework 스레딩 및 메시징 클래스의 도입으로 어느 때보다 쉬워졌습니다. 이 클래스를 사용하면 .NET Framework를 대상으로 하는 모든 언어로 다중 스레드 응용 프로그램을 작성할 수 있습니다. 이전에 Microsoft Visual Basic과 같은 도구는 스레딩에 대한 지원이 매우 제한되어 있었습니다. 따라서 C++을 사용하여 다중 스레드 코드를 작성하거나 Visual Basic에서 여러 프로세스나 ActiveX DLL로 구성되는 이상적이지 않은 솔루션을 작성하거나 또는 다중 스레딩을 완전히 무시하는 수 밖에 없었습니다. .NET Framework에서는 어떤 언어를 사용하는지에 관계없이 풍부한 다중 스레드 응용 프로그램을 작성할 수 있습니다.

이 기사에서는 Microsoft 메시지 대기열의 메시지를 수신하고 처리하는 다중 스레드 응용 프로그램을 작성하는 프로세스를 단계적으로 소개하며, 특히 System.ThreadingSystem.Messaging이라는 두 가지 네임스페이스에 초점을 둡니다. 샘플 코드는 C#으로 작성되어 있지만 원하는 다른 언어로 쉽게 변환할 수 있습니다.

스레딩에 대한 배경 지식

Win32 환경에서 스레딩의 기본 모델은 단일, 아파트 및 자유 등 세 가지입니다.

단일 스레딩

처음에 작성한 응용 프로그램은 아마 응용 프로그램의 프로세스에 해당하는 스레드만 포함된 단일 스레드였을 것입니다. 프로세스는 해당 응용 프로그램의 메모리 공간을 차지하는 응용 프로그램의 인스턴스로 정의할 수 있습니다. 대부분의 Windows 응용 프로그램은 단일 스레드에서 모든 작업을 수행하는 단일 스레드 응용 프로그램입니다.

아파트 스레딩

아파트 스레딩은 단일 스레드보다 복잡한 스레딩 모델입니다. 아파트 스레딩으로 표시된 코드는 자체의 아파트로 제한된 고유 스레드에서 실행될 수 있습니다. 스레드는 처리 시간 동안 일어날 프로세스에서 소유하는 엔터티로 정의할 수 있습니다. 아파트 스레딩 모델에서 모든 스레드는 기본 응용 프로그램의 메모리에서 각각의 하위 섹션 내에서만 작동합니다. 이 모델에서는 코드의 여러 인스턴스를 동시에 그리고 독립적으로 실행할 수 있습니다. 예를 들어 .NET 이전의 Visual Basic에서는 아파트 스레드 구성 요소와 응용 프로그램을 만드는 것으로 제한되어 있었습니다.

자유 스레딩

자유 스레딩은 가장 복잡한 스레딩 모델입니다. 자유 스레딩 모델에서는 동시에 여러 스레드가 같은 메서드와 구성 요소로 호출됩니다. 아파트 스레딩과 달리 자유 스레딩은 분리된 메모리 공간에 제한되지 않습니다. 예를 들어 응용 프로그램에서 매우 비슷하지만 독립적인 수학 계산을 대량으로 실행해야 하는 경우에 자유 스레드 개체를 사용할 수 있습니다. 이 경우 같은 코드 인스턴스를 사용하여 계산을 실행하는 여러 스레드를 만듭니다. Visual Basic 6.0과 같은 언어에서는 이와 같은 작업이 거의 불가능하므로 자유 스레드 응용 프로그램을 작성한 경험이 있는 응용 프로그램 개발자는 아마 C++ 개발자뿐일 것입니다.

스레딩 모델 작업

스레딩 모델에 대한 개념의 이해를 돕는 예로 한 집에서 다른 집으로 이사하는 일을 들 수 있습니다. 단일 스레드 방법은 포장에서 상자 운반과 짐 풀기까지의 모든 일을 직접하는 것이라고 볼 수 있습니다. 아파트 스레딩 모델로 작업하는 경우는 절친한 친구 몇에게 도움을 청하는 것과 같습니다. 각 친구는 각기 다른 방에서 일하고 다른 방에서 일하는 사람을 도울 수 없습니다. 그들은 각자의 공간과 이삿짐을 맡습니다. 자유 스레드 방법을 선택하는 경우, 친구들에게 도움을 요청하는 것은 아파트 스레딩 모델과 동일하지만 친구들이 모두 어느 시간이나 어느 방에서든 함께 이삿짐을 꾸릴 수 있다는 점이 다릅니다. 이 비유에서 집은 모든 스레드가 작동하는 프로세스이고 각 친구는 코드의 인스턴스이며 이삿짐은 응용 프로그램의 리소스와 변수입니다.

위의 예에서는 각 모델의 장점과 단점을 보여 줍니다. 아파트 스레딩은 구성 요소의 여러 인스턴스가 작동하므로 단일 스레딩보다 빠릅니다. 자유 스레딩에서는 모든 일이 동시에 일어나고 모든 리소스가 공유되므로 어떤 경우에는 아파트 스레딩보다 빠르고 훨씬 효율적입니다. 그러나 여러 스레드에서 공유 리소스를 변경하는 경우 문제가 일어날 수 있습니다. 한 사람이 상자를 사용해 부엌 물건을 싼 다음 다른 친구가 와서 같은 상자에 침실 물건을 포장하는 경우를 생각해 보십시오. 첫 번째 친구는 상자에 '부엌'이라는 레이블을 붙였는데 뒷 친구가 그 위에 '침실'이라는 레이블을 붙입니다. 결국 짐을 풀 때는 부엌 물건을 침실에서 풀게 될 것입니다.

예제 응용 프로그램

첫 단계로 예제 응용 프로그램의 디자인을 검토합니다. 이 응용 프로그램에서는 여러 스레드를 만들고 각 스레드는 MSMQ 대기열의 메시지를 수신합니다. 이 예제에서는 기본 Form 클래스와 사용자 지정 MQListen 클래스의 두 가지 클래스를 사용합니다. Form 클래스는 사용자 인터페이스를 처리하는 것과 아울러 작업자 스레드를 만들고 관리하고 소멸시킵니다. MQListen 클래스에는 메시지 대기열 항목을 비롯해 작업자 스레드를 실행하는 데 필요한 모든 코드가 포함됩니다.

응용 프로그램 준비

  • 응용 프로그램을 시작하려면 Visual Studio .NET을 열고 MultiThreadedMQListener라는 C# Windows 응용 프로그램을 새로 만듭니다. 폼의 속성을 열고 이름을 QueueListenerForm으로 지정합니다. 초기 폼이 그려지면 그 위에 레이블 두 개, 단추 두 개, 상태 표시줄 한 개 및 텍스트 상자 두 개를 끌어 놓습니다. 첫 번째 텍스트 상자는 Server로, 두 번째는 Queue로 이름을 지정합니다. 첫 번째 단추는 StartListening로, 두 번째는 StopListening으로 이름을 지정합니다. 상태 표시줄은 기본 이름인 statusBar1로 그대로 두어도 됩니다.
  • 그런 다음 프로젝트 메뉴에서 참조 추가를 클릭하여 System.Messaging 네임스페이스에 대한 참조를 추가합니다. .NET 구성 요소 목록에서 System.Messaging.Dll을 찾아 선택합니다. 이 네임스페이스에는 MSMQ 대기열과 통신하는 데 사용되는 클래스가 포함됩니다.
  • 그런 다음 파일 메뉴에서 새 항목 추가를 클릭하여 프로젝트에 새 클래스를 추가합니다. Class 템플릿을 선택하고 이름을 MQListen으로 지정합니다. 클래스 맨 위에 다음과 같은 using 문을 추가합니다.
    // C#
    using System.Threading;
    using System.Messaging;

    System.Threading 네임스페이스를 사용하여 필요한 모든 스레딩 기능(이 경우, Thread 클래스와 ThreadInterruptException 생성자)에 액세스할 수 있습니다. 이 네임스페이스에서 사용할 수 있는 다른 많은 추가 기능이 있으나, 이 기사에서는 이에 대해 다루지 않습니다. System.Messaging 네임스페이스를 사용하면 대기열의 메시지 보내기 및 받기를 포함한 MSMQ 기능에 액세스할 수 있습니다. 이 예제에서는 MessageQueue 클래스를 사용하여 메시지를 수신합니다. 또한 기본 폼 코드에 using System.Threading도 추가합니다.

모든 참조가 준비가 되면 코드 작성을 시작할 수 있습니다.

작업자 스레드

첫 단계로 모든 스레드 작업을 캡슐화하는 MQListen 클래스를 작성합니다. 다음 코드를 MQListen대해서도 삽입합니다.

// C#
public class MQListen
{   
   private string m_MachineName;
   private string m_QueueName;
      
   // 생성자는 필요한 대기열 정보를 적용합니다.
   public MQListen(string MachineName, string QueueName)
   {
      m_MachineName = MachineName;
      m_QueueName = QueueName;
   }
    

   // 각 스레드에서 MQ 메시지를 수신하는 데 사용하는 유일한 메서드입니다. 
   public void Listen()
   {
     // MessageQueue 개체를 만듭니다.
System.Messaging.MessageQueue MQ = new System.Messaging.MessageQueue(); // MessageQueue 개체의 경로 속성을 설정합니다.
MQ.Path = m_MachineName + "\\private$\\" + m_QueueName; // Message 개체를 만듭니다.
System.Messaging.Message Message = new System.Messaging.Message();
// 인터럽트가 수신될 때까지 반복합니다. while (true) { try { // 인터럽트가 throw된 경우 catch하기 위해 대기합니다. System.Threading.Thread.Sleep(100);
// Message 개체를 receive 함수의 결과와 동일하게 설정합니다. // Timespan(일, 시간, 분, 초).
Message = MQ.Receive(new TimeSpan(0, 0, 0, 1)); // 받은 메시지의 레이블을 표시합니다.
System.Windows.Forms.MessageBox.Show(" Label: " + Message.Label); } catch (ThreadInterruptedException e) {
// 기본 스레드에서 ThreadInterrupt를 catch하고 끝냅니다.
Console.WriteLine("Exiting Thread"); Message.Dispose(); MQ.Dispose(); break; } catch (Exception GenericException) { // receive에서 throw된 예외를 catch합니다.
Console.WriteLine(GenericException.Message); } } } }

코드 설명

MQListen 클래스에는 생성자 이외에 함수가 하나 있습니다. 이 함수는 각 작업 스레드가 실행하는 모든 작업을 캡슐화합니다. 스레드가 시작될 때 이 함수가 실행될 수 있도록 기본 스레드에서 이 함수에 대한 참조를 스레드 생성자로 전달합니다. Listen에서는 우선 메시지 대기열 개체를 설정합니다. MessageQueue 생성자는 세 가지 구현으로 오버로드됩니다. 첫 번째 구현 작업은 수신할 대기열의 위치를 지정하는 문자열 인수와 대기열을 처음으로 액세스하는 응용 프로그램에 대기열에 대한 단독 읽기 권한을 부여해야 하는지 여부를 지정하는 부울 등 두 가지 인수를 취합니다. 두 번째 구현은 대기열 경로 인수만을 취하고 세 번째 구현은 아무 인수도 취하지 않습니다. 간단히 하기 위해 세 번째 구현을 사용하여 다음 줄에 경로를 할당할 수 있습니다.

대기열에 대한 참조를 마쳤으면 메시지 개체를 만들어야 합니다. 메시지 생성자도 세 가지 구현을 가집니다. 처음 두 구현은 대기열에 메시지를 쓸 경우에 사용할 수 있습니다. 이 구현에서는 메시지 본문에 들어갈 개체와 메시지 본문으로 개체가 serialize되는 방법을 정의하는 IMessageFormatter 개체를 취합니다. 여기서는 대기열에서 읽는 중이므로 빈 메시지 개체를 초기화합니다.

개체를 초기화한 후 모든 작업을 수행할 기본 루프를 입력합니다. 나중에 기본 스레드에서 이 스레드를 중지시키기 위해 Interrupt를 호출하면 스레드가 대기, 중지 또는 조인 상태에 있는 경우에만 중단됩니다. 세 가지 상태 중 하나에 있지 않은 경우 다음에 이런 상태로 들어가기 전까지는 중단되지 않습니다. 작업자 스레드가 대기, 중지 또는 조인 상태를 입력하도록 하려면System.Threading 네임스페이스에 있는 Sleep 메서드를 호출합니다. Sleep 메서드는 이전에 Windows API sleep 함수를 사용한 경험이 있는 C++ 개발자와 Visual Basic 개발자에게는 아주 익숙할 것입니다. 이 메서드는 스레드가 대기하는 시간(밀리초)이라는 단일 인수를 취합니다. Sleep 메서드를 호출하지 않으면 작업자는 인터럽트 요청을 받을 수 있는 상태를 입력할 수 없고 프로세스를 수동으로 종료하기 전까지는 무기한 계속됩니다.

MQ Receive 메서드의 구현은 두 가지입니다. 첫 번째 구현은 아무것도 취하지 않으며 메시지를 수신할 때까지 무한히 대기합니다. 이 예제에서 사용되는 두 번째 구현에서는 TimeSpan 개체로 제한 시간을 지정합니다. TimeSpan 생성자에는 일, 시간, 분, 초 등 네 가지 인수가 있습니다. 이 예제에서는 Receive 메서드가 1초 동안 대기한 후 시간이 초과되어 반환됩니다.

메시지가 수신되면 메시지는 앞에서 만든 메시지 개체에 할당되어 처리에 사용될 수 있습니다. 이 예제에서는 해당 레이블이 있는 메시지 상자를 열고 메시지를 삭제합니다. 이 코드를 실제 사용을 위해 변경하려면 여기에 메시지 처리 코드를 넣습니다.

작업자 스레드에서 Interrupt 요청을 수신하면 ThreadInterruptedException 예외를 throw합니다. 해당 예외를 catch하려면 SleepReceive 함수를 try-catch 블록에 래핑합니다. 두 가지 catch를 지정해야 합니다. 첫째는 인터럽트 예외를 catch하고 둘째는 catch되는 오류 예외를 처리합니다. 인터럽트 예외가 catch되면 우선 스레드가 끝나는 디버그 창에 씁니다. 그런 다음 대기열 개체와 메시지 개체에서 Dispose 메서드를 호출하여 모든 메모리를 정리하고 가비지 수집기로 보냅니다. 마지막으로 while 루프를 빠져 나갑니다.

함수에서 while 루프를 끝내자마자 관련 스레드는 코드 0으로 종료합니다. 디버그 창에 'The thread '<name>' (0x660) has exited with code 0 (0x0)'와 같은 메시지가 나타납니다. 스레드는 이제 컨텍스트를 벗어났으며 자동으로 소멸됩니다. 기본 스레드와 작업 스레드 중 어디에서도 정리하기 위해 별도로 해야 할 일은 없습니다.

기본 폼

다음 단계에서는 폼에 코드를 추가하여 작업자 스레드를 만들고 각 스레드에서 MQListen 클래스를 시작합니다. 우선 폼에 다음과 같은 함수를 추가합니다.

// C#
private void StartThreads()
{
   int LoopCounter; // 스레드 수
   StopListeningFlag = false;
// 작업자가 중지될지 여부를 추적하는 플래그입니다. // 작업자 스레드가 될 5개의 스레드 배열을 선언합니다.
Thread[] ThreadArray = new Thread[5]; // 작업자 스레드의 모든 코드를 포함하는 클래스를 선언합니다.
MQListen objMQListen = new MQListen(this.ServerName.Text,this.QueueName.Text); for (LoopCounter = 0; LoopCounter < NUMBER_THREADS; LoopCounter++) { // Thread 개체를 만듭니다.
ThreadArray[LoopCounter] = new Thread(new ThreadStart(objMQListen.Listen));

// 스레드를 시작하면 ThreadStart 대리자를 호출합니다.
ThreadArray[LoopCounter].Start(); } statusBar1.Text = LoopCounter.ToString() + " listener threads started"; while (!StopListeningFlag) { // 사용자가 중지 단추를 누를 때까지 대기합니다. // 대기하는 동안 시스템에서는 다른 이벤트를 처리할 수 있습니다.
System.Windows.Forms.Application.DoEvents(); } statusBar1.Text = "Stop request received, stopping threads"; // 인터럽트 요청을 각 스레드에 보냅니다. for (LoopCounter = 0;LoopCounter < NUMBER_THREADS; LoopCounter++) { ThreadArray[LoopCounter].Interrupt(); } statusBar1.Text = "All Threads have been stopped"; }

코드 설명

이 함수에서는 먼저 5개의 항목으로 구성된 스레드 배열을 만듭니다. 이 배열은 나중에 사용할 수 있도록 모든 스레드 개체에 대한 참조를 보관합니다.

MQListen 클래스의 생성자는 메시지 대기열을 호스팅하는 컴퓨터 이름과 수신할 대기열의 이름 등 두 가지 인수를 취합니다. 이 생성자는 텍스트 상자의 값을 사용하여 이 인수를 할당합니다.

스레드를 만들려면 각 스레드 개체를 초기화할 루프를 입력합니다. 스레드의 Start 메서드가 호출될 때 호출될 함수를 가리키는 대리자를 Thread 생성자에 전달해야 합니다. MQListen.Listen 함수를 사용하여 스레드를 시작할 수 있지만 이 함수는 대리자가 아닙니다. 스레드 생성자의 요구 사항을 충족하려면 ThreadStart 개체를 전달하여 지정된 함수 이름으로 대리자를 만들어야 합니다. 여기서는 MQListen.Listen 함수에 대한 참조를 ThreadStart 개체에 전달합니다. 이 배열 요소가 초기화되었으므로 곧바로 Start 메서드를 호출하여 스레드를 시작합니다.

스레드가 모두 시작되면 폼의 상태 표시줄을 적절한 메시지로 업데이트합니다. 스레드가 실행되면서 대기열을 수신하고 있는 동안 기본 스레드는 사용자가 응용 프로그램에 수신을 중단하도록 요청할 때까지 대기합니다. 이렇게 하려면 사용자가 StopListening 단추를 클릭할 때까지 while 루프를 입력하여 StopListeningFlag값을 변경합니다. 이 대기 루프에서 응용 프로그램은 Forms.Application.DoEvents 메서드를 사용하여 필요한 다른 모든 처리를 수행할 수 있습니다. 이것은 Visual Basic에 익숙한 사람에게는 이전의 DoEvents 메서드와 같고, C++에 익숙한 사람에게는 MSG 펌프를 작성하는 것과 동일합니다.

StopListening 단추를 클릭하면 이 루프가 끝나고 스레드 종료 코드로 진입합니다. 스레드를 모두 종료하기 위해 코드에서는 스레드 배열 내에서 루프하여 각 스레드에 인터럽트 신호를 보냅니다. 이 루프 내에서 배열의 각 스레드 개체에 대해 Interrupt 메서드를 호출합니다. 이 메서드가 호출되기 전까지는 MQListen 클래스의 코드는 정상적으로 실행됩니다. 이 때문에 다른 것을 처리하는 도중에라도 각 작업자에 대해 Interrupt를 호출할 수 있습니다. 스레드 클래스는 스레드가 완료되면 각 스레드의 정리를 처리합니다. 마지막 작업으로 기본 폼의 상태 표시줄을 업데이트하고 종료합니다.

이제 단추 뒤에 코드를 추가해야 합니다. 다음과 같은 코드를 StartListening 단추의 Click 이벤트에 추가합니다.

// C#
statusBar1.Text = "Starting Threads";
StartThreads();

이 코드는 상태 표시줄을 업데이트하고 StartThreads 메서드를 호출합니다. 이 코드에서 StopListening 단추의 StopListeningFlagTrue로 설정하기만 하면 됩니다.

// C#
StopListeningFlag = true;

마지막 단계로 StopListeningFlag에 대해 폼 수준 변수를 추가합니다. 폼 코드 맨 위에 다음 줄을 추가합니다.

// C#
private bool StopListeningFlag = false;

응용 프로그램을 테스트하려면 메시지 대기열에 쓰기 위한 예제 응용 프로그램인 MQWrite를 다운로드합니다.

다중 스레드 코드의 문제

샘플 코드 작업을 완료했으므로, 이제 다중 스레드 응용 프로그램을 작성하는 데 필요한 도구를 가지게 되었습니다. 스레딩은 응용 프로그램의 성능과 확장성을 극적으로 개선할 수 있습니다. 이런 강력함과 더불어 스레딩의 위험에 대해서도 알고 있어야 합니다. 어떤 경우에는 스레드 사용으로 응용 프로그램에 해를 끼칠 수 있습니다. 스레드로 인해 작업이 다운되거나 예상치 못한 결과가 일어날 수 있으며 심지어 응용 프로그램이 응답을 중지할 수도 있습니다.

스레드가 여러 개인 경우 스레드 서로가 특정 지점에 도달하거나 종료할 때까지 대기하고 있지 않은지 확인합니다. 제대로 수행하지 않으면 각 스레드가 서로 대기하고 있으므로 아무 스레드도 종료되지 않는 교착 상태를 초래할 수 있습니다.

여러 스레드에서 쉽게 공유될 수 없는 리소스(예: 플로피 디스크 드라이브, 직렬 포트 또는 적외선 포트)에 액세스해야 하는 경우 스레드 사용을 방지하거나 synclock 또는 mutex와 같은 고급 스레딩 도구를 사용하여 동시성을 관리할 수 있습니다. 두 스레드가 이 리소스 중 하나를 동시에 액세스하려 하면 한 스레드에서는 리소스를 얻을 수 없고 데이터 손상이 일어납니다.

스레딩의 또 다른 일반적인 문제는 경쟁 조건입니다. 한 스레드가 파일에 데이터를 쓰는 동안 다른 스레드에서 해당 파일을 읽고 있는 경우 어떤 스레드가 먼저 종료할지 알 수 없습니다. 이 문제는 두 스레드가 파일 끝으로 경주하고 있기 때문에 경쟁 조건이라고 합니다. 읽는 스레드가 쓰는 스레드보다 앞서는 경우 알 수 없는 결과가 반환됩니다.

스레드를 사용할 때 모든 스레드가 다른 스레드와 별도로 완전히 작업을 마칠 수 있을지 여부도 생각해 보아야 합니다. 데이터를 앞뒤로 전달해야 하는 경우 데이터가 비교적 간단해야 합니다. 복잡한 개체를 전달하는 경우 이 개체를 앞뒤로 이동하기 위해 막대한 마샬링 비용이 들어가기 시작합니다. 이에 따라 운영 체제에서 관리하는 데 오버헤드가 생기고 전체 성능이 떨어집니다.

또 다른 문제로는 코드를 다른 개발자에게 넘겨주는 데 따른 전환 비용이 있습니다. .NET으로 스레딩이 훨씬 쉬워졌지만 코드를 유지 관리하는 다음 개발자가 스레딩 작업을 하기 위해서는 스레딩에 대해 알고 있어야 합니다. 그러나 이 점은 스레드 사용을 피해야 할 이유라기 보다는 적절한 코드 주석을 제공해야 할 이유입니다.

이런 문제들로 인해 스레딩 자체를 사용하지 않는 것 보다는 응용 프로그램을 디자인하고 스레드를 사용할지 여부를 결정할 때 모든 문제들을 기억하고 있는 것이 좋습니다. 불행히도 이 백서에서는 이런 문제를 방지하기 위한 방법을 설명하지 않습니다. 스레드를 사용하기로 했으나 위에서 언급한 문제가 발생한 경우 synclock이나 mutex를 검토하여 문제를 해결하거나 다른 솔루션을 찾아 보십시오.

결론

여기에 있는 내용으로 스레딩을 이용하는 응용 프로그램을 작성할 수 있습니다. 그러나 이렇게 하는 동안 관련된 문제를 기억하십시오. 스레딩은 제대로 사용하면 응용 프로그램의 성능과 확장성을 단일 스레드 응용 프로그램에 비해 훨씬 개선할 수 있지만, 올바로 사용하지 못하는 경우 정반대의 결과를 가져올 수 있으며 응용 프로그램이 불안정하게 될 수 있습니다.


출처: MSDN
Posted by SB패밀리

C# 프로그래머 참조  

문서 주석에 대한 권장 태그

http://msdn.microsoft.com/library/kor/default.asp?url=/library/kor/csref/html/vclrftagsfordocumentationcomments.asp

 

C# 컴파일러는 코드의 문서 주석을 XML 파일로 만듭니다. XML 파일을 처리하여 문서를 만드는 작업은 사용자의 사이트에서 구현해야 하는 세부적인 사항입니다.

태그는 형식, 형식 멤버 등과 같은 코드 구문에서 처리됩니다.

참고   태그는 네임스페이스에서 처리되지 않습니다.

컴파일러는 유효한 XML 태그를 모두 처리합니다. 아래 태그에는 사용자 문서에서 자주 사용하는 기능이 포함되어 있습니다.

1. 컴파일러는 구문을 검증합니다.

참고 항목

/doc(문서 주석 처리) | XML 문서

Posted by SB패밀리

C# 프로그래머 참조  

<c>

<c>text</c>

다음은 각 문자에 대한 설명입니다.

text
코드로 나타낼 텍스트입니다.

설명

<c> 태그는 설명에 있는 텍스트를 코드로 표시하는 데 사용합니다. 여러 줄을 코드로 표시하려면 <code>를 사용합니다.

/doc로 컴파일하여 문서 주석을 파일로 저장합니다.

예제

// xml_c_tag.cs
// compile with: /doc:xml_c_tag.xml

/// text for class MyClass
public class MyClass 
{
   /// <summary><c>MyMethod</c> is a method in the <c>MyClass</c> class.
   /// </summary>
   public static void MyMethod(int Int1) 
   {
   }
   /// text for Main
   public static void Main () 
   {
   }
}

참고 항목

문서 주석에 대한 권장 태그

Posted by SB패밀리

C# 프로그래머 참조  

<code>

<code>content</code>

다음은 각 문자에 대한 설명입니다.

content
코드로 표시할 텍스트입니다.

설명

<code> 태그는 여러 줄을 코드로 표시하는 데 사용합니다. <c> 태그는 설명에 있는 텍스트를 코드로 표시하는 데 사용합니다.

/doc로 컴파일하여 문서 주석을 파일로 저장합니다.

예제

<code> 태그의 사용 방법을 보여 주는 예제는 <example> 항목을 참조하십시오.

참고 항목

문서 주석에 대한 권장 태그

Posted by SB패밀리

C# 프로그래머 참조  

<example>

<example>description</example>

다음은 각 문자에 대한 설명입니다.

description
코드 예제에 대한 설명입니다.

설명

<example> 태그를 사용하면 메서드나 기타 라이브러리 멤버의 사용 방법에 대한 예제를 지정할 수 있습니다. 대개 이 태그는 <code> 태그와 함께 사용합니다.

/doc로 컴파일하여 문서 주석을 파일로 저장합니다.

예제

// xml_example_tag.cs
// compile with: /doc:xml_ctag.xml

/// text for class MyClass
public class MyClass 
{
   /// <summary>
   /// The GetZero method.
   /// </summary>
   /// <example> This sample shows how to call the GetZero method.
   /// <code>
   ///   class MyClass 
   ///   {
   ///      public static int Main() 
   ///      {
   ///         return GetZero();
   ///      }
   ///   }
   /// </code>
   /// </example>
   public static int GetZero() 
   {
      return 0;
   }
   /// text for Main
   public static void Main () 
   {
   }
}

참고 항목

문서 주석에 대한 권장 태그

Posted by SB패밀리

C# 프로그래머 참조  

<exception>

<exception cref="member">description</exception>

다음은 각 문자에 대한 설명입니다.

cref = "member"
현재 컴파일 환경에 있는 예외에 대한 참조. 컴파일러에서는 지정된 예외가 존재하는지를 확인하고 member를 출력 XML의 정식 요소 이름으로 변환합니다. member는 큰따옴표(" ")로 묶어야 합니다.
description
설명.

설명

throw할 수 있는 예외를 <exception> 태그에 지정합니다. 이 태그는 메서드 정의에 적용됩니다.

/doc로 컴파일하여 문서 주석을 파일로 저장합니다.

예제

// xml_exception_tag.cs
// compile with: /doc:xml_exception_tag.xml
using System;

/// comment for class
public class EClass : Exception 
{
   // class definition ...
}

/// <exception cref="System.Exception">Thrown when... .</exception>
class TestClass 
{
   public static void Main() 
   {
      try 
      {
      }
      catch(EClass) 
      {
      }
   }
}

참고 항목

문서 주석에 대한 권장 태그

Posted by SB패밀리

C# 프로그래머 참조  

<include>

<include file='filename' path='tagpath[@name="id"]' />

다음은 각 문자에 대한 설명입니다.

filename
문서를 포함할 파일 이름입니다. 파일 이름은 path로 한정될 수 있습니다. filename은 작은따옴표(' ')로 묶습니다.
tagpath
태그의 name을 찾을 수 있는 filename의 태그 경로입니다. path는 작은따옴표(' ')로 묶습니다.
name
주석 앞에 오는 태그의 이름 지정자입니다. name에는 id가 있어야 합니다.
id
주석 앞에 오는 태그의 ID입니다. ID는 큰따옴표(" ")로 묶습니다.

설명

<include> 태그를 사용하면 소스 코드의 형식과 멤버를 설명하는 다른 파일의 주석을 참조할 수 있습니다. 이렇게 하면 소스 코드 파일에 직접 문서 주석을 배치하지 않아도 됩니다.

<include> 태그는 XML XPath 구문을 사용합니다. <include>의 용도를 변경하는 방법은 XPath 문서를 참조하십시오.

예제

아래 예제는 여러 개의 파일로 구성됩니다. <include>를 사용하는 첫째 파일은 아래와 같습니다.

// xml_include_tag.cs
// compile with: /doc:xml_include_tag.xml
/// <include file='xml_include_tag.doc' path='MyDocs/MyMembers[@name="test"]/*' />
class Test
{
   public static void Main()
   {
   }
}

/// <include file='xml_include_tag.doc' path='MyDocs/MyMembers[@name="test2"]/*' />
class Test2
{
   public void Test()
   {
   }
}

두 번째 파일 xml_include_tag.doc에는 다음 문서 주석이 있습니다.

<MyDocs>

<MyMembers name="test">
<summary>
The summary for this type.
</summary>
</MyMembers>

<MyMembers name="test2">
<summary>
The summary for this other type.
</summary>
</MyMembers>

</MyDocs>

프로그램 출력

<?xml version="1.0"?>
<doc>
    <assembly>
        <name>t2</name>
    </assembly>
    <members>
        <member name="T:Test">
            <summary>
The summary for this type.
</summary>
        </member>
        <member name="T:Test2">
            <summary>
The summary for this other type.
</summary>
        </member>
    </members>
</doc>

참고 항목

문서 주석에 대한 권장 태그

Posted by SB패밀리

C# 프로그래머 참조  

<list>

<list type="bullet" | "number" | "table">
   <listheader>
      <term>term</term>
      <description>description</description>
   </listheader>
   <item>
      <term>term</term>
      <description>description</description>
   </item>
</list>

다음은 각 문자에 대한 설명입니다.

term
text로 정의할 용어입니다.
description
글머리 목록이나 번호 매기기의 항목 또는 term의 정의입니다.

설명

<listheader> 블록은 테이블이나 정의 목록의 머리글 행을 정의하는 데 사용됩니다. 테이블을 정의할 때는 머리글의 term에 대한 엔트리만 제공하면 됩니다.

목록의 각 항목은 <item> 블록으로 지정합니다. 정의 목록을 만들 때는 termtext를 모두 지정해야 합니다. 그러나 테이블, 글머리 목록 또는 번호 매기기의 경우에는 text의 엔트리만 제공하면 됩니다.

목록이나 테이블에 사용할 수 있는 <item> 블록의 수에는 제한이 없습니다.

/doc로 컴파일하여 문서 주석을 파일로 저장합니다.

예제

// xml_list_tag.cs
// compile with: /doc:xml_list_tag.xml 

/// text for class MyClass
public class MyClass 
{
   /// <remarks>Here is an example of a bulleted list:
   /// <list type="bullet">
   /// <item>
   /// <description>Item 1.</description>
   /// </item>
   /// <item>
   /// <description>Item 2.</description>
   /// </item>
   /// </list>
   /// </remarks>
   public static void Main ()
   {
   }
}

참고 항목

문서 주석에 대한 권장 태그

Posted by SB패밀리

C# 프로그래머 참조  

<para>

<para>content</para>

다음은 각 문자에 대한 설명입니다.

content
단락 텍스트입니다.

설명

<para> 태그를 <summary>, <remarks> 또는 <returns> 같은 태그 내에서 사용하여 텍스트에 구문을 추가할 수 있습니다.

/doc로 컴파일하여 문서 주석을 파일로 저장합니다.

예제

<para> 사용 예제는 <summary>를 참조하십시오.

참고 항목

문서 주석에 대한 권장 태그

Posted by SB패밀리

C# 프로그래머 참조  

<param>

<param name='name'>description</param>

다음은 각 문자에 대한 설명입니다.

name
메서드 매개 변수의 이름입니다. name은 작은따옴표(' ')로 묶습니다.
description
매개 변수에 대한 설명입니다.

설명

메서드의 매개 변수 중 하나를 설명하려면 메서드 선언의 주석에서 <param> 태그를 사용해야 합니다.

<param> 태그의 텍스트는 IntelliSense, 개체 브라우저코드 주석 웹 보고서에 표시됩니다.

/doc로 컴파일하여 문서 주석을 파일로 저장합니다.

예제

// xml_param_tag.cs
// compile with: /doc:xml_param_tag.xml 

/// text for class MyClass
public class MyClass 
{
   /// <param name="Int1">Used to indicate status.</param>
   public static void MyMethod(int Int1) 
   {
   }
   /// text for Main
   public static void Main () 
   {
   }
}

참고 항목

문서 주석에 대한 권장 태그

Posted by SB패밀리

C# 프로그래머 참조  

<paramref>

<paramref name="name"/>

다음은 각 문자에 대한 설명입니다.

name
참조할 매개 변수의 이름입니다. name은 큰따옴표(" ")로 묶습니다.

설명

<paramref> 태그를 사용하면 특정 단어가 매개 변수임을 나타낼 수 있습니다. 이제 XML 파일을 처리하여 이 매개 변수를 다른 방식으로 서식화할 수 있습니다.

/doc로 컴파일하여 문서 주석을 파일로 저장합니다.

예제

// xml_paramref_tag.cs
// compile with: /doc:xml_paramref_tag.xml 
/// text for class MyClass
public class MyClass
{
   /// <remarks>MyMethod is a method in the MyClass class.  
   /// The <paramref name="Int1"/> parameter takes a number.
   /// </remarks>
   public static void MyMethod(int Int1)
   {
   }

   /// text for Main
   public static void Main ()
   {
   }
}

참고 항목

문서 주석에 대한 권장 태그

Posted by SB패밀리

C# 프로그래머 참조  

<permission>

<permission cref="member">description</permission>

다음은 각 문자에 대한 설명입니다.

cref = "member"
현재 컴파일 환경에서 호출될 수 있는 멤버 또는 필드에 대한 참조입니다. 컴파일러는 지정된 코드 요소가 존재하고 출력 XML에서 member를 정식 요소 이름으로 변환할 수 있는지 확인합니다. member는 큰따옴표(" ")로 묶어야 합니다.
description
멤버 액세스에 대한 설명입니다.

설명

<permission> 태그를 사용하면 멤버 액세스를 문서화할 수 있습니다. System.Security.PermissionSet을 사용하여 멤버에 대한 액세스를 지정할 수 있습니다.

/doc로 컴파일하여 문서 주석을 파일로 저장합니다.

예제

// xml_permission_tag.cs
// compile with: /doc:xml_permission_tag.xml 
using System;
class TestClass
{
   /// <permission cref="System.Security.PermissionSet">Everyone can access this method.</permission>
   public static void Test()
   {
   }
   public static void Main()
   {
   }
}

참고 항목

문서 주석에 대한 권장 태그

Posted by SB패밀리