2012-06-13

C# Excel

액셀 cell에 직접 입력 하는 방법의 예.

 
/// 방법: Visual C# 2010 기능을 사용하여 Office Interop 개체에 액세스(C# 프로그래밍 가이드)
/// http://msdn.microsoft.com/ko-kr/library/dd264733
/// 솔루션-> 참조-> "COM" 탭 -> "Microsoft Excel 14.0 Object Library" 추가
/// 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Excel = Microsoft.Office.Interop.Excel;

namespace sample_excel
{
    public class Account
    {
        public int ID { get; set; }
        public double Balance { get; set; }
    }

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

        private void Form1_Load(object sender, EventArgs e)
        {
            // Create a list of accounts.
            var bankAccounts = new List {
                                                    new Account { 
                                                                  ID = 345678,
                                                                  Balance = 541.27
                                                                },
                                                    new Account {
                                                                  ID = 1230221,
                                                                  Balance = -127.44
                                                                }
                                                };
            // Display the list in an Excel spreadsheet.
            DisplayInExcel(bankAccounts);
        }

        static void DisplayInExcel(IEnumerable accounts)
        {
            var excelApp = new Excel.Application();
            
            // Make the object visible.
            excelApp.Visible = true;

            // Create a new, empty workbook and add it to the collection returned 
            // by property Workbooks. The new workbook becomes the active workbook.
            // Add has an optional parameter for specifying a praticular template. 
            // Because no argument is sent in this example, Add creates a new workbook. 
            excelApp.Workbooks.Add();

            // This example uses a single workSheet. The explicit type casting is
            // removed in a later procedure.
            Excel._Worksheet workSheet = (Excel.Worksheet)excelApp.ActiveSheet;

            // Establish column headings in cells A1 and B1.
            workSheet.Cells[1, "A"] = "ID Number";
            workSheet.Cells[1, "B"] = "Current Balance";
            workSheet.Cells[1, "C"] = "=SUM(A2:B2)";
            var row = 1;
            foreach (var acct in accounts)
            {
                row++;
                workSheet.Cells[row, "A"] = acct.ID;
                workSheet.Cells[row, "B"] = acct.Balance;
            }

            workSheet.Columns[1].AutoFit();
            workSheet.Columns[2].AutoFit();
        }

    }

}
// 
...

WH_MOUSE는 글로벌 훅이 불가

마우스 커서가 위치한 창의 Process ID나 Thread ID를 가져오려면 WH_MOUSE를 사용해서 후킹을 해야하는데 잘 동작하지 않아, 검색해봤으나 아무리 찾아도 관련 정보를 찾을 수 없었다.
마우스 후킹된 데이터를 저장하는 스트럭쳐만 MSLLHOOKSTRUCT대신 MOUSEHOOKSTRUCT를 사용하는 소스는 봤는데, 그렇게 하면 그냥 마우스의 x,y 좌표만 얻을 수 있다(POINT pt값).

MOUSEHOOKSTRUCT의 구조( 이걸 사용해봤자.. 메모리에 있는 내용은 MSLLHOOKSTRUCT)
typedef struct tagMOUSEHOOKSTRUCT {
  POINT     pt;
  HWND      hwnd;
  UINT      wHitTestCode;
  ULONG_PTR dwExtraInfo;
} MOUSEHOOKSTRUCT, *PMOUSEHOOKSTRUCT, *LPMOUSEHOOKSTRUCT;

MSLLHOOKSTRUCT의 구조
typedef struct tagMSLLHOOKSTRUCT {
  POINT     pt;
  DWORD     mouseData;
  DWORD     flags;
  DWORD     time;
  ULONG_PTR dwExtraInfo;
} MSLLHOOKSTRUCT, *PMSLLHOOKSTRUCT, *LPMSLLHOOKSTRUCT;



그나마 microsoft의 페이지에서 WH_MOUSE로 후킹하는 자료를 찾았으나, 내용은 아래처럼 글로벌 훅이 지원되지 않는다는 말만 있고, 훅이 글로벌 훅이 아닌 Form1에서만 동작했다.
WH_MOUSE만 글로벌 훅이 안된다고 하면 그러려니 할탠데 글로벌 훅 자체가 안된다고 하니, 다른 방법이 있지 않을까 한다.
WH_MOUSE_LL, WH_KEYBOARD_LL은 글로벌 훅이 동작하니까..



이하 MS의 글로벌 후크가 지원되지 않는 다는 내용.

http://support.microsoft.com/kb/318804/ko

글로벌 후크가 .NET Framework에서 지원되지 않음

