Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Sunday, November 11, 2018

C# Delegate/Event 정리

Delegate/Event
C#은 Java의 interface callback을 쉽게 하기 위한 방법으로 delegate/event를 제공한다.

Delegate (위임, 대리자)
Delegate는 C의 함수포인터와 같은 방식으로 함수를 저장했다가 파라미터로 전달 또는 호출할수 있는 객체이다.

using System;

namespace Delegate
{
    class MainClass
    {
        public delegate void Message(string msg);

        public void Hello(string msg)
        {
            Console.WriteLine("Hello "+msg);  
        }

        public void Run()
        {
            Message message = new Message(Hello);
            message("Delegate!");
        }

        public static void Main(string[] args)
        {
            MainClass mainClass = new MainClass();
            mainClass.Run();
        }
    }
}

C++의 함수 포인터와의 차이점
클래스를 사용하는 C++에는 Pointer to member function이 있는데, 이는 한 클래스의 멤버 함수에 대한 포인터로서 ‘객체’에 대한 컨텍스트를 가지고 있다는 점에서 C#의 delegate와 비슷하다.
단, C#의 delegate는 메서드 Prototype이 같다면 어느 클래스의 메서드도 쉽게 할당할 수 있는데 반해, C++의 Pointer to member는 함수 포인터 선언시 특정 클래스를 지정해주기 때문에 한 클래스에 대해서만 사용할 수 있다.
두번째로 C의 함수 포인터는 하나의 함수 포인터를 갖는데 반해, C# delegate는 하나 이상의 메서드 레퍼런스들을 가질 수 있어서 Multicast가 가능하다.
또한 C의 함수포인터는 Type Safety를 완전히 보장하지 않는 반면, C#의 delegate는 엄격하게 Type Safety를 보장한다.

Event
특별한 형태의 delegate 즉 C# event를 사용할 수 있다. C# event는 할당연산자(=)를 사용할 수 없으며, 오직 이벤트 추가(+= 연산자, Subscribe) 혹은 기존 이벤트 삭제 (-= 연산자, Unsubscribe) 만을 할 수 있다. 또한 delegate 와는 달리 해당 클래스 외부에서는 직접 호출할 수 없다.

using System;

namespace Delegate
{
    class MessageClass
    {
        public delegate void Message(string msg);
        public Message myMessage;
        public event Message myEvent;

        public void Hello(string msg)
        {
            Console.WriteLine("Hello " + msg);
        }

        public void Run()
        {
            Message message = new Message(Hello);
            message("Delegate!");
        }

        public void RunEvent()
        {
            myEvent("RunEvent!");
        }
    }

    class MainClass
    {
        public static void Main(string[] args)
        {
            MessageClass mainClass = new MessageClass();
            mainClass.myMessage = mainClass.Hello;
            mainClass.myMessage("External!");

            mainClass.myEvent += mainClass.Hello;

            // event는 클래스 외부에서 실행할수 없음
            //mainClass.myEvent("Event");
            mainClass.RunEvent();
        }
    }
}

Wednesday, November 18, 2015

C# 서버개발 관련 마영전 정리

마영전 서버가 C#으로 개발되었습니다.

마영전 서버 세션 정리
http://www.scribd.com/doc/57921356/ndc2011-%EB%A7%88-%EB%B9%84-%EB%85%B8-%EA%B8%B0-%EC%98%81-%EC%9B%85-%EC%A0%84-%EC%84%9C-%EB%B2%84-%EA%B4%80-%EB%A0%A8-%EC%84%B8-%EC%85%98-%EC%A0%95-%EB%A6%AC

C#으로 게임 서버를 개발 할 경우 성능에 대한 글
http://rosagigantea.tistory.com/408

NDC 참관기: 마비노기 영웅전 자이언트 서버의 비밀
https://rein.kr/blog/archives/2671

게임코디 쓰레드
http://www.gamecodi.com/board/zboard.php?id=GAMECODI_Talkdev&no=1792

Friday, June 19, 2015

Debugging Managed C++ (If the breakpoint is not hit)

When linking C# and Managed C++, there are times when a breakpoint is set in C# but not in Managed C++ alone.

In that case, follow these two procedures:
1. In the Managed C++ properties window, set Debugging - Debugger Type to Mixed.

2. In Visual Studio options, check Debugging - Use Managed Compatibility Mode.

Sunday, May 3, 2015

C# WPF Arc 타입을 못찾을 경우

다음과 같이 XAML 상부에 네임스페이스를 정의를 했지만 'Arc'타입을 찾지 못하는 경우가 있다.

네임스페이스 정의:
xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing" x:Name="MainControl"

