2020년 8월 12일 수요일

[C#, Win10] UIPI 뚫기

요즘 Window10에서 게임을 실행시키면 죄다 관리자 권한으로 실행되는데

Window10에서 생긴 UIPI를 활용하기 위함입니다.


UIPI란 낮은 권한의 프로그램이 높은 권한의 프로그램에 메시지를 보내거나

후킹하는 것을 못하도록 막는 보안체계입니다.


떄문에 이것을 고려하지 않고 매크로를 만들면 게임 밖에서의 테스트는 성공하지만

막상 게임을 켜고 테스트해보면 먹통이 되어버리죠.


하지만 당연하게도 이를 뚫는 방법이 있습니다.


제가 처음 해결방법을 발견한 글은

https://stackoverflow.com/questions/17645204/sendinput-fail-because-of-uipi

에 있습니다

저는 요약해서만 적어놓을테니 자세히 보려면 링크의 글을 참조해주세요


뚫는 방법

1. 인증서 생성


Visual Studio 개발자 CMD를 켠 후에

>makecert -r -pe -n "CN=Test Certificate - For Internal Use Only" -ss PrivateCertStore testcert.cer

>certmgr.exe -add testcert.cer -s -r localMachine root

>CertMgr.exe /add testcert.cer /s /r localMachine trustedpublisher

을 입력해서 인증서를 생성합니다.

2. 프로그램 매니페스트 생성



위 링크의 파일을 그대로 추가하거나 직접 만들어서 적어도 됩니다.











3. 프로그램을 생성한 인증서로 서명시키기


Visual Studio 개발자 CMD에서

SignTool sign /v /s PrivateCertStore /n "Test Certificate - For Internal Use Only" /t http://timestamp.verisign.com/scripts/timestamp.dll "파일경로"

를 입력하여 서명한다

4. 프로그램을 관리자 권한으로 실행시킨다


Done

2020년 8월 10일 월요일

[C#, WPF] 패스 오브 엑자일(Path of Exile)용 포션 매크로(Potion Macro)

 



사용법은 알아서 잘 하실 수 있으리라 믿어요!

절대 적기 귀찮아서 안적는거 아니니깐요




소스코드도 올리드리니 보고 싶으신 분들은 맘껏 봐주세요 >ㅅ<


p.s. 제가 쓰려고 해보니 안되더라구요. 그 원인은 UIPI란 것 때문인데
      그걸 깜빡했지 뭐에요 데헷.

2019년 7월 8일 월요일

자막 이름을 한꺼번에 변경하기 위한 프로그램

파일 : https://www.dropbox.com/s/wgxwjrt0afomjts/FileNameChanger_Binary.zip?dl=0

소스 : https://www.dropbox.com/s/9dhl0jiwfuziuf3/FileNameChanger_Source.zip?dl=0


드래그 드랍으로 폴더나 파일들을 넣고 "To Video Name" 버튼을 클릭하면 됩니다

2019년 6월 14일 금요일

[잡담] 접은 것이 후회되지 않는 로스트아크

로스트아크를 오픈베타 첫날부터 하루도 안빠지고 했었어요

처음에는 라이트 유저로써만 할 생각이었는데

길드가 커지고 길드전이나 각종 컨텐츠를 같이 즐길 유저가 필요해져서

템랩 530까지 찍었었네요


로스트아크를 하면서 좋은 기억보다는 나쁜 기억만 많이 남은 것 같아요

그런 기억들을 몇가지 풀어놓으려구요


물론 지금까지의 패치 내역을 보니 제가 겪었던 문제들이 고쳐지곤 있지만

전 어디까지나 패치 전에 직접 겪으며 고통받았으니 옹호해주고 싶지는 않아요


우선 룬 시스템이 극악이에요

끊임없이 교체를 요구하면서도 입수도 힘들고 교체도 힘들어요

증폭 룬슬롯을 만드는데에 몇백만 실링이 들어서 몇주간 실링 노가다만 하게 되구요

원래 부캐 안키울 생각이었는데 골드와 실링이 극악으로 부족해서

부캐 2개까지 포함해 3개의 캐릭터로 골드와 실링을 벌었었어요

당연히 재미없는 노가다였을뿐이에요

어쩌면 재미없다고 징징거릴게 아니라 지금처럼 편하게 접는게 현명한 판단이었겠네요


둘째로는 확률이 극악이에요

게임을 하면서 운영진에서 확률을 조작한다는 느낌을 피할 수가 없어요

실제로도 그런 일이 있었지만 한두번이면 모를까 매일 플레이하면서 느낄 수 있는 수준이에요

주로 플레티넘 필드에서 특정 수확물의 체감 입수량이 이상하리만치 극과 극을 오가요

실링 폭발에 경우 1%의 확률로 발동하는데 가챠보다 더 극악인 느낌이 들어요

1%면 100번 시도해서 60%정도로 한번은 성공하는데

한시간 몹을 계속 잡아도 한번뜨는거 보기도 힘들어요


셋째로는 돈의 수급 통제가 극악이에요

위에도 설명했지만 실링폭발이라는 실링 수급을 할 수 있어보이는 각인이 있지만

실제로 극악의 발동확률이라 쓸모도 없어요

실링을 얻을 수 있는 경로는 극히 제한되어있고

가장 쉬운 방법은 골드를 실리으로 바꾸는 것이에요

세상을 구한 용사인데, 루테란의 세대교체를 성공시킨 공신이고

토토이크에서 해적들의 음모를 저지시키고

애니츠에서 우승 및 악마측의 음모를 저지시키고

아르데타인에서도 슈샤이어에서도 로헨델에서도 영웅이었는데

배타고 다닐 돈도 없어서 빌빌거려야해요

이유는 뻔하죠 영웅인것은 스토리 설정일 뿐이지

개발자는 플레이어를 개돼지로 보기때문이겠죠


넷째로는 얼토당토 않은 거짓말이에요

핵 앤 슬래시라 떵떵거리며 홍보했지만 전혀 그렇지 않아요

핵 앤 슬레시의 특징 중 하나는 쿨타임없이 자원이 허락하는 한 스킬을 난사할 수 있어요

마치 디아2에서 소서가 마나표션 빨면서 스킬쓰듯이요

그런데 로스트아크는 태생이 다르면서 억지로 주장하고

억지로 컨텐츠를 따라 만드니 재미가 하나도 없어요

디아3가 수면제라 불리지만 로스트아크의 미궁만큼 졸립진 않아요


다섯째로는 정해진 시간과 횟수의 제약이에요

뭘 하려고해도 시간에 맞춰야해서 족쇄가 되고

횟수가 정해져있어서 숙제처럼 매일 일정량 꼬박꼬박해야해요

디아3나 POE를 하면서 평일에 일끝나고

숙제 해야하는데 하고 스트레스받지 않았는데

로스트아크는 하루 빼먹으면 나중에 못하고 시간에 늦으면 못하고 하니

스트레스만 받았던 것 같아



정말 쓰면서 느끼지만 로스트아크는 쓰레기같은 게임이에요

여러 게임을 하면서 특히 온라인 게임 중에는

게임 자체는 훌륭한데 사람이 쓰레기라 게임이 재미없어지는 경우는 많이 봤는데

착한 사람들이랑 해도 구역질나서 접은 게임은 로스트아크가 처음이었던 것 같아요


패스 오브 엑자일이 한글화된다는 소식을 듣고

2달 전부터 했었는데 확실히 로스트아크보다 할만해요

적어도 내가 하고 싶은걸 골라서할 수도 하기 싫으면 안할수도 있어요

아이템을 먹으며 고민할 거리도 많고 새로운 세팅을 만들어내는 재미도 있어요

아마 다시는 돌아가지 않을 것 같아요

로스트아크는 해당 게임 장르에 맞는 사람들이 하면 되지

광고에 속은 사람들이 할만한 게임은 결코 아니에

2017년 9월 27일 수요일

[잡담] 마우스, 헤드셋의 유무선에 따른 차이점

예전에는 무선기기들의 사용 시간이 짧다고 들어서 무조건 유선으로 사용해왔는데

작년과 올해에 무선 헤드셋 및 이어폰과 마우스를 사용해보았습니다.

그 경험으로 느낀 장점과 단점에 대해서 써보려합니다.

장점

제가 이어폰과 헤드셋을 사용할때 못쓰게 되는 가장 큰 이유가 선에 손상때문이었습니다.

특히 헤드셋은 선의 길이가 긴 것이 많아서 문 손잡이같은 곳에 곧잘 걸리곤 했죠.

다른 곳은 멀쩡한데 선과 3.5mm잭을 잇는 부분이 뽑혀서 못쓰거나

선의 피복이 벗겨져서 점점 손상이 심해지는 일이 많았어요.

그런데 무선 제품을 사용해보니 처음부터 선이 없어서 이러한 문제로부터 완전히 자유로워지더군요.

덕분에 제가 구매한 무선 이어폰이나 헤드셋은 굉장히 오래쓰고 있습니다.


단점

위에 적은 장점이 있음에도 무선 제품들의 단점은 여전히 많은 단점을 가지고 있는데

우선 언제나 피할 수 없는 배터리의 문제가 있습니다.

무선 제품들이 대부분 경량화와 소형화가 중요한 경우가 많아서

자연스럽게 배터리를 넣을 공간도 적어지는거죠.

짧은 사용시간은 잦은 충전을 필요로하니 장시간 사용하는 사람은 불편할 수 밖에 없고

부득이하게 단시간 외부 사용을 위한 무선 제품과 장기간 사용을 위한 유선 제품을 둘 다 준비해둘 필요가 있어요.

또 반응 속도의 문제도 있는데, 일반적인 사용에서는 크게 다가오지 않지만

이어폰이라면 리듬게임에서, 마우스라면 FPS나 AOS게임에서

반응속도때문에 미묘하지만 굉장히 크게 불편하다는 것을 느낄 수 있어요.

지금까지는 핸드폰에서 무선 이어폰(헤드셋)을 사용하여 리듬게임을 할떄 25ms만큼 시간 차이가 나고,

(다만 요즘 리듬게임은 싱크조절로 커버칠 수 있으니 싱크만 잘 조절하면 어떻게 쓸 수 있어요)

마우스는 유선에 경우 보통 4~5ms만큼 차이나는데 무선은 17~25ms만큼 차이가 나더군요.

특히 마우스는 17ms의 반응속도를 유지하다가 25ms로 갑자기 늦어져서 심각하게 불편했어요.


결론

반응속도를 요하지 않는 일반 사용에서는 무선 제품도 충분히 사용할 수 있지만

반응속도가 중요해지는 게임에서는 평소에는 느낄 수 없던 큰 차이를 느낄 수 있으니

용도별로 구매해서 사용하거나 범용성이 높은 제품을 사용하는 것이 좋을 것 같네요.

p.s.

이 글을 쓸때는 무선 마우스의 건전지가 다해서 부득이하게 배터리가 다 없어지기 전에 조이스틱으로 마우스를 조작하는 프로그램을 만들어서 쓴 글이에요.
아래의 프로그램이 현재(읽는 당신에게는 과거) 사용하고 있는 프로그램입니다 ㅇㅅㅇ..
https://github.com/CodeGenerater/D3Controller/tree/master/StickToMouse
(사용하면서 느낀건데 버튼의 반응 딜레이를 1ms로 하면 제대로 작동을 안하고
5ms로 설정하니 제대로 작동하는걸 보니 괜히 마우스 반응 속도가 5ms가 아니군요)
마우스는 역시 유선이 좋은 것 같아요 8ㅅ8

2017년 8월 28일 월요일

[C#] 키보드 및 마우스 조작 완성편(Control Keyboard and Mouse)

https://github.com/CodeGenerater/MacroSolution/tree/master/HardwareControl


키보드 : System.Windows.Input.Key(WindowsBase.dll)를 사용하여 키를 누르거나 땔 수 있음

마우스 : System.Windows.Input.MouseButtons(PresentationCore.dll)를 사용하여 키를 누르거나 땔 수 있음
X버튼 및 휠(수평 휠은 테스트 안됨) 조작 가능.
마우스 커서 위치를 가져오거나 설정할 수 있음. (단 상대이동은 X)
(만약 상대이동을 원하시면 mouse_event(user32.dll)를 사용하여 하시면 되요. 실질적으로 필요없는 것 같아서 넣지 않았습니다)

공통 : 키가 눌려져있는지 알 수 있음

2017년 8월 1일 화요일

[C#, WCF] WCF를 활용한 간단한 로거 (Simple logger with WCF)



WCF를 사용하여 다른 컴퓨터와 통신하려면 IIS를 사용해야하지만

같은 컴퓨터 내에서 통신할때는 필요없는 점을 활용해서

로그 확인용 프로그램을 만들 수 있습니다



완성형이라 할 순 없지만 그럭저럭 쓸만합니다

p.s. 유니티엔진을 사용한 게임 모드를 제작할때 로그 기록용으로 써본 적이 있는데
     작동하지 않더군요

2017년 7월 30일 일요일

2017년 7월 24일 월요일

[C#, WPF] 방송용 채팅 위젯을 모니터에 직접 띄우는 프로그램


프로그램의 이름은 "ShowOnDesktop" 이라고 지었습니다.

원래 WPF에 있는 WebBrowser 컨트롤을 사용하여 만드려고 했는데

유감스럽게도 이 컨트롤은 IE의 구버전 브라우저이기 때문인지

스크립트 오류를 뿜으며 되지 않더군요.


그래서 닷넷을 위한 CEF(Chromium Embedded Framework)을 구해서

어찌저찌 만들어보았습니다.

※구글 드라이버와의 동기화문제 때문에 삭제되었었으나 일단 복구했습니다.
소스코드는 나중에 올리고 현재는 실행파일만 받을 수 있습니다.
소스코드 : https://drive.google.com/drive/folders/0B3EmLCf3GeuUaHJzTEt5cGZJSUk?usp=sharing (X)

실행파일 : https://drive.google.com/file/d/0B3EmLCf3GeuUWHFWSlQ3Q0pNSHM/view?usp=sharing (O)


유감스럽게도 프로젝트와 프로그램의 크기는 매우 작지만

CefSharp의 크기가 300MB에 달해서 쓸데없이 크기가 비대해졌군요.


궁금한 것이 있으시면 codegenerater@gmail.com 으로 문의해주세요

2017년 3월 12일 일요일

[C#] 다키스트 던전 장신구 디버프 제거 프로그램 (Darkest Dungeon Trinket Debuff Deletor)

소스 파일 (Source File)


실행 파일은 bin/Release/TrinketDebuffDeletor.exe 을 사용하세요

사용법 (How to)

게임 폴더 내의 base.entries.trinkets.json 파일을 드래그 드랍한 다음

Delete 버튼을 클릭하세요 (자동으로 백업을 생성합니다)

폴더는 \Steam\steamapps\common\DarkestDungeon\trinkets 으로 찾아가시면 됩니다



알림(2017.8.10)

광폭화의 부적 (Berserk Charm)에 경우 스트레스 15% 더 받는 효과가 사라지지 않는데

보통 다른 장신구에서 이러한 효과는 STRESSDMG라고 표기되어있지만

이 장신구는 STRESSDMG_BUFF라고 표기되어있습니다

즉, 디버프인데 버프라고 써있는 셈이죠

수정하는 방법은

\SteamLibrary\steamapps\common\DarkestDungeon\shared\buffs\base.buffs.json

파일에서 TRINKET_berserk_charm_STRESSDMG_BUFF를 찾은 다음

0.15 라고 되어있는 것을 -0.15 로 바꿔주시면 됩니다

또는 base.entries.trinkets.json 파일에서 해당 효과를 지우셔도 됩니다

2016년 10월 30일 일요일

[잡담] MorphVOX를 이용한 마이크 잡음제거

오버워치를 구매한 김에 마이크도 5만원짜리를 하나 장만했었습니다
그런데 마이크에서 삐~하느 잡음이 사라지지를 않더군요

여기저기 찾아보니 접지를 해야한다느니
비싼 마이크(10만원이상)를 구매해야한다느니 하는 글이 있던데

저는 음질과 상관없이 그저 잡음만 잡아내면 되기에
프로그램에서 답을 찾았습니다




설정에서 Sound Threashold(소리 임계값)을 조정하여 잡음과 외부 소음을 없을 수 있습니다. 일정 이상의 소리가 아니면 나오지 않도록 하는 설정이며 트랙바의 위치로 조정할 수 있습니다.
※임계값에 의해서 목소리의 끝부분이 잘릴 수 있습니다. (스팀에서 부정적 평가에 가면 해당 현상떄문에 불만을 가진 분이 계신 것 같더군요)

Hum Reduction이나 Echo Cancellation은 음질만 낮추고 큰 효과를 못보는 것 같아 끄고 쓰고 있습니다



이퀄라이저에서 가장 오른쪽에 있는 8K와 16K를 가장 밑으로 낮춥니다.
이렇게 해서 고음의 삐~하는 소리를 어느정도 없앨 수 있는 것 같습니다.


원래는 목소리를 다른 목소리(여자, 개, 로봇 등)로 변환하는 프로그램이지만
마땅히 실시간 잡음제거 프로그램이 보이지 않아 이 프로그램을 사용하게 되었네요

2016년 10월 23일 일요일

[C#, Reflection] 직렬화를 자동화하기 (Automatical Serialization)

도입


직렬화는 클래스를 저장하고 불러오기에 편리한 도구지만

많은 프로퍼티와 많은 클래스들을 직렬화(Serialization)하려면

직렬화할 멤버 하나당 2줄의 코드를 쓸 필요가 있습니다

또한 코드를 일일이 쓰다보니 잘못 써서 버그가 생길 염려도 있지요

그렇기에 리플렉션을 이용하여 자동화하는 것이 필요합니다




SerializationHelper

using System;
using System.Linq;
using System.Reflection;
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace CodeGenerater.Example
{
    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
    public sealed class SerializationTargetAttribute : Attribute
    {
    }
    public static class SerializationHelper
    {
        public static void Serialize(object Instance, SerializationInfo Info)
        {
            foreach (dynamic each in GetTarget(Instance))
                if (each is FieldInfo)
                    Info.AddValue(each.Name, each.GetValue(Instance), each.FieldType);
                else if (each is PropertyInfo)
                    Info.AddValue(each.Name, each.GetValue(Instance), each.PropertyType);
        }
        public static void Deserialize(object Instance, SerializationInfo Info)
        {
            foreach (dynamic each in GetTarget(Instance))
                if (each is FieldInfo)
                    each.SetValue(Instance, Info.GetValue(each.Name, each.FieldType));
                else if (each is PropertyInfo)
                    each.SetValue(Instance, Info.GetValue(each.Name, each.PropertyType));
        }
        static IEnumerable<MemberInfo> GetTarget(object Instance)
        {
            return from q in Instance.GetType().GetMembers(BindingFlags.GetField | BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                   where q.GetCustomAttribute<SerializationTargetAttribute>() != null
                   select q;
        }
    }
}
cs

직렬화를 자동화하기 위한 클래스입니다

Serialize, Deserialize 함수에 있는 dynamic 키워드는 4.0버전부터 가능하므로

만약 그 이전의 버전을 사용하고 계실경우 아래와 같이 쓰시면 됩니다

public static void Serialize(object Instance, SerializationInfo Info)
{
    foreach (var each in GetTarget(Instance))
        if (each is FieldInfo)
        {
            FieldInfo F = each as FieldInfo;
            Info.AddValue(F.Name, F.GetValue(Instance), F.FieldType);
        }
        else if (each is PropertyInfo)
        {
            PropertyInfo P = each as PropertyInfo;
            Info.AddValue(P.Name, P.GetValue(Instance), P.PropertyType);
        }
}
cs





Example

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace CodeGenerater.Example
{
    [Serializable]
    class Program : ISerializable
    {
        #region Serializaion
        public void GetObjectData(SerializationInfo Info, StreamingContext Context)
        {
            SerializationHelper.Serialize(this, Info);
        }
        Program(SerializationInfo Info, StreamingContext Conmtext)
        {
            SerializationHelper.Deserialize(this, Info);
        }
        #endregion
        #region Constructor
        public Program()
        {
        }
        #endregion
        #region Field
        [SerializationTarget]
        int PrivateField;
        #endregion
        #region Property
        [SerializationTarget]
        public int PublicProperty
        {
            set;
            get;
        }
        [SerializationTarget]
        public int HalfPublicProperty
        {
            private set;
            get;
        }
        [SerializationTarget]
        int PrivateProperty
        {
            set;
            get;
        }
        #endregion
        #region Method
        static void Main(string[] args)
        {
            var T = new Program();
            int R_PrivateProperty, R_HalfPublicProperty, R_PublicProperty, R_PrivateField;
        
            #region Initialize
            Random R = new Random();
            
            T.PrivateProperty = R_PrivateProperty = R.Next();
            T.HalfPublicProperty = R_HalfPublicProperty = R.Next();
            T.PublicProperty = R_PublicProperty = R.Next();
            T.PrivateField = R_PrivateField = R.Next();
            #endregion
            using (MemoryStream Stream = new MemoryStream())
            {
                #region Serialization
                BinaryFormatter F = new BinaryFormatter();
                F.Serialize(Stream, T);
                #endregion
                #region Init
                T = null;
                Stream.Position = 0;
                #endregion
                #region Deserialization
                T = (Program)F.Deserialize(Stream);
                #endregion
                #region Check
                bool TestSuccess =
                    T.PrivateProperty == R_PrivateProperty &&
                    T.HalfPublicProperty == R_HalfPublicProperty &&
                    T.PublicProperty == R_PublicProperty &&
                    T.PrivateField == R_PrivateField;
                if (TestSuccess)
                    Console.WriteLine("Success");
                else
                    Console.WriteLine("Fail");
                #endregion
            }
        }
        #endregion
    }
}
cs

간단하게 작동여부를 확인할 수 있는 예제입니다





주의할 점

프로퍼티를 직렬화할때 Setter와 Getter가 한정자와 상관없이 모두 존재해야합니다

Setter와 Getter 중 하나가 존재하지 않으면 쓰거나 읽을때 오류가 납니다





Archive File

2016년 8월 5일 금요일

[유용한 자료] 값을 누적하면서 평균을 구해야할 때 간단화하는 방법

도입 - 필요성


어떤 값의 집합이 있다고 하고

그 값들의 평균값이 아래와 같다고 할 때
평균값을 지속적으로 새로 구해야할 경우가 있습니다

예를 들어,
어떤 함수의 평균 실행 시간을 계속해서 구해야할 때
위의 방법으로 매번 평균을 구한다면
함수가 실행될때마다 그 실행 시간을 리스트에 저장할 필요성이 생기죠

한두번은 괜찮지만 만약 몇 만번 이상 실행한다면
리스트에 일일이 저장하는 것만으로도 컴퓨터에 부담을 주게 됩니다

이 글에서는 리스트에 일일이 저장하지 않고도
새로운 평균값을 구하는 방법에 대하여 설명합니다

해결 - 풀이


n 번째 평균이 Average(n)이라 한다면
n+1 번째 평균은 Average(n+1)이 됩니다

Average(n) 에서 f(n+1) 을 더하면 Average(n+1) 이 된다한다면 f(n+1) 은 아래와 같습니다

이 때 식에서 반복적으로 나오는 부분을 g(n) 이라 하면

f(n+1) 을 아래와 같이 표현할 수 있습니다


결국 Average(n+1) 은 아래와 같이 계산할 수 있는 것이죠

결론 - 정리


어떤 평균값 Average(n) 에서 새 값이 추가된 Average(n+1) 을 구하기 위해서는

1. 이전 평균값
2. 새 값
3. 새 값을 포함한 값의 갯수

이 세가지만 알면 된다는 것을 알 수 있습니다

코드로 작성하면


이렇게 간단하게 표현할 수 있습니다

부디 유용하게 써주세요 ㅇㅅㅇ!!

2014년 4월 10일 목요일

[C#, WPF] ObservableStack

닷넷의 컬렉션 중에서

배열이나 리스트는 XML 직렬화나 데이터 바인딩에 대해서 걱정할 것이 없는데

사전이나 스택같은 구조는 사용자가 직접 구현해야(...)하더군요


그런데 이왕이면 원래 코드에 약간의 코드만 추가하면 되는 것이라

어떻게 하면 쉽게 될까 했는데

ILSpy라는 DLL의 내용을 볼 수 있는 프로그램이 있더군요

덕분에 원래 스택코드를 복붙해서 할 수 있었습니다 ㅎㅎ

ObservableStack(데이터 바인딩을 위한 스택) 테스트 프로젝트
프로젝트 테스트 방법은 실행 후

엔터 -> 랜덤값 Push
딜리트 -> 최상위값 삭제
ESC -> 스택 초기화

입니다

그리고 위의 ObservableStack에 추가적으로 XML직렬화 기능을 넣어서
새로운 스택을 만들었습니다
https://www.dropbox.com/s/t6dwfdcpp8q5i2b/CustomizeStack.cs

2014년 3월 10일 월요일

[C#, WPF] Implementation of ObservableDictionary class

Why it need?

ObservableCollection<T> allow to automatic renew to UI. (Only WPF)

So you don't need to concern about changing of Collection.

But Sometime need binding UI with Dictionary and automatical renewal.

Because ObservableDictionary is not exist in standard library, need to implement.

How implement?

ObservableCollection<T> class use INotifyCollectionChanged interface.

So if you want to implement own ObservableCollection class,

need to implement INotifyCollectionChanged interface.


INotifyCollectionChanged interface expose only CollectionChanged

When collection changed, must call CollectionChanged event.

Example(C#)

Example code is created in Visual Studio 2013.


If you use lower version, just copy "ObservableDictionary.cs"

2013년 11월 25일 월요일

[C] 포인터(Pointer)에 대해서

들어가며

많은 분들이 C언어의 포인터를 어려워하십니다. 저 역시 그랬구요.

하지만 지금 되돌아보면
사실 간단한 것인데 주변에서 어렵다 어렵다 하니
저도 그렇게 생각했었던 것 같더라구요

이 글은 포인터를 어려워하시는 분들에게 도움을 드리고 싶어서
포인터에 관한 제 생각을 써보았습니다


왜 포인터를 쓰는 것 일까요?



  • 이 글을 읽고 왜 포인터를 사용하는지 생각해봐요

만약 여러분이 학교나 회사에 갈 때 집을 들고 다닌다면 어떨까요?















바닥에 고정되어있는데다가 너무 무거우니 아무도 그런 것은 하고 싶지 않을거에요










소라개나 달팽이같은 동물들은 집이 무거워서 빠르게 다니지 못해요 ㅠ,ㅠ


그래서 우리는 이런 느린 동물들처럼 집을 들고다니는 대신 주소를 외우고 다니지요

그 편이 훨씬 효율적이고 빠르잖아요 ㅎㅎ


이제 이것을 컴퓨터에 적용시켜보도록 해요


배열이나 구조체같은 것은 변수들을 많이 저장할 수 있어요

변수들에게 집이나 마찬가지이지요

그런데 그런 배열이나 구조체를 변수들이 직접 가지고 다니고 싶어할까요?


물론 컴퓨터를 만들때 굳이 그렇게 시킨다면

변수들을 속으로 울면서도 힘내서 자기들의 집을 들고 다니겠죠

하지만 그렇게하면 분명 컴퓨터가 느려질거에요

여러분은 그런 느린 컴퓨터를 사용하고 싶으신가요?

컴퓨터는 여러분을 기다리게 하지않기 위해서

주소를 적어놓은 변수(포인터)를 쓰는거랍니다.


컴퓨터의 주소는 어떻게 쓸까요?

  • 여기서부터 변수를 종이, 값을 내용이라고 쓸거에요
  • 예제 1과 예제 2를 비교해보아요

예제 1) 포인터를 사용하지 않는 예제



















이 코드를 실행하면 어떤 결과가 나올까요?










이제 이 결과가 왜 이렇게 나왔는지 생각해보도록 해요

우선 우리는

int Value = 10;

이라는 코드를 썼어요.

이것은 Value라는 종이에 10이라는 내용을 쓴 거에요

















그 다음에 실행될 코드는

Increase(Value);

네요. 여기서 main함수의 Value에서 Increase로 Input으로 내용을 전달해요
















이제 Increase함수 안의 코드를 살펴봐요

Input = Input + 1;

Input 이라는 종이에 적힌 내용에 1을 더하고 있어요















하지만 1을 더한 것은 Input이라는 종이이기때문에

Value 종이에는 그대로 10이라고 써있네요

그래서

printf("Value : %d", Value);

를 했을때 10이 나온 것이에요

그럼 여기서 포인터를 사용하면 어떻게 될까요?



예제 2) 포인터를 사용하는 예제




















이 예제의 결과는 어떨까요?










예제 1의 결과와 다른 점이 보이시나요?

예제 1에서는 결과가 10 이었지만

몇 글자를 더 추가한 이 예제는 결과가 11이에요.

이제 예제 2가 왜 이런 결과를 냈는지 설명해드릴께요


main함수의 맨 첫번째는 예제 1과 똑같아요

int Value = 10;

















그런데 두번째 코드는 약간 달라진 점이 있어요

Increase(&Value);

왜 &라는 것을 더 추가했을까요?

왜냐하면 &는 주소를 가르쳐주기때문이에요!
















이제 Input은 Value의 주소를 내용으로 가지고 있어요

그 다음 Increase함수의 내용을 보면

*Input = *Input + 1;

이라고 써있네요.

&이 주소를 가르쳐주는 연산자라면 *는 어떤 연산자일까요?

바로 주소를 따라가는 연산자에요

즉, *Input은 Input에 적힌 주소를 따라가서 Value를 데려오는거에요

















Increase함수에 있던 Input이

주소를 보고 main함수의 Value를 직접 데려와 1을 더해서

printf("Value : %d", Value);

이 코드에서 Value의 내용이 1 늘어난 11 인거에요

이해가 되셨나요?

만약 이해가 않되신다면 직접 코드를 짜서 실험해보면 도움이 될거에요 ㅎㅎ



포인터를 사용하려면 어떻게 해야할까?

포인터를 실제로 사용하려면 딱 세 가지만 알고 있으면 되요
  • int*은 int의 주소를 저장하는 타입
  • &는 주소를 가르쳐주는 연산자
  • *는 주소를 따라가서 데려오는 연산자

이 세 가지만 알면 포인터에 대해서 더 이상 알 것이 없어요. 참 쉽죠?