Microsoft .NET Framework에서는 글로벌 후크를 구현할 수 없습니다. 글로벌 후크를 설치하려면 일관성 있고 유효한 함수를 호출해야 하는 다른 프로세스에 DLL 자체를 삽입하는 기본 동적 연결 라이브러리(DLL) 내보내기가 후크에 있어야 합니다. 이러한 DLL 내보내기는 .NET Framework에서 지원되지 않습니다. 이러한 함수 포인터는 동적으로 만들어지는 프록시이기 때문에 관리되는 코드에는 함수 포인터에 대해 일관성 있는 값이라는 개념이 없습니다.

blogspot, blogger.com에 SyntaxHighLighter 적용

SyntaxHighLighter 페이지:http://code.google.com/p/syntaxhighlighter/
Blogger 적용방법 참조 : http://majumawm.blogspot.kr/2010/08/syntaxhighlighter-3083.html

SyntaxHighLighter를 사용하면 소스코드의 가독성을 높힐 수 있어 적용해 보았다.
Blogger에 적용하는 방법에 대해서는 위의 출처를 참조했다.

적용방법
1. Blogger 대쉬보드에서 "템플릿" -> "HTML 편집"

2. 자바스크립트를 붙여넣기 할, 태그 찾기

3. 태그 위에 SyntaxHighLighter 자바스크립트 붙여넣기




이것으로 사용할 준비가 끝났다.
사용할 때는, 소스코드 부분을 HTML편집 해야한다.

 
Console.WriteLine("pre 태그 안에 소스코드 작성...");

C# xml 데이터로 treeview 형태로 표현하기


출처: http://support.microsoft.com/kb/317597/ko



xmlDoc.Load("sample.xml");
XmlDocument xmlDoc = new XmlDocument();
treeView1.Nodes.Add(new TreeNode(xmlDoc.DocumentElement.Name)); //root node(family)를 treeview1에 업데이트
TreeNode tnode = new TreeNode(); //root node에 붙일 node 초기화
tnode=treeView1.Nodes[0]; // 0번 node에 tnode를 붙임

AddNode(xmlDoc.DocumentElement, tnode); //재귀호출
---------------------------------

        ///

        /// XmlNode로 부터 TreeNode를 기록하는 Recursive call.
        /// AddNode가 받을 TreeNode와 XmlNode parameter를 A와 B로 변경
        /// 재귀호출에 쓰일 TreeNode와 XmlNode를 AA와 BB로 변경함.
        ///

        /// 재귀탐색을 할 XmlNode
        /// 재귀기록을 할 TreeNode
        private void AddNode(XmlNode A,TreeNode B)
        {

             XmlNode AA;   //AddNode를 재귀호출 할 때 쓰일 XmlNode
             TreeNode BB;  //AddNode를 재귀호출 할 때 쓰일 TreeNode
             XmlNodeList xmlNodes; //A 밑의 ChildNodes를 저장할 컬렉션
             int i; // Child의 수만큼 재귀반복 할 count

             // Loop through the XML nodes until the leaf is reached.
             // Add the nodes to the TreeView during the looping process.
             if (A.HasChildNodes) //A가 child를 가지고 있으면 재귀호출하며 마지막 노드를 찾음.
             {
                xmlNodes = A.ChildNodes; // A child노드들을 노드컬렉션(xmlNodes)에 등록
                for(i = 0; i<=xmlNodes.Count - 1; i++) //xmlNodes의 수 많큼 반복
                {
                   AA = A.ChildNodes[i]; // A의 child노드를 하나씩 재귀호출에 쓰일 AA에 저장
                   B.Nodes.Add(new TreeNode(AA.Name)); //TreeNode B에 AA항목(node) 추가
                   BB = B.Nodes[i];//AA.Name으로 추가된 TreeNode를 다음 재귀호출에 쓰일 BB로 저장
                   AddNode(AA, BB); // AA와 BB로 재귀호출
                   B.Text = "!";
                }
             }
             else // child가 없는 leaf node(Xml의 tag가 아닌 Text에 해당)이면 B.Text에 XML태그 값을 저장
             {
                // Here you need to pull the data from the XmlNode based on the
                // type of node, whether attribute values are required, and so forth.
                B.Text = (A.OuterXml).Trim(); // A.OuterXml의 의미 없는 공백문자를 제거
             }
        }

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

2012-06-05

Mouse hook

(마우스 커서는 폼 밖에 있으나 x,y 좌표를 계속 받는다.)

풀소스 및 출처 : CodeSummoner, http://www.codeproject.com/Articles/28064/Global-Mouse-and-Keyboard-Library

keyboard와 mouse를 후킹 하는 라이브러리.

지난 번, keyboard hook과의 차이점은

keyboardHook.cs와 mouseHook.cs에서 globalHook.cs을 상속 받아 구현했다.
globalHook.cs에서 필요한 DllImport,
키보드 데이터 스트럭쳐와 마우스 데이터 스트럭쳐 정의,
후킹에 필요한 상수 정의,
후킹이 실행됬는지에 대한 Property정의,
Application.ApplicationExit+= new EventHandler(Application_ApplicationExit)으로 unhook() 함수를 대신하고
후킹의 콜백 프로시져는 HookCallbackProcedure로 가상 함수로 구현되었다.
SetWindowHookEx는 Hook()에서 Start()로 변경되었다.