Arc를 찾지 못한다는 메세지:
The tag 'Arc' does not exist in XML namespace 'http://schemas.microsoft.com/expression/2010/drawing'. Line 11 Position 4.
Done building project "TextBinding.csproj" -- FAILED.

그럴 경우에는 Microsoft Blend4를 설치하고 프로젝트에 다음과 같은 레퍼런스를 추가하여야 한다:
'C:\Program Files (x86)\Microsoft SDKs\Expression\Blend\Silverlight\v4.0\Libraries\Microsoft.Expression.Drawing.dll'

C# 파일 읽기 유니코드 문제

// 파일을 읽을때 유니코드 문제를 드디어 해결했다.
// 문제는 Encoding parameter부분이 default parameter가 Encoding.Default가 아니라는 점이다. 따라서 명시적으로 Default Encoding이라고 해주어야 함

FileStream fs = new FileStream(fn, FileMode.Open, FileAccess.Read);
StreamReader sr = new StreamReader(fs, Encoding.Default);
string s = sr.ReadLine();

Sunday, April 19, 2015

C# 쓰레드 생성시 폼이 종료되지 않는 문제

만약에 C# Form에서 쓰레드를 생성한 후, Form Close가 되었는데 프로그램이 종료되지 않는다면, 다음과 같이 IsBackgound를 true로 설정하면 된다.

Thread t = new Thread(myAction);
t.IsBackground = true;
t.Start();

Friday, April 10, 2015

C# WPF XAML 로딩 에러

Visual Studio 2010에서 원격지에 있는 WPF소스로 작업을 하다 보면 분명히 소스가 컴파일은 되는데 XAML 창에서는 컴파일 에러라고 나오는 경우가 있다.

이 경우는 Visual Studio 2010에서 보안 문제로 인하여 WPF원격지 컨트롤들을 기본적으로 로딩하지 않아서 생기는 문제이다. 다음과 같이 수정하면 해결이 가능하다.

1.다음파일을 연다.
C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe.config

2.다음과 같이 XML 엘리먼트를 추가한다.
<?xml version ="1.0"?>
<configuration>
    <runtime>
 <loadFromRemoteSources enabled="true"/>
    </runtime>
</configuration>

3.Visual Studio 2010을 새로연다.

Monday, April 6, 2015

C# PasrseHTML로 HTML 파싱하기

ParseHTML이라는 외부 라이브러리로 HTML을 파싱해보자.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HTML;
using System.IO;

namespace ParseHTMLTester
{
    class Program
    {
        static void Main(string[] args)
        {
            StreamReader reader = new StreamReader("1.txt");// html을 1.txt로 저장해 놓음
            HTML.ParseHTML parse = new HTML.ParseHTML();

            // 스트림 리터에서 파일 전체를 string으로 변경
            string data = reader.ReadToEnd();
            parse.Source = data;

            while (!parse.Eof())
            {
                char ch = parse.Parse();
                if (ch == 0)
                {
                    AttributeList tag = parse.GetTag();
                    if (tag.Name == "th")
                    {
                        // th일 경우 class의 값을 프린트
                        if (tag["class"] != null)
                        {
                            Console.WriteLine("th class=" + tag["class"].Value);
                        }
                    }
                    else
                    {
                        // 일반 태그는 그냥 프린트
                        Console.WriteLine(tag.Name);
                    }
                }
            }
        }
    }
}

다운로드

C# 디버그 메세지 출력하기

C#에서 OutputDebugString을 할려면 다음과 같은 2가지 방법이 있다.

Debug.Write(), Trace.Write()의 차이점은 Debug는 Debug모드 빌드에서만 동작하며, Trace는 Release/Debug 둘다 동작한다는 점이다. 물론 OutputDebugString기반이므로 DebugView에서도 확인할 수 있다.

System.Diagnostics.Debug.Write("Debug1");
System.Diagnostics.Debug.Write("Debug2");
System.Diagnostics.Trace.Write("Trace1");
System.Diagnostics.Trace.Write("Trace2");

Friday, April 3, 2015

C# UDP Server/Client 예제

//Server
System.Net.Sockets.UdpClient udpClient = new System.Net.Sockets.UdpClient("127.0.0.1", 5555);
String cmd = "dump";
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[] dgrams = encoding.GetBytes(cmd);
udpClient.Send(dgrams, dgrams.Length);
udpClient.Close();