테스트 실행에서 이미 디버깅되 실행파일로 나와 있는 샘플을 실행할 땐 정상 작동했으나, 직접 F5로 실행해보면 제대로 동작하지 못한다. 중간에 소스코드에 무슨 변화가 있던 것 같다.
임시로 hInstance가 Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]로 되어 있던 것을 LoadLibrary("User32")로 변경하면.. 일단 실행이 된다.

globalHook.cs에 마우스훅스트럭쳐를 보면 마우스 좌표를 기억하기 위한 point형을 사용하고 있다.

        protected class MouseLLHookStruct // MSDN MSLLHOOKSTRUCT와 동일
        {
            public POINT pt;  //마우스 좌표
            public int mouseData; // 메세지가 WM_MOUSEWHEEL일 경우, 휠을 움직인 델타값. X-button일 경우 어떤 X-button인지 저장.
            public int flags; // event injected 플래그
            public int time; // 메시지에 대한 time stamp, 키보드훅과 동일
            public int dwExtraInfo; // additional inform(?), MSDN에는 UintPtr type을 쓴다.
        }


        protected class POINT
        {
            public int x;
            public int y;
        }


mouseHook.cs에 overriding된 훅 프로시져(HookCallbackProcedure)의 내용은 크게 MouseButtons 객체에 후킹된 버튼 기억, 유저 어플리케이션에 전달될 MouseEventArgs 정의, 후킹된 이벤트에 따라 유저 어플리케이션으로 이밴트 발생이 있다.



protected override int HookCallbackProcedure(int nCode, int wParam, IntPtr lParam)
// nCode는 후킹할 대상, WH_MOUSE_LL (=14)

// wParam에는 마우스 메시지가..
// lParam에는 마우스의 훅 정보가 담긴 스트럭쳐의 포인터 (여기서는 MouseLLHookStruct)

MouseButtons button = GetButton(wParam); // 마우스 버튼 객체 정의

// MouseEventArgs 정의
MouseEventArgs e = new MouseEventArgs(
                    button,
                    (eventType == MouseEventType.DoubleClick ? 2 : 1),
                    mouseHookStruct.pt.x,
                    mouseHookStruct.pt.y,
                    (eventType == MouseEventType.MouseWheel ? (short)((mouseHookStruct.mouseData >> 16) & 0xffff) : 0));



        private MouseButtons GetButton(Int32 wParam) // case에 따라  "Left", "Right", "Middle", "None"을 return, MouseEventArgs.Button property에 기록된다.
        {

            switch (wParam)
            {

                case WM_LBUTTONDOWN:
                case WM_LBUTTONUP:
                case WM_LBUTTONDBLCLK:
                    return MouseButtons.Left;
                case WM_RBUTTONDOWN:
                case WM_RBUTTONUP:
                case WM_RBUTTONDBLCLK:
                    return MouseButtons.Right;
                case WM_MBUTTONDOWN:
                case WM_MBUTTONUP:
                case WM_MBUTTONDBLCLK:
                    return MouseButtons.Middle;
                default:
                    return MouseButtons.None;

            }

        }




유저 어플리케이션에서 이 라이브러리를 사용하는 방법은 지난 번 키보드 훅을 사용할 때와 같다.
MouseHook 객체를 생성하고, 생성한 객체의 이밴트에 이밴트핸들러를 추가하고, 어떤 일을 할지 이밴트핸들러를 정의해주면 된다.

using MouseKeyboardLibrary; //네임스페이스 사용
MouseHook mh = new MouseHook(); 마우스 훅 인스턴스 생성


mh.MouseMove += new MouseEventHandler(mh_MouseMove); //MouseHook에 정의된 이벤트에 유저 이벤트핸들러 추가
mh.MouseDown += new MouseEventHandler(mh_mousedown); //마우스 버튼 관련 이밴트 핸들러 추가
mh.Start(); // 마우스 훅 시작.



        private void mh_MouseMove(object sender,MouseEventArgs e) // 이벤트핸들러 구성
        {
            xyCoordinator(e.X, e.Y); //좌표 표시용 함수 호출
            textBox3.Text = mh.IsStarted.ToString(); //test, 후킹 중인지 상태 표시
        }

        private void xyCoordinator(int x, int y) //좌표 표시용 함수
        {
            textBox1.Text = String.Format("x= {0}", x);
            textBox2.Text = String.Format("y= {0}", y);
        }

        private void mh_mousedown(object sender, MouseEventArgs e)
        {
            textBox3.Text = e.Button.ToString(); // "Left" or "Right" 누른 마우스 버튼 표시
        }