//Client
static private UdpClient udpServer;
static private byte[] data;
static private IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 5555);
static private IPEndPoint server = new IPEndPoint(IPAddress.Any, 0);
static private void ThreadProc()
{
    while (true)
    {
        data = udpServer.Receive(ref server);
        string s = Encoding.Default.GetString(data);
        Console.WriteLine(s);
    }
}
private void Form1_Load(object sender, EventArgs e)
{
    ipep = new IPEndPoint(IPAddress.Any, 5555);
    server = new IPEndPoint(IPAddress.Any, 0);
    udpServer = new UdpClient(ipep);
    data = new byte[1024];
    Thread thread = new Thread(new ThreadStart(ThreadProc));
    thread.Start();
    Console.WriteLine("Thread started");
}


C# BMP 파일 읽기

public class BmpLoader
{
    public struct BMPHeader
    {
        public short type;
        public int size;
        public short reserved1;
        public short reserved2;
        public int offset;
    }
    public struct BMPInfoHeader
    {
        public int size;
        public int width;
        public int height;
        public short planes;
        public short bitsPerPixel;
        public uint compression;
        public uint imageSize;
        public int xPelsPerMeter;
        public int yPelsPerMeter;
        public int clrUsed;
        public int clrImportant;
    }

    private BMPHeader header;
    private BMPInfoHeader infoHeader;
    public byte[] Load(string filename, out int width, out int height)
    {
        BinaryReader reader = new BinaryReader(File.OpenRead(filename));
        header.type = reader.ReadInt16();
        header.size = reader.ReadInt32();
        header.reserved1 = reader.ReadInt16();
        header.reserved2 = reader.ReadInt16();
        header.offset = reader.ReadInt32();
        infoHeader.size = reader.ReadInt32();
        infoHeader.width = reader.ReadInt32();
        infoHeader.height = reader.ReadInt32();
        infoHeader.planes = reader.ReadInt16();
        infoHeader.bitsPerPixel = reader.ReadInt16();
        infoHeader.compression = reader.ReadUInt32();
        infoHeader.compression = reader.ReadUInt32();
        infoHeader.xPelsPerMeter = reader.ReadInt32();
        infoHeader.yPelsPerMeter = reader.ReadInt32();
        infoHeader.clrUsed = reader.ReadInt32();
        infoHeader.clrImportant = reader.ReadInt32();
        int size = infoHeader.width * infoHeader.height * (infoHeader.bitsPerPixel / 8);
        byte[] pixels = reader.ReadBytes(size);
        width = infoHeader.width;
        height = infoHeader.height;
        return pixels;
    }
}

C# 콜스택 보기

    StackTrace stackTrace = new StackTrace();           // get call stack
    StackFrame[] stackFrames = stackTrace.GetFrames();  // get method calls (frames)
    // write call stack method names
    foreach (StackFrame stackFrame in stackFrames)
    {
     System.Reflection.MethodBase method = stackFrame.GetMethod();
     String strFrame = method.Name + " " + method.Module + " " + method.DeclaringType;
     Console.WriteLine(strFrame);   // write method name
    }


C# 참조된 모든 어셈블리 보기

using System;
using System.Reflection;
using System.Collections;
public class DependencyReporter
{
    static void Main(string[] args)
    {
        try
        {
            if (args.Length == 0)
            {
                Console.WriteLine
                ("Usage: DependencyReporter <assembly1> [assembly2 ...]");
            }
            Hashtable alreadyLoaded = new Hashtable();
            foreach (string name in args)
            {
                Assembly assm = Assembly.LoadFrom(name);
                DumpAssembly(assm, alreadyLoaded, 0);
            }
        }
        catch (Exception e)
        {
            Console.WriteLine("Error: {0}", e.Message);
        }
    }
    static void DumpAssembly(Assembly assm, Hashtable alreadyLoaded,
    int indent)
    {
        Console.Write(new String(' ', indent));
        AssemblyName fqn = assm.GetName();
        if (alreadyLoaded.Contains(fqn.FullName))
        {
            Console.WriteLine("[{0}]", fqn.Name);
            return;
        }
        alreadyLoaded[fqn.FullName] = fqn.FullName;
        Console.WriteLine(fqn.Name);
        foreach (AssemblyName name in assm.GetReferencedAssemblies())
        {
            Assembly referenced = Assembly.Load(name);
            DumpAssembly(referenced, alreadyLoaded, indent + 2);
        }
    }
}

C# HTTP POST 요청하기

Thursday, April 2, 2015

C# PNG 이미지 확대 에러

PNG이미지를 Image 포맷으로 읽을경우 자체적으로 생성한 Bitmap과 Resolution이 달라서 이미지 복사할 경우에 의도치 않은 이미지 확대가 일어나는 경우가 있다.

다음은 그러한 경우이다.
아래와 같이 똑같은 크기로 이미지를 생성하고 복사를 하여도 이미지는 확대가 되어 복사가 된다.
            Image image = ToolManager.rawRenderer_.pictureBoxRaw.Image;
            Bitmap frameBitmap = new Bitmap(image.Width, image.Height);
            Graphics g = Graphics.FromImage(frameBitmap);
            g.Clear(Color.White);
            g.DrawImage(image, 0, 0, new Rectangle(0, 0, image.Width, image.Height), GraphicsUnit.Pixel);

이유를 살펴보았더니 VerticalResolution, HorizontalResolution이 image의 값과 frameBitmap의 값이 서로 75, 96으로 달라서 발생했다. 이는 PNG이미지의 경우 resolution이 75인 파일도 있고 96인 파일도  있어서 그렇다.

그래서 아래와 같이 resolution을 frameBitmap쪽으로 통일을 시키면 DrawImage시 안전하게 확대가 일어나지 않고 복사할수 있다.
            Bitmap imageBitmap = image as Bitmap;
            imageBitmap.SetResolution(frameBitmap.HorizontalResolution, frameBitmap.VerticalResolution);


C# 프로세스별 CPU 사용률 구하기

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;
using System.Management;
using System.IO;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            GetProcesses();
        }
        public static void GetProcesses()
        {
            ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_PerfFormattedData_PerfProc_Process");

            StreamWriter SW;
            SW = File.CreateText("c:\\MyTextFile.txt");
            foreach (ManagementObject queryObj in searcher.Get())
            {
                SW.Write("Name: {0} ", queryObj["Name"]);
                SW.Write("ProcessID: {0} ", queryObj["IDProcess"]);
                SW.Write("Handles: {0} ", queryObj["HandleCount"]);
                SW.Write("Threads: {0} ", queryObj["ThreadCount"]);
                SW.Write("Memory: {0} ", queryObj["WorkingSetPrivate"]);
                SW.WriteLine("CPU%: {0}", queryObj["PercentProcessorTime"]);
            }
            SW.Close();

        }
    }
}

Tuesday, November 18, 2014

Sunday, November 2, 2014

C# Bitmap 픽셀 처리(읽기/쓰기)

C# Bitmap에서 SetPixel, GetPixel을 사용하게 되면 매우 느리게 된다.(전체 픽셀을 다룰 경우) 그럴경우 다음과 같이 픽셀 포인터를 얻어서 사용하면 매우 빠르기 픽셀 처리를 할수 있다. 이를 위해서는 unsafe옵션을 켜주어야 한다.

private Image _image = null;

// 비트맵 픽셀 처리
        private void Form1_Load(object sender, EventArgs e)
        {
            Bitmap bitmap = new Bitmap(100, 100);
            BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, 100, 100), ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            unsafe
            {
                byte* ptr = (byte* )bmpData.Scan0.ToPointer();
                for (int i = 0; i < bmpData.Height; i++)
                {
                    for (int j = 0; j < bmpData.Width; j++)
                    {
                        ptr[bmpData.Stride * i + 3 * j + 0] = 0;// B
                        ptr[bmpData.Stride * i + 3 * j + 1] = 0;// G
                        ptr[bmpData.Stride * i + 3 * j + 2] = 255;// R
                    }
                }
                bitmap.UnlockBits(bmpData);
            }
            _image = bitmap;
        }

// 비트맵 그리기
        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            if (_image != null)
            {
                g.DrawImage(_image, 0, 0, _image.Width * _imageScale, _image.Height * _imageScale);
            }
        }

Saturday, November 1, 2014

C# OutputDebugString 사용하기

C#에서 OutputDebugString이 안될때는 다음과 같이 [Project] - [Properties] - [Debug]탭에서 Enable native code debugging을 활성화 시키면 된다.
OutputDebugString을 Managed C++에서 써도 마찬가지 방법으로 활성화 시킨다.


C# C++ char* 문자열 전달하기

C++ 함수가 다음과 같은 것이 있고, MBCS 문자열 인코딩을 사용할 때
void encoding_test(const char* pstr);

다음과 같이 C#에서 작성하면 char* 형으로 문자열을 전달할 수 있다.

        unsafe private sbyte[] get_sbyte_string(string s)
        {
// 51949는 EUC-KR이다.
            byte[] b2 = Encoding.GetEncoding(51949).GetBytes(s);
            sbyte[] sb = (sbyte[])((Array)b2);
            for (int i = 0; i < sb.Length; i++)
            {
                Console.WriteLine(sb[i]);
            }
            return sb;
        }

            string s = "하이";
            unsafe
            {
                fixed (sbyte* psb = get_sbyte_string(s))
                {
                    encoding_test(psb);
                }
            }