반응형
반응형
1. 사용자 정의 애트리뷰트 만들기
2. 애트리뷰트 클래스를 이용한 애트리뷰트 객체 생성하기
3. 애트리뷰트 정보 얻어내기
4. 내장 애트리뷰트
5. Conditional
6. Obsolete
7. DllImport

- 설명 -
1. 사용자 정의 애트리뷰트 만들기
-public class AppleAttribute : Attribute
 {
     // Empty
 }

2. 애트리뷰트 클래스를 이용한 애트리뷰트 객체 생성하기
- [AppleAttribute("머리만1톤의 클래스입니다.")]
public class AppleStore
{
    [AppleAttribute("사과의 개수를 나타내는 필드입니다.")]
    public int count = 5;
    [AppleAttribute("사과의 개수를 리턴하는 함수입니다.")]
    public int GetCount()
    {
         return this.count;
    }
}

- 클래스나 멤버 필드 그리고 멤버 함수 윗부분에 달아두는 의미
 : [] 로 감싸서 달아두는 것 자체가 객체의 생성을 의미. 클래스에 부연설명을 추가하기 위해서 객체의 메모리를 첨부시켜 둔 것.

- 애트리뷰트를 사용하는 이유 : 컴파일 시 또는 실행시에 그 정보를 이용

3. 애트리뷰트 정보 얻어내기

- 리플랙션 기법 이용

- Type 클래스를 이용해서 Type 객체를 얻은 후 애트리뷰트를 얻어내는 방법

- Type type = Type.GetType("AppleStore");
foreach(Attribute attr in type.GetCustomAttribute(true)
{
    //
}
foreach(FieldInfo finfo in type.GetFields())
{
    foreach(Attribute attr in finfo.GetCustomAttribute(true)
    {
        //
    }
}
foreach(MethodInfo minfo in type.GetMethods())
{
    foreach(Attribute attr in minfo.GetCustomAttributes(true))
    {
        //
    }
}

4. 내장 애트리뷰트

- 내장 애트리뷰트는 네임스페이스명을 기준으로 분류함
 : System.ComponentModel 계열
 : System.ContextStaticAttribute 계열
 : System.Diagnostics 계열
 : System.EnterpriseServices 계열
 : System.Reflection 계열
 : System.Runtime 계열
 : System.Security 계열
 : System.Web 계열
 : System.Xml 계열

5. Conditional

- 특정 전처리 식별자에 의해 실행되는 조건부 함수의 호출을 제어할 수 있는 애트리뷰트

- #define으로 정의된 문자를 사용하였을 경우 해당 함수 실행

- #define으로 정의되어 있지 않으면 해당함수가 호출되지 않는다.

6. Obsolete

- 더 이상 사용하지 않는 프로그램 요소를 표시

- Obsolete 애트리뷰트가 붙어있는 함수가 호출되면 컴파일 시 애트리뷰트에서 설정한 내용이 명령 프롬프트 창에 경고로 출력

7. DllImport

- 기존에 만들어진 외부 DLL을 호출하기 위해서 사용하는 애트리뷰트

- using System.Runtime.InteropServices;

- User32.Dll 의 MessageBox 함수 호출 순서
 : 먼저 사용하려는 함수에서 DllImport 애트리뷰트를 지정
 : DllImport 애트리뷰트에는 호출할 Dll의 이름을 기입
 : 외부의 비관리 코드에 있는 Dll을 특정 프로세스 메모리에 로딩
 : 이 함수의 메모리 주소를 MessageBox() 함수에 지정
 : extern 키워드 -> 어떤 함수가 현재 프로그램 외부에 있음을 나타내는 키워드


반응형
반응형

bool chk = c.IsChecked ?? false;    // null이 아니면 (true)이면 true, 아니면 기본값 (false)를...
반응형
반응형

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 System.Runtime.InteropServices;

namespace CredentialManager
{
    public partial class Form1 : Form
    {
        public static Guid CLSID_InternetSecurityManager = new Guid("7b8a2d94-0ac9-11d1-896c-00c04fb6bfc4");
        public static Guid IID_IInternetSecurityManager = new Guid("79eac9ee-baf9-11ce-8c82-00aa004ba90b");

        private const uint SZM_CREATE = 0;
        private const uint SZM_DELETE = 1;

        public const uint ZoneLocalMachine = 0;
        public const uint ZoneIntranet = 1;
        public const uint ZoneTrusted = 2;
        public const uint ZoneInternet = 3;
        public const uint ZoneUntrusted = 4;

        public Form1()
        {
            InitializeComponent();
            AddSiteToZone(ZoneTrusted, "http://test.wonx.com");
        }

        private static IInternetSecurityManager CreateInternetSecurityManager()
        {
            Type iismType = Type.GetTypeFromCLSID(CLSID_InternetSecurityManager);
            return (IInternetSecurityManager)Activator.CreateInstance(iismType);
        }

        public static void AddSiteToZone(uint zone, string pattern)
        {
            try
            {
                IInternetSecurityManager ism = CreateInternetSecurityManager();
                ism.SetZoneMapping(zone, pattern, SZM_CREATE);
            }
            catch (COMException e)
            {
                throw new InvalidOperationException("URL has already been added to a zone", e);
            }
            catch (UnauthorizedAccessException e)
            {
                throw new InvalidOperationException("Can't add non-SSL site to zone that requires SSL", e);
            }
        }

        public static void RemoveSiteFromZone(string pattern)
        {
            uint currentZone;
            IInternetSecurityManager ism = CreateInternetSecurityManager();
            ism.MapUrlToZone(pattern, out currentZone, 0);
            ism.SetZoneMapping(currentZone, pattern, SZM_DELETE);
        }

        [ComImport, GuidAttribute("79EAC9EE-BAF9-11CE-8C82-00AA004BA90B"),
        InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IInternetSecurityManager
        {
            [return: MarshalAs(UnmanagedType.I4)]
            [PreserveSig]
            int SetSecuritySite([In] IntPtr pSite);

            [return: MarshalAs(UnmanagedType.I4)]
            [PreserveSig]
            int GetSecuritySite([Out] IntPtr pSite);

            [return: MarshalAs(UnmanagedType.I4)]
            [PreserveSig]
            int MapUrlToZone([In, MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, out UInt32 pdwZone, UInt32 dwFlags);

            [return: MarshalAs(UnmanagedType.I4)]
            [PreserveSig]
            int GetSecurityId([MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, [MarshalAs(UnmanagedType.LPArray)] byte[] pbSecurityId, ref UInt32 pcbSecurityId, uint dwReserved);

            [return: MarshalAs(UnmanagedType.I4)]
            [PreserveSig]
            int ProcessUrlAction([In, MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, UInt32 dwAction, out byte pPolicy, UInt32 cbPolicy, byte pContext, UInt32 cbContext, UInt32 dwFlags, UInt32 dwReserved);

            [return: MarshalAs(UnmanagedType.I4)]
            [PreserveSig]
            int QueryCustomPolicy([In, MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, ref Guid guidKey, ref byte ppPolicy, ref UInt32 pcbPolicy, ref byte pContext, UInt32 cbContext, UInt32 dwReserved);

            [return: MarshalAs(UnmanagedType.I4)]
            [PreserveSig]
            int SetZoneMapping(UInt32 dwZone, [In, MarshalAs(UnmanagedType.LPWStr)] string lpszPattern, UInt32 dwFlags);

            [return: MarshalAs(UnmanagedType.I4)]
            [PreserveSig]
            int GetZoneMappings(UInt32 dwZone, out UCOMIEnumString ppenumString, UInt32 dwFlags);
        }
    }
}

반응형
반응형

InstallShield 로 작업중에 한 사이트로부터 해당 프로그램이 구동하는 서버 주소를 신뢰된 사이트에 등록해달라고 함.

찾아보니 registy 쪽을 살짝 추가해주면 됨.

예) *.handysoft.co.kr 을 추가해야할 경우
---------------------------------------------------------------------------------------------------------------
Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\handysoft.co.kr]
"http"=dword:00000002
---------------------------------------------------------------------------------------------------------------
위와 같은 형태로 추가해주면 된다

예) bbs.test.com
---------------------------------------------------------------------------------------------------------------
Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\test.com]

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\test.com\bbs]
"http"=dword:00000002

예) 123.123.123.1
---------------------------------------------------------------------------------------------------------------
Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Ranges\Range99]
"http"=dword:00000002
":Range"="10.40.17.26"
---------------------------------------------------------------------------------------------------------------
Range숫자 // 부분은 사용자가 원하는대로 추가

반응형
반응형
http://msdn.microsoft.com/ko-kr/library/206sadcd(VS.80).aspx

안녕하세요? 맨날맑음 입니다.

.NET 으로 프로젝트를 만들고, 배포를 하는 방법은 Click Once같은 방법도 있지만 이번에는 Windows Installer 배포에 대해 알아보겠습니다. 기존에 .Net으로 프로젝트 개발만 해보았지, 배포는 신경을 쓰지 않아 잘 모르다가, 이번에 VS2008에서 기본으로 제공되는 배포 프로젝트의 사용법을 알아 보았습니다.
아래 링크를 따라가면 배포프로젝트에 관한 MSDN 도움말을 보실 수 있습니다.
http://msdn.microsoft.com/ko-kr/library/206sadcd(VS.80).aspx

우선 배포할 프로그램을 준비합니다. 저는 간단한 윈폼 프로젝트로 하겠습니다.

VS2008에서 새 프로젝트를 추가 하고, 기타 프로젝트 형식 -> 설치 및 배포 -> 설치프로젝트를 선택합니다.

다음과 같이 배포 프로젝트가 생성됩니다.

솔루션 탐색기와 속성 창을 보면 아래와 같이 프로젝트와, 여러 속성이 보이게 됩니다.
이제 이 속성들의 의미를 하나하나 알아보겠습니다.
▷AddRemoveProgramIcon : 제어판 -> 프로그램 추가/제거에 표시될 아이콘을 등록합니다.
▷Author : 프로젝트 작성자의 이름을 등록합니다.
▷Desciption : 설치 관리자에 관한 설명을 등록합니다.
▷DetectNewerInstalledVersion : 프로그램 설치시 버전 비교를 통해 새 버전인지 확인 해 줍니다. 이미 설치 되있을 경우 설치 되어있다고 알려주기도 합니다.
▷Keyword : 설치 관리자를 검색하는데 사용 할 키워드를 지정합니다.
▷Localization : 로케일을 적용한다고 하는데, 글로벌 프로그램이 아니라면 신경 안써도 될 듯 합니다.
▷Manufacturer : 제조업체의 이름을 지정합니다
▷MunufacturerUrl : 제조업체의 홈페이지 링크를 지정.
▷PostBuildEvent : 배포프로젝트를 빌드한 후에 실행 할 명령줄을 지정합니다.
▷PreBuildEvent : 배포프로젝트를 빌드하기 전에 실행 할 명령줄을 지정합니다.
▷ProductCode : 응용프로그램의 고유 식별자(GUID)를 지정합니다.
▷ProductName : 프로그램의 공개 이름을 지정합니다.
▷RemovePrevionsVersions : 설치시 이전버전을 삭제 할지를 지정합니다.
▷RunPostBuildEvent : PostBuildEvent 속성에서 지정된 명령줄을 실행할 시기를 결정합니다.
▷SearchPath : 개발 컴퓨터의 어셈블리, 파일 또는 병합 모듈을 검색하는 데 사용되는 경로를 지정합니다.
Subject : 프로그램을 설명하는 추가정보를 지정합니다.
▷SupportPhone : 전화번호를 지정합니다.
▷SupportUrl : 마찬가지로 추가 설명을 하는 웹사이트 주소
TargetPlatform : 프로그램이 실행될 플랫폼을 지정.
▷Title : 설치 관리자의 제목을 지정합니다.
▷UpgradeCode : 프로그램 버전이 여러가지 일때 고유식별자를 지정합니다.
▷Virsion : 버전을 지정합니다.




속성 참 많네요.. 정작 중요한건 ProductName, Title, Author, MAnufacturer 정도 입니다.

이제 파일시스템 탭으로 이동하여 대상 컴퓨터의 파일 시스템 -> 응용 프로그램 폴더를 선택한 후 속성창을 확인합니다.

DefalutLocation이라는 속성에 [ProgramFilesFolder][Manufacturer]\[ProductName] 라고 되어 있습니다. 인스톨시 프로그램이 설치될 폴더 인데요. 이 설정으로 하게 되면 프로그램파일 폴더 밑에 제조회사명 밑에 프로그램 이름 폴더 안에 깔리게 되겠습니다. 맘에 드는 폴더로 변경 하시면 됩니다.

이제 파일을 추가 해 보겠습니다. 응용 프로그램 폴더에서 마우스 오른쪽 버튼을 누르면 파일이나 폴더등을 추가 할 수 있습니다. 미리 만들어 놓은 샘플 어플리케이션을 추가 하겠습니다.


이렇게 하면 앞서 지정된 설치 폴더에 MainApp.exe가 설치 됩니다. 명색이 인스톨 프로그램인데 이것만 지정하면 안되겠죠? 위에 사용자 바탕화면사용자 프로그램 메뉴가 보입니다.
말 그래로 사용자 바탕화면은 바탕화면에 설치 될 파일을 지정 할 수 있고, 사용자 프로그램 메뉴는 [시작]->[프로그램]의 폴더나 파일을 지정 할 수 있습니다.
바탕화면과 프로그램 메뉴에 MainApp.exe의 바로가기를 넣어주면 클라이언트가 아주 편리 할 것 같습니다.
MainApp.exe를 마우스 오른쪽 버튼으로 클릭하여 바로가기를 만듭니다. 저는 두개를 만들어 이름을 원하는데로 변경한 후 하나는 사용자 바탕화면으로 끌어다 놓았고, 사용자 프로그램 메뉴에는 [새폴더]를 하나 추가 하여, 그 안에 넣었습니다. 그리고 아이콘 파일(.ico)도 하나 추가하여 바로가기의 속성중 Icon에 연결 시켜 줍니다. 그럼 바로가기가 우리가 지정한 아이콘으로 생성 됩니다.

이제 언인스톨 기능을 하는 바로가기도 지원해 주어야 좀 더 있어보일 것입니다. 
바탕화면에서 텍스트문서(txt)를 하나 추가해서 확장자를 bat로 바꾸어 줍니다. 편집기로 파일을 열어 Msiexec /x {ProductCode} 를 추가 해 줍니다. 여기서 ProductCode는 위에 프로젝트 속성중에 있던 코드 입니다. 지금 예제 대로 하면 Msiexec /x {A1715BBB-A953-4F01-B788-168542ED2BC3} 이 되겠네요.

현재 배포하는 샘플 프로그램이 매우 간단하여 파일이 하나이지만, 대부분의 응용은 여러 DLL을 포함하고 있을것입니다. 그리고 각 파일마다 설치하고 싶은 경로가 다를 수 있는데, 파일시스템 탭의 대상 컴퓨터의 파일 시스템을 오른쪽 버튼으로 누르면 특수폴더 추가에서 원하는 폴더를 추가 할 수 있습니다.

이제 이 파일을 응용프로그램 폴더에 포함 시켜주고, 마찬가지 방법으로 바로 가기를 만들어서 원하는 곳에 추가 시켜 줍니다. 프로젝트를 다시 빌드 하고 테스트 해보겠습니다. 프로젝트 폴더의 Relese 폴더에 들어가니 파일이 두개 보입니다.(Relese모드로 빌드 했을 경우, Debug 모드 일경우 Debug 폴더에 생성)
Setup.exe를 더블 클릭하니 설치가 잘 됩니다. 
설치시 생긴 바로가기 아이콘으로 Uninstall도 잘되는지 확인해 보겠습니다.
정상적으로 잘 되는걸 볼 수 있습니다. 쓰다 보니 스크롤의 압박이군요;
만약 설치 대상컴퓨터(클라이언트)에 .Net Framwork가 없을때 자동으로 설치되게 하는 것 까지 쓰려고 했는데,
다음편으로 넘겨야 할 것 같습니다. 다음편에는 이같은 기능을 해주는 Boot Strapper에 관해 포스팅 하겠습니다. 
반응형
반응형

안녕하세요 : )

서버측 소프트웨어를 작성하다 보면, 서비스에 대한 제어가 필요한 경우가 많습니다. VS.Net의 경우 시스템에 존재하는 서비스에 접근할 수 있는 코드를 쉽게 만들 수 있습니다.

그럼 시작합니다 : )

서버 탐색기

    

VS.Net을 사용하고 있고, 서버측 애플리케이션 작성을 많이 하고 있다면, 아마 서버 탐색기 탭을 많이 사용하고 있을 것이다. SQL Server 아이콘에서 Drag'n Drop 만으로 SqlCommand 개체를 생성할 수 있다는 것 정도는 아마 알고 있겠지만, 서비스에 대한 접근도 가능하다는 것은 알고 있는가?

    

MSSQLSERVER 서비스 아이콘을 끌어서 폼 위에 놓으면 serviceController1 개체가 생성된다. 그리고 다음과 같이 버튼을 하나 배치해보자 :

     

 

이렇게 해 놓으면 사용할 준비는 끝났다. 다음과 같이 코딩해보자 :

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

{

    DialogResult result;

    switch(serviceController1.Status)

    {

        case System.ServiceProcess.ServiceControllerStatus.Stopped:

            result = MessageBox.Show(

                string.Format("{0} 서비스가 중지되어 있습니다. 시작하시겠습니까?", serviceController1.ServiceName),

                "서비스 중지",

                MessageBoxButtons.YesNo);

            if(result == DialogResult.Yes)

                serviceController1.Start();

            break;

        case System.ServiceProcess.ServiceControllerStatus.Running:

            result = MessageBox.Show(

                string.Format("{0} 서비스가 실행중입니다. 중지하시겠습니까?", serviceController1.ServiceName),

                "서비스 실행",

                MessageBoxButtons.YesNo);

            if(result == DialogResult.Yes)

                serviceController1.Stop();

            break;

    }

}

 

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

{

    this.button1.Enabled = true;

    switch(serviceController1.Status)

    {

        case System.ServiceProcess.ServiceControllerStatus.Stopped:

            this.button1.Text =

                string.Format("{0} 서비스 시작", serviceController1.ServiceName);

            break;

        case System.ServiceProcess.ServiceControllerStatus.Running:

            this.button1.Text =

                string.Format("{0} 서비스 중지", serviceController1.ServiceName);

            break;

        default:

            this.button1.Enabled = false;

            break;

    }

}

코드 자체는 어렵지 않으므로 쉽게 이해할 수 있으리라 생각한다. 프로그램을 실행시키면 다음과 같은 폼이 나타난다 :

이런 식으로 서비스의 현재 상태를 체크할 수 있고, 시작/중지/일시 정지 등의 기능을 수행할 수 있으며, 서비스에서 미리 정의되어 있는 명령이 있다면 ExecuteCommand() 메서드를 사용해서 정의된 명령을 내릴 수도 있다.

정리

여러 서버의 서비스를 동시에 제어해야 한다거나, 원격에 있는 서비스를 제어하는 등 응용 가능성은 남겨놓도록 하겠습니다.

그럼 : )


  작성자 : 이수겸(Kenial),MS Visual C# MVP
  이메일 : keniallee@msn.com
  홈페이지 : www.kenial.net


반응형
반응형

Objective


This article will explain how to perform operations on Active Directory (AD) using C#.  In this step-by-step tutorial, I will build a class library (DLL) project that will perform all the AD Operations and then you can use this class library in any application to use this functionality.

Basic introduction of Active Directory is provided and code examples for operations like

1.       Finding user by login name

2.       Finding user by Name

3.       Finding user by First Name

4.       Resolving AD Group in users etc

What is Active Directory


This is a Directory structure used in Windows for storing information about networks and domains.  This was first used in Windows 2000.  This is a hierarchical structure which helps in organizing information on objects.  In lay term it is used to store user information, network information in an organization.

Solution Explorer for the Active Directory Helper Class library

 


 

ActiveDirectoryHelper is the main working class. This class will contain all the functions for various operations on AD. Other classes are helping class to perform operations and being used in ActiveDirectoryHelper class.  After adding DLL of this project, at the client side object of ActiveDirectory class will get created and the function will get called.

Diving into code to Perform Operations

Step 1

Create a new project by selecting project template Class Library.

Step 2

Add below references to the project

System.DirectoryServices

System.DirectoryServices.AccountManagement

System.DirectoryServices.Protocols.

System.Configuration

Step 3

Add an Application Configuration file to project.  And add App setting for

1.       LDAP User Name

2.       LDAP Password

3.       LDAP Path

So App.Config file will look like below,

App.Config

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

  <appSettings>

    <add key="LDAPPassword" value="xxxPasswordxxx " />

    <add key="LDAPPath" value="LDAP://domain/DC=xxx,DC=com" />

    <add key="LDAPUser" value="xxxUserxxx " />

  </appSettings>

</configuration>

Note: Give user name, password and path according to your LDAP

Step 4. Creating ADUser class

Create or add a class in the project for ADUser details. This class will have the properties corresponding to the information of the AD User.

1.       This class has read only properties for fetching First Name, Last Name, City, Login Name etc.

2.       Constructor of the class is taking one parameter of type DirectoryEntry class.

3.       In Constructor all the information about ADUser is getting fetched using static class ADProperties.

4.       There are two static functions inside this class. GetUser and GetProperty

5.       Get Property is returning a string which holds property of AD User.

6.       GetUser static function is returning an ADUser.

ADUserDetail.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.DirectoryServices;

 

namespace ActiveDirectoryHelper

{

    public class ADUserDetail

    {

        private String _firstName;

        private String _middleName;

        private String _lastName;

        private String _loginName;

        private String _loginNameWithDomain;

        private String _streetAddress;

        private String _city;

        private String _state;

        private String _postalCode;

        private String _country;

        private String _homePhone;

        private String _extension;

        private String _mobile;

        private String _fax;

        private String _emailAddress;

        private String _title;

        private String _company;

        private String _manager;

        private String _managerName;

        private String _department;

 

        public String Department

        {

            get { return _department; }

        }

 

        public String FirstName

        {

            get { return _firstName; }

        }

 

        public String MiddleName

        {

            get { return _middleName; }

        }

 

        public String LastName

        {

            get { return _lastName; }

        }

 

        public String LoginName

        {

            get { return _loginName; }

        }

 

        public String LoginNameWithDomain

        {

            get { return _loginNameWithDomain; }

        }

 

        public String StreetAddress

        {

            get { return _streetAddress; }

        }

 

        public String City

        {

            get { return _city; }

        }

 

        public String State

        {

            get { return _state; }

        }

 

        public String PostalCode

        {

            get { return _postalCode; }

        }

 

        public String Country

        {

            get { return _country; }

        }

 

        public String HomePhone

        {

            get { return _homePhone; }

        }

 

        public String Extension

        {

            get { return _extension; }

        }

 

        public String Mobile

        {

            get { return _mobile; }

        }

 

        public String Fax

        {

            get { return _fax; }

        }

 

        public String EmailAddress

        {

            get { return _emailAddress; }

        }

 

        public String Title

        {

            get { return _title; }

        }

 

        public String Company

        {

            get { return _company; }

        }

 

        public ADUserDetail Manager

        {

            get

            {

                if (!String.IsNullOrEmpty(_managerName))

                {

                    ActiveDirectoryHelper ad = new ActiveDirectoryHelper();

                    return ad.GetUserByFullName(_managerName);

                }

                return null;

            }

        }

 

        public String ManagerName

        {

            get { return _managerName; }

        }

 

 

        private ADUserDetail(DirectoryEntry directoryUser)

        {

 

            String domainAddress;

            String domainName;

            _firstName = GetProperty(directoryUser, ADProperties.FIRSTNAME);

            _middleName = GetProperty(directoryUser, ADProperties.MIDDLENAME);

            _lastName = GetProperty(directoryUser, ADProperties.LASTNAME);

            _loginName = GetProperty(directoryUser, ADProperties.LOGINNAME);

            String userPrincipalName = GetProperty(directoryUser, ADProperties.USERPRINCIPALNAME);

            if (!string.IsNullOrEmpty(userPrincipalName))

            {

                 domainAddress = userPrincipalName.Split('@')[1];

            }

            else

            {

                domainAddress = String.Empty;

            }

 

            if (!string.IsNullOrEmpty(domainAddress))

            {

                domainName = domainAddress.Split('.').First();

            }

            else

            {

                domainName = String.Empty;

            }

            _loginNameWithDomain = String.Format(@"{0}\{1}", domainName, _loginName);

            _streetAddress = GetProperty(directoryUser, ADProperties.STREETADDRESS);

            _city = GetProperty(directoryUser, ADProperties.CITY);

            _state = GetProperty(directoryUser, ADProperties.STATE);

            _postalCode = GetProperty(directoryUser, ADProperties.POSTALCODE);

            _country = GetProperty(directoryUser, ADProperties.COUNTRY);

            _company = GetProperty(directoryUser, ADProperties.COMPANY);

            _department = GetProperty(directoryUser, ADProperties.DEPARTMENT);

            _homePhone = GetProperty(directoryUser, ADProperties.HOMEPHONE);

            _extension = GetProperty(directoryUser, ADProperties.EXTENSION);

            _mobile = GetProperty(directoryUser, ADProperties.MOBILE);

            _fax = GetProperty(directoryUser, ADProperties.FAX);

            _emailAddress = GetProperty(directoryUser, ADProperties.EMAILADDRESS);

            _title = GetProperty(directoryUser, ADProperties.TITLE);

            _manager = GetProperty(directoryUser, ADProperties.MANAGER);

            if (!String.IsNullOrEmpty(_manager))

            {

                String[] managerArray = _manager.Split(',');

                _managerName = managerArray[0].Replace("CN=", "");

            }

        }

 

 

        private static String GetProperty(DirectoryEntry userDetail, String propertyName)

        {

            if (userDetail.Properties.Contains(propertyName))

            {

                return userDetail.Properties[propertyName][0].ToString();

            }

            else

            {

                return string.Empty;

            }

        }

 

        public static ADUserDetail GetUser(DirectoryEntry directoryUser)

        {

            return new ADUserDetail(directoryUser);

        }

    }

}

Step 5: Creating ADProperties class


Create or add a class in the project for ADProperties. This class will have the properties corresponding to the information of the AD User.  This is a static class. This class is having all the properties as constant string for ADUser.  This class is giving readable name to all the properties of user details.

ADProperties.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace ActiveDirectoryHelper

{

    public static class ADProperties

    {

        public const String OBJECTCLASS = "objectClass";

        public const String CONTAINERNAME = "cn";

        public const String LASTNAME = "sn";

        public const String COUNTRYNOTATION = "c";

        public const String CITY = "l";

        public const String STATE = "st";

        public const String TITLE = "title";

        public const String POSTALCODE = "postalCode";

        public const String PHYSICALDELIVERYOFFICENAME = "physicalDeliveryOfficeName";

        public const String FIRSTNAME = "givenName";

        public const String MIDDLENAME = "initials";

        public const String DISTINGUISHEDNAME = "distinguishedName";

        public const String INSTANCETYPE = "instanceType";

        public const String WHENCREATED = "whenCreated";

        public const String WHENCHANGED = "whenChanged";

        public const String DISPLAYNAME = "displayName";

        public const String USNCREATED = "uSNCreated";

        public const String MEMBEROF = "memberOf";

        public const String USNCHANGED = "uSNChanged";

        public const String COUNTRY = "co";

        public const String DEPARTMENT = "department";

        public const String COMPANY = "company";

        public const String PROXYADDRESSES = "proxyAddresses";

        public const String STREETADDRESS = "streetAddress";

        public const String DIRECTREPORTS = "directReports";

        public const String NAME = "name";

        public const String OBJECTGUID = "objectGUID";

        public const String USERACCOUNTCONTROL = "userAccountControl";

        public const String BADPWDCOUNT = "badPwdCount";

        public const String CODEPAGE = "codePage";

        public const String COUNTRYCODE = "countryCode";

        public const String BADPASSWORDTIME = "badPasswordTime";

        public const String LASTLOGOFF = "lastLogoff";

        public const String LASTLOGON = "lastLogon";

        public const String PWDLASTSET = "pwdLastSet";

        public const String PRIMARYGROUPID = "primaryGroupID";

        public const String OBJECTSID = "objectSid";

        public const String ADMINCOUNT = "adminCount";

        public const String ACCOUNTEXPIRES = "accountExpires";

        public const String LOGONCOUNT = "logonCount";

        public const String LOGINNAME = "sAMAccountName";

        public const String SAMACCOUNTTYPE = "sAMAccountType";

        public const String SHOWINADDRESSBOOK = "showInAddressBook";

        public const String LEGACYEXCHANGEDN = "legacyExchangeDN";

        public const String USERPRINCIPALNAME = "userPrincipalName";

        public const String EXTENSION = "ipPhone";

        public const String SERVICEPRINCIPALNAME = "servicePrincipalName";

        public const String OBJECTCATEGORY = "objectCategory";

        public const String DSCOREPROPAGATIONDATA = "dSCorePropagationData";

        public const String LASTLOGONTIMESTAMP = "lastLogonTimestamp";

        public const String EMAILADDRESS = "mail";

        public const String MANAGER = "manager";

        public const String MOBILE = "mobile";

        public const String PAGER = "pager";

        public const String FAX = "facsimileTelephoneNumber";

        public const String HOMEPHONE = "homePhone";

        public const String MSEXCHUSERACCOUNTCONTROL = "msExchUserAccountControl";

        public const String MDBUSEDEFAULTS = "mDBUseDefaults";

        public const String MSEXCHMAILBOXSECURITYDESCRIPTOR = "msExchMailboxSecurityDescriptor";

        public const String HOMEMDB = "homeMDB";

        public const String MSEXCHPOLICIESINCLUDED = "msExchPoliciesIncluded";

        public const String HOMEMTA = "homeMTA";

        public const String MSEXCHRECIPIENTTYPEDETAILS = "msExchRecipientTypeDetails";

        public const String MAILNICKNAME = "mailNickname";

        public const String MSEXCHHOMESERVERNAME = "msExchHomeServerName";

        public const String MSEXCHVERSION = "msExchVersion";

        public const String MSEXCHRECIPIENTDISPLAYTYPE = "msExchRecipientDisplayType";

        public const String MSEXCHMAILBOXGUID = "msExchMailboxGuid";

        public const String NTSECURITYDESCRIPTOR = "nTSecurityDescriptor";

    }

}

 

Step 6. Creating ActiveDirectoryHelper class

 

1.       This class will have all the function to perform operations to Active Directory.

2.       There are four properties in the class

LDAPPath property

This property is reading the LDAPPath from config file.

private  String LDAPPath

        {

            get

            {

                return ConfigurationManager.AppSettings["LDAPPath"];

            }

        }

 

 

LDAPUser property

 

This property is reading the LDAP user from the config file.

 

        private  String LDAPUser

        {

            get

            {

                return ConfigurationManager.AppSettings["LDAPUser"];

            }

  }

 

LDAPPassword property

This property is reading the LDAP Password from the config file.

private  String LDAPPassword

        {

            get

            {

                return ConfigurationManager.AppSettings["LDAPPassword"];

            }

        }

 

Search Root Property

This Property is initializing the Directory entry by passing the LDAPUser, LDAPPAth, and LDAPPassword.  This property is creating a new instance DirectoryEntry and returning that.

private  DirectoryEntry SearchRoot

        {

            get

            {

                if (_directoryEntry == null)

                {

                    _directoryEntry = new DirectoryEntry(LDAPPath, LDAPUser, LDAPPassword, AuthenticationTypes.Secure);

                }

                return _directoryEntry;

            }

        }

Various operations in ActiveDirectoryHelper class

Get User by Full Name

This function will take a full name as input parameter and return AD user corresponding to that.

public  ADUserDetail GetUserByFullName(String userName)

        {

            try

            {

                _directoryEntry = null;

                DirectorySearcher directorySearch = new DirectorySearcher(SearchRoot);

                directorySearch.Filter = "(&(objectClass=user)(cn=" + userName + "))";

                SearchResult results = directorySearch.FindOne();

 

                if (results != null)

                {

                    DirectoryEntry user = new DirectoryEntry(results.Path, LDAPUser, LDAPPassword);

                    return ADUserDetail.GetUser(user);

                }

                else

                {

                    return null;

                }

            }

            catch (Exception ex)

            {

                return null;

            }

        }

Get User by Login Name

This function will return AD user. This takes Login name as input parameter.

  public  ADUserDetail GetUserByLoginName(String userName)

        {

            try

            {

                _directoryEntry = null;

                DirectorySearcher directorySearch = new DirectorySearcher(SearchRoot);

                directorySearch.Filter = "(&(objectClass=user)(SAMAccountName=" + userName + "))";

                SearchResult results = directorySearch.FindOne();

 

                if (results != null)

                {

                    DirectoryEntry user = new DirectoryEntry(results.Path, LDAPUser, LDAPPassword);

                    return ADUserDetail.GetUser(user);

                }

                return null;

            }

            catch (Exception ex)

            {

                return null;

            }

        }

Get Users by from a AD Group by Group Name

This function will take a group name as input and return list of AD User in that group.

public  List<ADUserDetail> GetUserFromGroup(String groupName)

        {

            List<ADUserDetail> userlist = new List<ADUserDetail>();

            try

            {

                _directoryEntry = null;

                DirectorySearcher directorySearch = new DirectorySearcher(SearchRoot);

                directorySearch.Filter = "(&(objectClass=group)(SAMAccountName=" + groupName + "))";

                SearchResult results = directorySearch.FindOne();

                if (results != null)

                {

 

                    DirectoryEntry deGroup = new DirectoryEntry(results.Path, LDAPUser, LDAPPassword);

                    System.DirectoryServices.PropertyCollection pColl = deGroup.Properties;

                    int count = pColl["member"].Count;

 

 

                    for (int i = 0; i < count; i++)

                    {

                        string respath = results.Path;

                        string[] pathnavigate = respath.Split("CN".ToCharArray());

                        respath = pathnavigate[0];

                        string objpath = pColl["member"][i].ToString();

                        string path = respath + objpath;

 

 

                        DirectoryEntry user = new DirectoryEntry(path, LDAPUser, LDAPPassword);

                        ADUserDetail userobj = ADUserDetail.GetUser(user);

                        userlist.Add(userobj);

                        user.Close();

                    }

                }

                return userlist;

            }

            catch (Exception ex)

            {

                return userlist;

            }

 

        }

Get Users and Group by from a AD basis on starting with string

This function will return Users and Group information from AD on basis of first characters. Wild character * is used to filter the criteria. 

public  List<ADUserDetail>GetUsersByFirstName(string fName)

        {

 

            //UserProfile user;

            List<ADUserDetail> userlist = new List<ADUserDetail>();

            string filter = "";

 

            _directoryEntry = null;

            DirectorySearcher directorySearch = new DirectorySearcher(SearchRoot);

            directorySearch.Asynchronous = true;

            directorySearch.CacheResults = true;

            //directorySearch.Filter = "(&(objectClass=user)(SAMAccountName=" + userName + "))";

            filter = string.Format("(givenName={0}*", fName);

            //filter = "(&(objectClass=user)(objectCategory=person)" + filter + ")";

            filter = "(&(objectClass=user)(objectCategory=person)(givenName="+fName+ "*))";

 

 

            directorySearch.Filter = filter;

           

            SearchResultCollection userCollection = directorySearch.FindAll();

            foreach (SearchResult users in userCollection)

            {

                DirectoryEntry userEntry = new DirectoryEntry(users.Path, LDAPUser, LDAPPassword);

                ADUserDetail userInfo =  ADUserDetail.GetUser(userEntry);

 

               

                userlist.Add(userInfo);

                            }

               

                directorySearch.Filter = "(&(objectClass=group)(SAMAccountName=" +fName  + "*))";

                SearchResultCollection results = directorySearch.FindAll();

                if (results != null)

                {

 

                    foreach (SearchResult r in results)

                    {

                        DirectoryEntry deGroup = new DirectoryEntry(r.Path, LDAPUser, LDAPPassword);

                       // ADUserDetail dhan = new ADUserDetail();

                        ADUserDetail agroup = ADUserDetail.GetUser(deGroup);

                        userlist.Add(agroup);

                    }

 

                }

            return userlist;             

        }

Adding User to Active Directory Group

This function will take a user login name and add this to a group of AD.

public  bool AddUserToGroup(string userlogin, string groupName)

        {

            try

            {

                _directoryEntry = null;

                ADManager admanager = new ADManager(LDAPDomain, LDAPUser, LDAPPassword);

                admanager.AddUserToGroup(userlogin, groupName);

                return true;

            }

            catch (Exception ex)

            {

                return false;

            }

        }    

Removing User to Active Directory Group

 

This function will take a user login name and remove this to a group of AD.

    

      public  bool RemoveUserToGroup(string userlogin, string groupName)

        {

            try

            {

                                _directoryEntry = null;

                ADManager admanager = new ADManager("xxx", LDAPUser, LDAPPassword);

                admanager.RemoveUserFromGroup(userlogin, groupName);

                return true;

            }

            catch (Exception ex)

            {

                return false;

            }

        }

 

In above two functions ADManager class is being used for adding and removing user in AD.

ADManager.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.DirectoryServices.AccountManagement;

 

namespace ActiveDirectoryHelper

{

    public class ADManager

    {

 

        PrincipalContext context;

 

        public ADManager()

        {

            context = new PrincipalContext(ContextType.Machine, "xxx", "xxx", "xxx");

           

        }

 

       

        public ADManager(string domain, string container)

        {

            context = new PrincipalContext(ContextType.Domain, domain, container);

        }

 

        public ADManager(string domain, string username, string password)

        {

            context = new PrincipalContext(ContextType.Domain, username, password);

        }

 

        public bool AddUserToGroup(string userName, string groupName)

        {

            bool done = false;

            GroupPrincipal group = GroupPrincipal.FindByIdentity(context, groupName);

            if (group == null)

            {

                group = new GroupPrincipal(context, groupName);

            }

            UserPrincipal user = UserPrincipal.FindByIdentity(context, userName);

            if (user != null & group != null)

            {

                group.Members.Add(user);

                group.Save();

                done = (user.IsMemberOf(group));

            }

            return done;

        }

 

       

        public bool RemoveUserFromGroup(string userName, string groupName)

        {

            bool done = false;

            UserPrincipal user = UserPrincipal.FindByIdentity(context, userName);

            GroupPrincipal group = GroupPrincipal.FindByIdentity(context, groupName);

            if (user != null & group != null)

            {

                group.Members.Remove(user);

                group.Save();

                done = !(user.IsMemberOf(group));

            }

            return done;

        }

    }

}

 

This is the way all the operation could be perform on the AD.

Complete code for ActiveDirectoryHelper.cs class

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.DirectoryServices;

using System.Configuration;

 

namespace ActiveDirectoryHelper

{

    public  class ActiveDirectoryHelper

    {

        private  DirectoryEntry _directoryEntry = null;

 

        private  DirectoryEntry SearchRoot

        {

            get

            {

                if (_directoryEntry == null)

                {

                    _directoryEntry = new DirectoryEntry(LDAPPath, LDAPUser, LDAPPassword, AuthenticationTypes.Secure);

                }

                return _directoryEntry;

            }

        }

 

        private  String LDAPPath

        {

            get

            {

                return ConfigurationManager.AppSettings["LDAPPath"];

            }

        }

 

        private  String LDAPUser

        {

            get

            {

                return ConfigurationManager.AppSettings["LDAPUser"];

            }

        }

 

        private  String LDAPPassword

        {

            get

            {

                return ConfigurationManager.AppSettings["LDAPPassword"];

            }

        }

 

        private  String LDAPDomain

        {

            get

            {

                return ConfigurationManager.AppSettings["LDAPDomain"];

            }

        }

 

        internal  ADUserDetail GetUserByFullName(String userName)

        {

            try

            {

                _directoryEntry = null;

                DirectorySearcher directorySearch = new DirectorySearcher(SearchRoot);

                directorySearch.Filter = "(&(objectClass=user)(cn=" + userName + "))";

                SearchResult results = directorySearch.FindOne();

 

                if (results != null)

                {

                    DirectoryEntry user = new DirectoryEntry(results.Path, LDAPUser, LDAPPassword);

                    return ADUserDetail.GetUser(user);

                }

                else

                {

                    return null;

                }

            }

            catch (Exception ex)

            {

                return null;

            }

        }

 

        public  ADUserDetail GetUserByLoginName(String userName)

        {

            try

            {

                _directoryEntry = null;

                DirectorySearcher directorySearch = new DirectorySearcher(SearchRoot);

                directorySearch.Filter = "(&(objectClass=user)(SAMAccountName=" + userName + "))";

                SearchResult results = directorySearch.FindOne();

 

                if (results != null)

                {

                    DirectoryEntry user = new DirectoryEntry(results.Path, LDAPUser, LDAPPassword);

                    return ADUserDetail.GetUser(user);

                }

                return null;

            }

            catch (Exception ex)

            {

                return null;

            }

        }

 

 

        /// <summary>

        /// This function will take a DL or Group name and return list of users

        /// </summary>

        /// <param name="groupName"></param>

        /// <returns></returns>

        public  List<ADUserDetail> GetUserFromGroup(String groupName)

        {

            List<ADUserDetail> userlist = new List<ADUserDetail>();

            try

            {

                _directoryEntry = null;

                DirectorySearcher directorySearch = new DirectorySearcher(SearchRoot);

                directorySearch.Filter = "(&(objectClass=group)(SAMAccountName=" + groupName + "))";

                SearchResult results = directorySearch.FindOne();

                if (results != null)

                {

 

                    DirectoryEntry deGroup = new DirectoryEntry(results.Path, LDAPUser, LDAPPassword);

                    System.DirectoryServices.PropertyCollection pColl = deGroup.Properties;

                    int count = pColl["member"].Count;

 

 

                    for (int i = 0; i < count; i++)

                    {

                        string respath = results.Path;

                        string[] pathnavigate = respath.Split("CN".ToCharArray());

                        respath = pathnavigate[0];

                        string objpath = pColl["member"][i].ToString();

                        string path = respath + objpath;

 

 

                        DirectoryEntry user = new DirectoryEntry(path, LDAPUser, LDAPPassword);

                        ADUserDetail userobj = ADUserDetail.GetUser(user);

                        userlist.Add(userobj);

                        user.Close();

                    }

                }

                return userlist;

            }

            catch (Exception ex)

            {

                return userlist;

            }

 

        }

 

        #region Get user with First Name

 

        public  List<ADUserDetail>GetUsersByFirstName(string fName)

        {

 

            //UserProfile user;

            List<ADUserDetail> userlist = new List<ADUserDetail>();

            string filter = "";

 

            _directoryEntry = null;

            DirectorySearcher directorySearch = new DirectorySearcher(SearchRoot);

            directorySearch.Asynchronous = true;

            directorySearch.CacheResults = true;

                        filter = string.Format("(givenName={0}*", fName);

            //            filter = "(&(objectClass=user)(objectCategory=person)(givenName="+fName+ "*))";

 

 

            directorySearch.Filter = filter;

           

            SearchResultCollection userCollection = directorySearch.FindAll();

            foreach (SearchResult users in userCollection)

            {

                DirectoryEntry userEntry = new DirectoryEntry(users.Path, LDAPUser, LDAPPassword);

                ADUserDetail userInfo =  ADUserDetail.GetUser(userEntry);

 

                                userlist.Add(userInfo);

               

            }

               

                directorySearch.Filter = "(&(objectClass=group)(SAMAccountName=" +fName  + "*))";

                SearchResultCollection results = directorySearch.FindAll();

                if (results != null)

                {

 

                    foreach (SearchResult r in results)

                    {

                        DirectoryEntry deGroup = new DirectoryEntry(r.Path, LDAPUser, LDAPPassword);

                      

                        ADUserDetail agroup = ADUserDetail.GetUser(deGroup);

                        userlist.Add(agroup);

                    }

 

                }

            return userlist;             

        }

 

        #endregion

 

 

        #region AddUserToGroup

        public  bool AddUserToGroup(string userlogin, string groupName)

        {

            try

            {

                                _directoryEntry = null;

                ADManager admanager = new ADManager(LDAPDomain, LDAPUser, LDAPPassword);

                admanager.AddUserToGroup(userlogin, groupName);

                return true;

            }

            catch (Exception ex)

            {

                return false;

            }

        }

        #endregion

 

        #region RemoveUserToGroup

        public  bool RemoveUserToGroup(string userlogin, string groupName)

        {

            try

            {

                _directoryEntry = null;

                ADManager admanager = new ADManager("xxx", LDAPUser, LDAPPassword);

                admanager.RemoveUserFromGroup(userlogin, groupName);

                return true;

            }

            catch (Exception ex)

            {

                return false;

            }

        }

        #endregion

    }

}

반응형
반응형

원문 : http://www.rkttu.com/326 (남정현님 블로그)

 

Visual Studio, 특히 Windows Forms 기반 프로젝트를 진행하면서, 사용자 정의 컴포넌트나 사용자 정의 컨트롤을 개발할 때 쉽게 파악하기 힘든 사항 중에 하나가 현재 로드된 컴포넌트나 컨트롤이 디자인 타임 위에서 실행 중인지 런타임 위에서 실행 중인지를 파악하는 것입니다. 저 또한 이 문제 때문에  많은 고민과 테스트를 수행해보았습니다만 시원치 않은 결과들 뿐이었습니다.

 

그러다가 결론을 하나 구했고 다음과 같은 내용들입니다.

 

  • Component.DesignMode 속성은 Component.Site 속성이 null 참조가 아니고, 지정된 Site 객체의DesignMode 속성을 읽어서 반환하는 것이므로 큰 의미는 없습니다.
  • Component.Site 속성이 null 참조를 반환하는지 검사하는 방법은 논리적인 오류가 내포되어있을 가능성이 있습니다. 무조건 이런 검사를 사용하면, 디자인 타임이 아니면서도 Site 속성을 이용할 때 문제가 발생할 수 있습니다.
  • 외국 포럼의 자료를 검색한 결과 System.ComponentModel.LicenseManager 클래스의 UsageMode 속성을 이용하는 방법을 찾을 수 있었습니다. 이 속성은, LicenseManager 클래스의 Context 객체가 null 참조가 아니고, 해당 객체의 UsageMode 속성 값을 반환하는 것이며, null 참조일 경우 런타임으로 이해합니다.
  • Site 속성에 비해 훨씬 목적이 분명하고 제한적이므로 Site 속성을 이용한 판정보다는 안전한 선택이라고 예상됩니다.
  • 다만, 초기에 컴포넌트나 컨트롤의 생성자 단계에서만 유효한 정보이므로 이 때 캐치하지 못하면 디자인 타임 위인지 런타임 위인지 판정하지 못한채 런타임으로 인지하고 실행해버리므로 별도의 변수에 보관할 필요가 있습니다.

그 결과 아래와 같이 코드를 구성할  있었습니다.

 

public class MyComponent : Component

{

    private readonly bool inDesign;

    public MyComponent()

    {

         // 중략

         this.inDesign = (LicenseManager.UsageMode == LicenseUsageMode.Design);

    }
}

 

디자인 타임  만들어진 객체의 유효 기간은, Visual Studio에서 디자인 타임 편집 창을 닫기 전까지이므로 싱글턴 패턴을 이용하지 않는다면 만들어질 여러 MyComponent 객체 간의 간섭 효과는 걱정하지 않아도 될 것입니다.


반응형
반응형


상당히 오랫만에 블로그에 글을 올리는 듯 합니다.

진행중인 프로젝트이며, 이것 저것 벌려놓은 것이 많다보니..

아무래도 블로그에 소홀하게 될 수 밖에 없는 것 같습니다.

 

어제 문뜩 데브피아에 답변달기 놀이를 하기 위해서 들어갔는데..

이런 질문이 있더군요.. "날씨 정보를 받아보고 싶어요."

그래서 잘 정리된 블로그가 있길래 링크를 달아주었습니다.

이곳에는 ASP.NET으로 되어 있었지만..

제 딴에는.. '어차피 Winform이건 ASP.NET이건 XML로 받아와서 파싱해서 사용하는건 같다.'

라고 생각했는데.. 저만의 오산이었나 봅니다.

대부분 이런 기능을 검색하면 ASP.NET으로 되어 있는 예제들이 수두룩 하지요.

 

혹시나 위와 같은신 분들이 계실까봐.. WinForm으로 포스팅을 해봅니다.

 

 

 

# 본 글에서 사용되는 WeatherReader클래스는 데브피아의 조동현님의 글에서 발췌하였습니다.

http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=217&MAEULNO=8&no=28438&page=2

 

 

 

 환경
 

 - Visual Studio 2008

 - .Net Framework 3.0 이상

 - WinForm with C#

 - Google API

 

 

 

 

구글에서는 날씨정보를 받아 볼 수 있는 OpenAPI를 별도로 제공해 주고 있습니다.

다음 쿼리스트링을 이용하면 날씨 정보가 담긴 XML문서를 받아볼 수 있지요.

 

http://www.google.co.kr/ig.api?weather=도시 또는 지역명

 

 서울에 대해서 받아본 XML

 

 

보이는 것처럼 이미지를 비롯한..

당일의 날씨 정보 및 해당 주(week)의 날씨에 대한 정보를 제공 받을 수 있습니다.

 

헌데.. 일부 사람들은.. Google은 크로스 도메인을 지원하지 않아서 안된다는 등..

이런 저런 이야기가 많더군요.

 

설마 그럴리가 있나요. ^^

 

그. 래. 서. 간단하게 제작해보았습니다. 현재 소스는 오늘의 날씨 정보만을 받아오는데요.

XML파싱하는 부분을 조금만 편집하면 어렵지 않게.. 주(Week) 단위의 정보도 받아올 수 있겠지요 :)

 

우선 저는 2개의 클래스를 사용했습니다.

 

하나는 예상하시는 것 처럼.. 날씨 정보를 받아와서 파싱하는 것 까지 진행해주는 클래스이며..

다른 한 클래스는 파싱된 정보를 저장할 수 있는 클래스입니다.

 

 

 WeatherReader 클래스

 구글 API를 이용하여 날씨 정보를 가져오고, 받아온 XML데이터를 파싱하는 클래스

 

 주요 메서드 : WeatherData Reading(string strCity);

                    매개변수로 지역명(영문)을 받으며,

                    해당 지역에 대해서 종합된 날씨 정보인 WeatherData의 객체를 리턴함.

 

     class WeatherReader
    {
        private string headerURL = @"http://www.google.co.kr/";

        public WeatherReader()
        {
        }

        public WeatherData Reading(string strCity)
        {
            try
            {
                WebClient wc = new WebClient();
                string buffer = wc.DownloadString(string.Format("{0}ig/api?weather={1}%20", headerURL, strCity));
                wc.Dispose();

                StringReader sr = new StringReader(buffer);
                XmlDocument doc = new XmlDocument();
                doc.Load(sr);
                sr.Close();

                XmlNode currentNode = doc.SelectSingleNode("xml_api_reply/weather/current_conditions");
                if (currentNode == null)
                    return null;

                string condition = GetNodeValue(currentNode, "condition");
                string temp_f = GetNodeValue(currentNode, "temp_f");     //화씨
                string temp_c = GetNodeValue(currentNode, "temp_c");   //섭씨
                string humidity = GetNodeValue(currentNode, "humidity");

                string wind_condition = GetNodeValue(currentNode, "wind_condition");
                humidity = humidity.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries)[1];

                return new WeatherData(LoadIcon(GetNodeValue(currentNode, "icon")), strCity, condition,

                                                   wind_condition, temp_c, humidity);
            }
            catch (Exception)
            {
                return null;
            }
        }

        private Bitmap LoadIcon(string url)
        {
            try
            {
                if (string.IsNullOrEmpty(url))
                    return null;

                WebClient wc = new WebClient();
                url = headerURL + url;
                Byte[] buffer = wc.DownloadData(url);
                wc.Dispose();
                MemoryStream ms = new MemoryStream(buffer);
                Bitmap bmp = new Bitmap(ms);
                ms.Dispose();
                return bmp;
            }
            catch
            {
                return null;
            }
        }

        private string GetNodeValue(XmlNode parent, string name)
        {
            try
            {
                XmlAttribute attr = parent.SelectSingleNode(name).Attributes["data"];
                if (attr != null)
                    return attr.Value;
                return null;
            }
            catch
            {
                return null;
            }
        }
    }

 

 

 

아래는 위에서 사용된 WeatherData클래스 입니다.

단순히 파싱된 날씨 정보를 저장하기 위한 클래스이죠..

 

 

 WeatherData 클래스

 - 그다지 분석할 필요성은 없음.

 - ToString을 사용하면 문자열로 표현된 해당 지역의 날씨 정보가 등장.

 

     class WeatherData
    {

        public Bitmap Icon { get; private set; }
        public string City { get; private set; }
        public string Condition { get; private set; }
        public string WindCondition { get; private set; }
        public string Temperature { get; private set; }
        public string Humidity { get; private set; }

        public WeatherData(Bitmap icon, string city, string condition, string wind, string temperature, string humidity)
        {
            Icon = icon;
            City = city;
            Condition = condition;
            WindCondition = wind;
            Temperature = temperature;
            Humidity = humidity;
        }

        public override string ToString()
        {
            return  City + " 날씨 정보..\r\n" + Condition + "\r\n" + WindCondition

                            + "\r\n온도:" + Temperature + ", 습도:" + Humidity;
        }
    }

 

 

 

아래는 위 클래스를 기반으로 직접 실행시켜본  것입니다.

 

 

 

 

예제 소스는 파일로 별첨합니다.

모두 유익한 개발되시길....

 

반응형
반응형

데브피아 윤성님의 팁입니다.

저는 보통 폼끼리 참조하여 사용해왔는데.. 이쪽이 훨씬 마음에 드네요.. :)

 

 

------------------- 이하 원문

 

이글을 적게되는 이유의 하나는 지속되는 질답란의 질문들이며

또 하나의 이유는 아래의 허접한 하나의  생성에 대해서 감사 댓글이 달렸기 때문이다.

 

사실상 이걸 적어볼까 하고 생각한지가 일년은 훌쩍 넘은듯 싶다.

귀찮기도 하고 별게 아닌거라서 뭐하자는 이야기인지 허접스럽기도 하고 말이다.

 

사실상 아래의 "하나의  생성"인지.. 글에 대략 이건 옳지 못합니다. 클래스 생성이 낭비됩니다등의 댓글이 달릴것이라 예측했다.

또는 openform 비교가 아닌 indexer적인 접근으로 null 비교를 하지 않는가 하는 의문이 달리지않을까 했는데.. 적어놓은 시간이 짧아서인지 그런글은 없는듯싶다.

 

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

 

Form collection 존재한다는 사실을 알고 있는이는  알고 있는데도 불구하고

사람들은 이것을 이용하지 않는듯 싶다.

(?)인지는  익숙하지 않아서 그런것이라.

MS에서는 FromCollection ControlCollection Indexer까지 구현해서  만들어 두었음에도

대부분의 경우 무식하게 Indexer 사용하지 않고 Loop 돌리거나 해서 찾는경우가 많다.

 

아래의 ( 하나생성) 또한 그런 오류를 범한것중 하나이다.

(과연 그럴까?.... 나름 이유가 있을까? 이유는  게을러서? 이지 않을까 싶다만..  죽어도 잘난척이란..)

 

Form Collection 있다는 사실 또는 이것을 이용할줄 모르는 사태로 인해서 가끔식은FrameWork이라고 만든것들은 임의로 자신의 FormCollection 구현하고 이로인해서 오히려 쉬운길을 두고 어렵게 가기도 한다.

 

기초적인것이면서 한줄짜리? 지식이라

사실 이렇게 글을 적는게 오히려 민망하기도 하고 황망스럽기도 하나..

 

몰라서 저지르는 실수들이 너무 많아서 이렇게 펜을 들어본다( 그러는 나는 알고 있을까나?)

 

일단.. 기초과정을.. 밟아 보도록 하자..

 

1. Indexer이용하기.

이렇게.. 폼을 두개를 만들자.

 

이런식으로.. 두개의 폼을.. 만들도록 하자.

Form2 닫게 하려면 어떻게 하는가?

 

Form2 닫지를 못하는 사람? 자진납세하자.(댓글함 적어다오 얼마나 많은지 파악이 안된다.)

문제의 시작은 이것이다. Form2 생성했는데 어떻게 하질 못하겠다는것이다.

Form2 생성은 이렇게 했다.

결국  문제를 해결하기 위해서.. 어떤이는?...

 

Form1 클래스의 변수로.. Xx 선언한다. 일종의 전역변수같은거 말이다.

 다른경우는 프로젝트의 자체 컬랙션에서 처리한다.

 

두가지  나쁜 방법은 아니다.

단지.. 내가 의문을 지니는것은  그럴까? 하는것뿐이다.

 

Form2 닫는건 이렇게 적으면 된다.

 

그렇다. 내가 그랬지… 한줄짜리 지식이라고..

한줄 적어주고 어지간히 아는척이 많다.

 

.. 이제는 FW 경우를 살펴보자.(FW FrameWork 준말로 사용한다. )

솔류션을 이렇게 만들고 FW에서 기준폼으로 MyForm 만들고

Form3 Myform 상속받았다고 치자.

 

요렇게 상속받음..

 

Myform  필요도 없지만.. 행여나 보여주자면..

이런식이라고 보자.

 

 이런식이 될때 FormCollection.. 과연 Form3 가질까 하는것이다.

대답은.. 모든 Form개체  상속받은것들은.. 무조건 Show할때.. FormCollection 들어간다.

그럼 반대로 Hide하면 어떻게 될까? 사라질까?

대답이 뭐일것 같은가? 귀찮아서 그냥 알려준다만.. 사라지기 전까지는 들어가 있다.

 hide 여전히 존재한다. Close 호출되어야 사라진다.

다시 강조해서 말하자면.. Show할때 들어가고..(그냥 생성한다고 들어가진 않는다.)

(여유되시면 reflection으로 show 까보면 좋겠다만..  귀차니즘의 끝은 어디에 있는지 누가 해다오)

 

하여간.. 위의 예제에서 말하고자 하는 이야기는

FW 만들더라도 굳이  컬랙션을 만들지 마라.. 피곤하다.

(말은 이렇게 하지만 대부분의 FW에서 필요하긴 하다. Form 경우 특정 영역성이 필요하게 되는데 일반적으로 기준 Form(위에서 말한 Myform) 에서 Show메세드의 오버로딩을 통해서 영역을 설정하곤 한다. / 또한 대부분의 경우 Dictionary같은 지네릭타입으로 해서 "as" 적지 않고 처리하길 원한다.)

 

이제는 FW 사용하는 이들은  의문을 가질것이다. 그럼 Myform 상속받은것은 어떻게 구분하냐고?

"is"  녀석은 그냥.. 있는게 아니다. 사용하면 될꺼 아닌가

한줄이지만. 굳이 예제를 만들기도 귀찮은 관계로.. 패스다. 모른다고 누가 손든다면... 너무한거 아냐? 라고 말하고 싶다.

 안되면 확장메서드 하나 만들어 버리던지..

 

. 이제 본론에 들어가야 하는데 폼에게 특정한 메시지를 전송한다는것 자체가 무의미한 수준까지왔다.

 이미 눈치 코치  알아버렸듯이 할것이 없다.

 

그래도 행여나 하는 맘으로 몇자  적어보자.

 

나같은 경우는 Form에서 Form으로 특정메세지나 무시기를 전달하기 위해서 SendMessage같은API 써본적은 없다. 물론 Domain 다른 Application이라면 어쩔수 없겠지만..

그런경우만..WinProc override해서 처리하면 된다.

이럴때도 광역인지 뭔가 방법이 있을법도 하다만.. 내가 모르는덕분에.. 이건  배워야 할듯 싶다.

 

계속 주제를 어긋나는데 주제에 집중하자.

하여간 나의 경우는 Interface 정의해서 사용한다.

 

심풀하게 설명해서 이렇게 인터페이스를 만들어 보자.

 

 

 그럼.. 이걸 가지고.. Form2에게 이녀석을 구현하도록 해보자.

이렇게 구현하고 나서..

 

이지의 좌측 아래에 있는 버튼을 누르면.. 이렇게 실행이 된다.

.. Form2 에게 궁극적으로 메시지를 보냈다.(물론 헛소리다.)

.. From2 매서드를 단지 실행한것에 불과하다 args넣어서.

 

소스야 앞서 이야기 했듯이 is 사용하면 된다.

 

이렇게.. 물론 이것의 응용(?)으로 앞서 이야기 했듯이  Indexer 입력받아 바로.. Is 인터페이스체크하고 실행하는 방법도 있겠다. (업무에 따라서..)

 응용은 알아서 하길 바란다. 계속 곁가지로 나가면.. 사실 적을게 너무 많다.

 

 

위와 동일한 형태지만.. Myform 에서 가지고 하는걸 보자.

(이건  필요 없을것 같다..... 그냥 대충 대충 진행하자.. 생략해도 좋다.)

FW 경우에는 이렇게 해야될것이다.

우리가 사용할 녀석에게 당연히 상속을 받아 구현하게 해야할것이다.

 

 여기서 주의깊게 봐야 하는것은 상속받고 구현하고.. 그리고 Virtual이라고 적어두는것이다.

그래야… 이녀석을 다시 상속받는 녀석들에게.. Override 할수 있도록 하기 위함이다.

아차차..  virtual앞에 public 붙쳐야되는데 얼른 적다보니  빠뜨렸다. 알아서 넣자.

 

하여간..

 

한줄짜리 기초가  이렇게 많은 글을 적어야 되는지는 .. 당연히 설명하는 능력의 부재이겠지만..

이게 나름 적기 시작하면 무지 적을게 많기도 하다.( 뻥이다. 귀찮아서 적지 않을뿐이다.)

여하튼 인터페이스에 정의하는것들로는  Clear같은거라든지.. 여타 몇몇개는 고정적으로 사용되는것들이 있는데 그런것들도 알아서 하도록 하자..

반응형
반응형

음.. 오늘 또 어느분께서 WMI를 이용해서 IP주소를 알아내는 방법에 대해서 질문하셨습니다.

그래서 간단하게.. WMI를 이용해서 IP주소를 포함한.. 다른 시스템 정보를 받아오는 방법에 대해서 알아보도록 하겠습니다.

.NET기반 에서는 System.Management 를 참조함으로써 사용할 수 있게 됩니다.

 

우선 위 클래스 사용을 위해서 참조를 추가합니다.

 

 

그리고 사용하기 원하는 파일에서

 

using System.Management;

 

간단하게 코드를 통해서 알아보도록 하겠습니다.

저는 드라이버의 Volume Serial Number, CUP ID(Processor ID), NIC카드의 On/Off여부, MAC/IP Address를 알아오는 것에 대해서 해보았습니다.

 

 

 Volume Serial Number 알아오기

 

 

        private String GetVolumeSerialNumber(String Drive)
        {
            String strVolumeSerialNumber = String.Empty;
            ObjectQuery objQuery = new ObjectQuery("SELECT VolumeSerialNumber FROM Win32_LogicalDisk WHERE Name='" + Drive + ":'");
            ManagementObjectSearcher mobjSearcher = new ManagementObjectSearcher(objQuery);

            try
            {
                foreach (ManagementObject obj in mobjSearcher.Get())
                {
                    strVolumeSerialNumber = obj["VolumeSerialNumber"].ToString();
                    break;
                }
            }
            catch(Exception e)
            {
                MessageBox.Show(e.Message);
                strVolumeSerialNumber = String.Empty;
            }

            return strVolumeSerialNumber;
        }

 

 사용예

 

String strVolumeSerial = GetVolumeSerialNumber("C"); //C드라이브의 시리얼 번호 가져오기

 

 

 

인터넷 연결 여부 가져오기

 

        private bool GetNetConnectionStatus()
        {
            return SystemInformation.Network;
        }

 

 

true = 연결됨

false = 연결안됨 

 

 

 

 

 NIC의 MAC Address 가져오기

 

 

        private String GetMACAddress()
        {
            String strMACAddress = String.Empty;

            if (GetNetConnectionStatus())
            {
                ObjectQuery objQuery = new ObjectQuery("SELECT NetConnectionStatus, MacAddress FROM Win32_NetworkAdapter");
                ManagementObjectSearcher mobjSearcher = new ManagementObjectSearcher(objQuery);

                try
                {
                    foreach (ManagementObject obj in mobjSearcher.Get())
                    {
                        if (obj["NetConnectionStatus"] != Convert.DBNull)
                        {
                            if (Convert.ToInt32(obj["NetConnectionStatus"].ToString()) == 2)
                            {
                                strMACAddress = obj["MACAddress"].ToString();
                                break;
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    MessageBox.Show(e.Message);
                    strMACAddress = String.Empty;
                }
            }

            return strMACAddress;
        }

 

 사용예

 

String strMacAddress = GetMACAddress();

 

 

 

 

 Network정보 가져오기 (IP주소)

 

현재는 IP주소만 명시했지만, 이를 이용해 Win32_NetworkAdapterConfiguration를 이용하면 Subnetmask, DefaultGateway등.. 다른 정보도 가져오거나 편집할 수 있습니다.

 

 

        private String GetIpAddress()
        {
            String strIpAddress = String.Empty;

            ObjectQuery objQuery = new ObjectQuery("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled='True'");
            ManagementObjectSearcher mobjSearcher = new ManagementObjectSearcher(objQuery);

            try
            {
                foreach (ManagementObject obj in mobjSearcher.Get())
                {
                    strIpAddress = ((String[])obj["IPAddress"])[0];
                    break;
                }
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
                strIpAddress = String.Empty;
            }

            return strIpAddress;
        }

 

 사용예

 

String strIpAddress = GetIpAddress();

 

 

간단하게 살펴보았는데요..

기본적으로 WMI라고 하여도.. 쿼리문을 이용해서 해당 정보를 조회하거나 설정하는 형태입니다.

좀 더 많은 정보를 원하시면 WQL(WMI for SQL)을 찾아 적용하시면 됩니다.

 

 

반응형
반응형

.NET 기반에서 C#으로 윈도우메세지를 핸들링하기 위해서는 WndProc를 오버라이드하여 사용하는 것으로 많이 알려져 있습니다. 하지만 .Net CF 에서는 Form클래스에 WndProc메소드가 기본적으로 존재하지 않습니다. 대신에 MessageWindow클래스를 이용하여 WndProc를 오버라이드하면 윈도우 메세지를 핸들링할 수 있도록 지원해줍니다.

 

그럼, 간단하게 폼 위에서 마우스가 이동하면, 이때 마우스 좌표값을 윈도우 메세지 형태로 날려서

이 값을 Form의 Text속성에 표시하는 예제를 함께 구현해 보도록 하지요.

 

우선 MessageWindow 클래스 사용을 위해서는 다음과 같이 참조추가를 해주어야 합니다.

 

 

사용하기 원하는 코드에서

 

using Microsoft.WindowsCE.Forms;

 

이제 MessageWindow를 사용할 수 있게 됩니다.

 

아래는 기본적으로 프로젝트 생성시에 생성되는 폼(frmMain)에서

MessageWindow를 상속받아 WndProc를 오버라이드한 클래스를 이용하는 코드입니다.

굵은 부분을 참고하면 어떤식으로 윈도우메세지를 핸들링하는지 흐름을 파악할 수 있을 겁니다.

 

frmMain 코드 - 프로젝트 생성시 생성되는 기본 폼

 

    public partial class frmMain : Form
    {
        MsgWindow MsgWin = null;

 

        public frmMain()
        {
            InitializeComponent();

            this.MsgWin = new MsgWindow(this);
        }

 

        //마우스 이동시에 메세지를 생성하여 날려주는 작업을 해주겠습니다.

        protected override void OnMouseMove(MouseEventArgs e)
        {
            Message msg = Message.Create(MsgWin.Hwnd, MsgWindow.WM_CUSTOMMSG,

                                                            (IntPtr)e.X, (IntPtr)e.Y);
            MessageWindow.SendMessage(ref msg);
            base.OnMouseMove(e);
        }

       

        //MsgWin을 통해 현재 폼에 접근할 수 있도록 메소드를 하나 정의합니다.

        public void RespondToMessage(int x, int y)
        {
            this.Text = "X = " + x.ToString() + ", Y= " + y.ToString();
        }
    }

 

 

 

 MesssageWindow를 상속받아 WndProc를 오버라이드

 

    public class MsgWindow : MessageWindow
    {
        public const int WM_CUSTOMMSG = 0x0400;

        private frmMain msgform;

 

        public MsgWindow(frmMain msgform)
        {
            this.msgform = msgform;
        }

 

        protected override void WndProc(ref Message msg)
        {
            switch (msg.Msg)
            {
                case WM_CUSTOMMSG:
                    this.msgform.RespondToMessage((int)msg.WParam, (int)msg.LParam);
                    break;
            }
            
            base.WndProc(ref msg);
        }
    }

 

반응형
반응형

Devpia, C#포럼에서 어떤 분께서 프로세스(실행중인 프로그램)에 대한 정보를 가져오는 질문에 대해서

시삽인 남정현님께서 답한 내용입니다.

 

Vista 및 7등 Windows계열에서는 권한 문제때문에 프로세스 정보를 얻어오지 못할 수 있다고 합니다.

아래 기재된 링크를 통해서 UAC권한상승에 대한 문제를 해결하고 아래 샘플코드에서 프로세스 정보에 접근하는 방법을 소개 하고 있습니다.

 

 

 

 

- 이하 원문

(http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=17&MAEULNO=8&no=116488&ref=116486&page=1#Contents116488)

 

 

다음의 샘플 코드를 참고하시면 되겠습니다. 아래 코드는, Windows Vista 이후의 운영 체제의 경우, 권한이 없기 때문에 프로세스에 대한 토큰을 열 수 없어서 사용자 이름을 가져오지 못할 수 있으며, 이를 해결하려면 해당 프로그램을 UAC 매니페스트를 지정하여 권한 상승 (Elevation) 처리를 해야 합니다. UAC 권한 상승에 대한 자세한 정보는 http://sjpison.tistory.com/68 를 참고하시면 도움될 것입니다.

 

namespace ConsoleApplication1
{
    using System;
    using System.Text;
    using System.Diagnostics;
    using System.Runtime.InteropServices;

    static class ProcessExtension
    {
        #region P/Invoke

        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle);

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool CloseHandle(IntPtr hObject);

        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern bool GetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, IntPtr TokenInformation, uint TokenInformationLength, out uint ReturnLength);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool LookupAccountSid(
            string lpSystemName,
            [MarshalAs(UnmanagedType.LPArray)] byte[] Sid,
            StringBuilder lpName,
            ref uint cchName,
            StringBuilder ReferencedDomainName,
            ref uint cchReferencedDomainName,
            out SID_NAME_USE peUse);

        #endregion // P/Invoke

        #region Constants

        [NonSerialized]
        public const uint STANDARD_RIGHTS_REQUIRED = 0x000F0000u;

        [NonSerialized]
        public const uint STANDARD_RIGHTS_READ = 0x00020000u;

        [NonSerialized]
        public const uint TOKEN_ASSIGN_PRIMARY = 0x0001u;

        [NonSerialized]
        public const uint TOKEN_DUPLICATE = 0x0002u;

        [NonSerialized]
        public const uint TOKEN_IMPERSONATE = 0x0004u;

        [NonSerialized]
        public const uint TOKEN_QUERY = 0x0008u;

        [NonSerialized]
        public const uint TOKEN_QUERY_SOURCE = 0x0010u;

        [NonSerialized]
        public const uint TOKEN_ADJUST_PRIVILEGES = 0x0020u;

        [NonSerialized]
        public const uint TOKEN_ADJUST_GROUPS = 0x0040u;

        [NonSerialized]
        public const uint TOKEN_ADJUST_DEFAULT = 0x0080u;

        [NonSerialized]
        public const uint TOKEN_ADJUST_SESSIONID = 0x0100u;

        [NonSerialized]
        public const uint TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY);

        [NonSerialized]
        public const uint TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY |
            TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE |
            TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT |
            TOKEN_ADJUST_SESSIONID);

        [NonSerialized]
        public const uint NO_ERROR = 0u;

        [NonSerialized]
        public const uint ERROR_INSUFFICIENT_BUFFER = 122u;

        #endregion // Constants

        #region Enum Values

        [Serializable]
        public enum TOKEN_INFORMATION_CLASS : uint
        {
            TokenUser = 1,
            TokenGroups,
            TokenPrivileges,
            TokenOwner,
            TokenPrimaryGroup,
            TokenDefaultDacl,
            TokenSource,
            TokenType,
            TokenImpersonationLevel,
            TokenStatistics,
            TokenRestrictedSids,
            TokenSessionId,
            TokenGroupsAndPrivileges,
            TokenSessionReference,
            TokenSandBoxInert,
            TokenAuditPolicy,
            TokenOrigin
        }

        [Serializable]
        public enum SID_NAME_USE : uint
        {
            SidTypeUser = 1,
            SidTypeGroup,
            SidTypeDomain,
            SidTypeAlias,
            SidTypeWellKnownGroup,
            SidTypeDeletedAccount,
            SidTypeInvalid,
            SidTypeUnknown,
            SidTypeComputer
        }

        #endregion // Enum Values

        #region Structures

        [Serializable]
        [StructLayout(LayoutKind.Sequential)]
        public struct TOKEN_USER
        {
            public SID_AND_ATTRIBUTES User;
        }

        [Serializable]
        [StructLayout(LayoutKind.Sequential)]
        public struct SID_AND_ATTRIBUTES
        {
            public IntPtr Sid;
            public int Attributes;
        }

        #endregion // Structures

        public static byte[] GetSIDByteArr(Process targetProcess)
        {
            int MAX_INTPTR_BYTE_ARR_SIZE = 512;
            IntPtr tokenHandle = IntPtr.Zero;
            IntPtr processHandle = IntPtr.Zero;
            byte[] sidBytes;

            try
            {
                try { processHandle = targetProcess.Handle; }
                catch { return null; }

                // Get the Process Token
                if (!OpenProcessToken(processHandle, TOKEN_READ, out tokenHandle))
                    throw new Exception("Could not get process token.  Win32 Error Code: " + Marshal.GetLastWin32Error());

                uint tokenInfoLength = 0;
                bool result;
                result = GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenUser, IntPtr.Zero, tokenInfoLength, out tokenInfoLength);  // get the token info length
                IntPtr tokenInfo = Marshal.AllocHGlobal((int)tokenInfoLength);
                result = GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenUser, tokenInfo, tokenInfoLength, out tokenInfoLength);  // get the token info

                // Get the User SID
                if (result)
                {
                    TOKEN_USER tokenUser = (TOKEN_USER)Marshal.PtrToStructure(tokenInfo, typeof(TOKEN_USER));
                    sidBytes = new byte[MAX_INTPTR_BYTE_ARR_SIZE];  // Since I don't yet know how to be more precise w/ the size of the byte arr, it is being set to 512
                    Marshal.Copy(tokenUser.User.Sid, sidBytes, 0, MAX_INTPTR_BYTE_ARR_SIZE);  // get a byte[] representation of the SID
                }
                else
                    throw new Exception("Could not get process token.  Win32 Error Code: " + Marshal.GetLastWin32Error());

                return sidBytes;
            }
            finally
            {
                if (!tokenHandle.Equals(IntPtr.Zero))
                    CloseHandle(tokenHandle);
            }
        }

        public static bool GetUserAndDomainName(Process targetProcess, string targetSystemName, out string userName, out string domainName, out int win32ErrorCode)
        {
            StringBuilder name = new StringBuilder();
            uint cchName = (uint)name.Capacity;

            StringBuilder referencedDomainName = new StringBuilder();
            uint cchReferencedDomainName = (uint)referencedDomainName.Capacity;

            SID_NAME_USE sidUse;
            byte[] sid = GetSIDByteArr(targetProcess);

            if (sid == null)
            {
                win32ErrorCode = Marshal.GetLastWin32Error();
                userName = null;
                domainName = null;
                return false;
            }

            win32ErrorCode = (int)NO_ERROR;

            if (!LookupAccountSid(targetSystemName, sid, name, ref cchName,
                referencedDomainName, ref cchReferencedDomainName, out sidUse))
            {
                win32ErrorCode = Marshal.GetLastWin32Error();

                if (win32ErrorCode == ERROR_INSUFFICIENT_BUFFER)
                {
                    name.EnsureCapacity((int)cchName);
                    referencedDomainName.EnsureCapacity((int)cchReferencedDomainName);
                    win32ErrorCode = (int)NO_ERROR;

                    if (!LookupAccountSid(targetSystemName, sid, name, ref cchName,
                        referencedDomainName, ref cchReferencedDomainName, out sidUse))
                        win32ErrorCode = Marshal.GetLastWin32Error();
                }
            }

            if (win32ErrorCode == 0)
            {
                userName = name.ToString();
                domainName = referencedDomainName.ToString();
                return true;
            }
            else
            {
                userName = null;
                domainName = null;
                return false;
            }
        }

        public static bool GetUserAndDomainName(Process targetProcess, string targetSystemName, out string userName, out string domainName)
        {
            int win32ErrorCodeToIgnore = 0;
            return GetUserAndDomainName(targetProcess, targetSystemName, out userName, out domainName, out win32ErrorCodeToIgnore);
        }

        public static bool GetUserAndDomainName(Process targetProcess, out string userName, out string domainName, int win32ErrorCode)
        {
            return GetUserAndDomainName(targetProcess, null, out userName, out domainName, out win32ErrorCode);
        }

        public static bool GetUserAndDomainName(Process targetProcess, out string userName, out string domainName)
        {
            int win32ErrorCodeToIgnore = 0;
            return GetUserAndDomainName(targetProcess, null, out userName, out domainName, out win32ErrorCodeToIgnore);
        }
    }

 

    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            foreach (Process eachProcess in Process.GetProcesses())
            {
                string imageName = eachProcess.ProcessName;
                string userName = null;
                string domainName = null;
                string result = null;

                if (ProcessExtension.GetUserAndDomainName(eachProcess, out userName, out domainName))
                    result = userName + "@" + domainName;
                else
                    result = "(Access Denied)";

                Console.WriteLine("{0} / {1}", imageName, result);
            }
        }
    }
}

 

반응형
반응형

윈폼 프로그래밍을 하다보면, 폼 이동시에 잔상이 남게 되는데요. 개발자의 입장에서 상당히 거슬리는 부분이 아닐 수 없습니다.

 

이럴때 Windows Form 2.0의 경우에는 EnableDoubleBuffering속성을 True로 변경하여 어느정도 효과를 볼 수 있다고 하네요. 또한 Windows Form 1.0의 경우는 아래 UI와 샘플 코드를 참고하여 DoubleBuffering을 구현할 수 있습니다.

 

 

 

 

 

using System;

using System.Drawing;

using System.Drawing.Drawing2D;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

 

namespace DoubleBuffer

{

  /// <summary>

  /// Summary description for Form1.

  /// </summary>

  public class Form1 : System.Windows.Forms.Form

  {

 

    private System.Windows.Forms.Timer timer1;

    private System.ComponentModel.IContainer components;

    private System.Windows.Forms.CheckBox checkBox1;

 

    float _angle;

    bool _doBuffer;

 

    public Form1()

    {

      //

      // Required for Windows Form Designer support

      //

      InitializeComponent();

 

      //

      // TODO: Add any constructor code after InitializeComponent call

      //

    }

 

    /// <summary>

    /// Clean up any resources being used.

    /// </summary>

    protected override void Dispose( bool disposing )

    {

      if( disposing )

      {

        if (components != null)

        {

          components.Dispose();

        }

      }

      base.Dispose( disposing );

    }

 

    #region Windows Form Designer generated code

    /// <summary>

    /// Required method for Designer support - do not modify

    /// the contents of this method with the code editor.

    /// </summary>

    private void InitializeComponent()

    {

      this.components = new System.ComponentModel.Container();

      this.timer1 = new System.Windows.Forms.Timer(this.components);

      this.checkBox1 = new System.Windows.Forms.CheckBox();

      this.SuspendLayout();

      //

      // timer1

      //

      this.timer1.Enabled = true;

      this.timer1.Tick += new System.EventHandler(this.timer1_Tick);

      //

      // checkBox1

      //

      this.checkBox1.Location = new System.Drawing.Point(8, 8);

      this.checkBox1.Name = "checkBox1";

      this.checkBox1.TabIndex = 0;

      this.checkBox1.Text = "Double Buffer";

      this.checkBox1.CheckedChanged += newSystem.EventHandler(this.checkBox1_CheckedChanged);

      //

      // Form1

      //

      this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);

      this.ClientSize = new System.Drawing.Size(292, 273);

      this.Controls.Add(this.checkBox1);

      this.Name = "Form1";

      this.Text = "Form1";

      this.ResumeLayout(false);

 

    }

    #endregion

 

    /// <summary>

    /// The main entry point for the application.

    /// </summary>

    [STAThread]

    static void Main()

    {

      Application.Run(new Form1());

    }

 

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

    {

      _angle+=3;

      if(_angle>359)

        _angle=0;

      Invalidate();

    }

 

    private Bitmap _backBuffer;

    

    protected override void OnPaint(PaintEventArgs e)

    {

      if(_backBuffer==null)

      {

        _backBuffer=new Bitmap(this.ClientSize.Width,this.ClientSize.Height);

      }

      

      Graphics g=null;

      if(_doBuffer)

        g=Graphics.FromImage(_backBuffer);

      else

        g=e.Graphics;

 

            g.Clear(Color.White);      

 

      g.SmoothingMode=SmoothingMode.AntiAlias;

 

      Matrix mx=new Matrix();

      mx.Rotate(_angle,MatrixOrder.Append);

      mx.Translate(this.ClientSize.Width/2,this.ClientSize.Height/2,MatrixOrder.Append);

      g.Transform=mx;

      g.FillRectangle(Brushes.Red,-100,-100,200,200);

 

      mx=new Matrix();

      mx.Rotate(-_angle,MatrixOrder.Append);

      mx.Translate(this.ClientSize.Width/2,this.ClientSize.Height/2,MatrixOrder.Append);

      g.Transform=mx;

      g.FillRectangle(Brushes.Green,-75,-75,149,149);

    

      mx=new Matrix();

      mx.Rotate(_angle*2,MatrixOrder.Append);

      mx.Translate(this.ClientSize.Width/2,this.ClientSize.Height/2,MatrixOrder.Append);

      g.Transform=mx;

      g.FillRectangle(Brushes.Blue,-50,-50,100,100);

 

      if(_doBuffer)

      {

        g.Dispose();

 

        //Copy the back buffer to the screen

 

        e.Graphics.DrawImageUnscaled(_backBuffer,0,0);

      }

 

      //base.OnPaint (e); //optional but not recommended

    }

 

    protected override void OnPaintBackground(PaintEventArgs pevent)

    {

      //Don't allow the background to paint

    }

 

    protected override void OnSizeChanged(EventArgs e)

    {

      if(_backBuffer!=null)

      {

        _backBuffer.Dispose();

        _backBuffer=null;

      }

      base.OnSizeChanged (e);

    }

 

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

    {

      _doBuffer=this.checkBox1.Checked;

    }

  }

}

반응형

'Program > C#' 카테고리의 다른 글

.NET CF에서 WndProc 사용법  (0) 2010.03.19
프로세스 정보 가져오기  (0) 2010.03.19
PictureBox에서 Image 깜빡이는 효과주기.  (0) 2010.03.19
타임 서버에서 데이터 받아오기  (0) 2010.03.19
C#에서 ActiveX 사용하기  (0) 2010.03.19
반응형

데브피아에서 어떤분이 제목과 같은 기능 구현에 대해서 물어오길래.

여러가지 방법이 있을 수 있겠지만.. 다음과 같이 구현해봤습니다.

 

Timer를 2개 선언합니다. 여기서는 Timer1, Timer2로 하겠습니다.

직접 선언하면 귀찮으니까 도구상자를 이용하세요. 그리고 Tick 이벤트에 대해서 이벤트 핸들러를 등록합니다.

 

마지막으로 Image의 객체를 하나 선언합니다.

 

 

1. 깜빡이는 효과를 주기 원하는 시점에서 첫번째 타이머를 시작하고, 픽처박스에 이미지를 올립니다.

 

2. 첫번째 타이머의 이벤트 핸들러에서 이미지를 위에 선언한 Image객체에 저장합니다.

 

3. 픽처박스의 Image속성을 null로 지정합니다. (그림이 안보이게 됩니다.)

 

3. 두번째 타이머를 시작합니다.

 

4. 두번째 타이머의 이벤트 핸들러에서 저장했던 Image객체를 픽처박스에 다시 올립고, 두번째 타이머를 멈춥니다.

 

이렇게 했을 때, 첫번째 타이머와 두번째 타이머의 인터벌만 잘 조절해주면 그럴싸하게 깜빡이는 효과를 줄 수 있습니다.

 

 

아래는 3초마다 0.3초 간격으로 깜빡이는 효과를 주는 소스입니다.

 

        private Image img = null;

 

        private void button1_Click(object sender, EventArgs e)
        {
            timer1.Interval = 3000;
            timer1.Start();
        }

 

        private void timer1_Tick(object sender, EventArgs e)
        {
            img = pictureBox1.Image;
            pictureBox1.Image = null;

 

            timer2.Interval = 300;
            timer2.Start();
        }

 

        private void timer2_Tick(object sender, EventArgs e)
        {
            pictureBox1.Image = img;
            timer2.Stop();
        }

반응형
반응형

데브피아 서생일님께서 올리신 팁&강좌 게시판에서 가져온 글입니다.

타입서버에서 표준시간을 얻어오는 방법을 제시해주고 있습니다.

 

 

 

using System;

using System.Collections.Generic;

using System.Text;

using System.IO;

using System.Net.Sockets;

 

namespace NTP_CLIENT

{

    class Program

    {

        static void Main(string[] args)

        {

            TcpClient tsc = new TcpClient("time-a.nist.gov", 13);

 

            if (tsc.Connected)

            {

                    NetworkStream ns = tsc.GetStream();

                    StreamReader sr = new StreamReader(ns);

                    string sResult = sr.ReadToEnd().Trim();

 

                    Console.WriteLine(sResult); //서버에서 받은 결과

 

                    //공백으로 결과값을 나눠서 배열에 넣음.

                    string[] saResult = sResult.Split(' ');

 

                    foreach (string s in saResult)

                    {

                        Console.WriteLine(s);

                    }

            }

            else

            {

                Console.WriteLine("-_-; 연결 안됨");

            }

        }

    }

}

반응형
반응형

우리가  ActiveX 를 사용하는 이유는 Desktop Application 과 동일한 함수, 이벤트

Properties  Web Application 에서 사용하기 위함이다.

Web Application 개발자들은 클라이언트에서 좀더 고급기능의 함수를 제공하고

싶어한다. 그것은 printing Streams, socket programming, cross domain 등등 이있다.

아래 소스에서 Asignatures 라는 interface 를 정의할것이다.

클래스는 method  properties 로 구성되어있다. 이것은 Web Browser 에서

자바스크립트를 통해 호출될 함수이다.

모든 interface 멤버는 기본적으로 abstract  public 이다.

구현한 ActiveX Class  Aclass 는 이 interface 클래스를 상속받아서 구현을 한다.

구현된 ActiveX Class  ClassInterfaceType.AutoDual 옵션을 적용했는데

이것은 COM 에서 볼수있도록 자동으로 공개되는 형식이다.


using
 System;

using System.Runtime.InteropServices;

namespace ANamespace

{

    public interface ASignatures

    {

        string FName();

        string SName();

        int Age { get;}

    }

 

    [ClassInterface(ClassInterfaceType.AutoDual)]

    public class AClass : ASignatures

    {

        public string FName()

        {

            return "Imran";

        }

        public string SName()

        {

            return "Nathani";

        }

        public int Age

        {

            get { return 24; }

        }

    }

}

 

이제 위의 소스를 컴파일 해야한다. ActiveX 이므로 라이브러리를 만드어야 되는데

csc.exe 를 이용해서 컴파일한다.

이 프로그램은 보통 \WINDOWS\Microsoft.NET\Framework\v2.0.xxxxx 위치하며

소스를 이곳에 넣고 dos command 창을 띄운후 csc /t:library ACass.cs 입력한다.


이제 생성된 dll  client register 에 등록을 해야한다.

assembly 를 등록할수 있는 방법은 여러가지인데 setup file 이나 브라우저에서 바로

설치할수 있도록 self extractor file 로 만들수 있다.

그러나 이 제는 command prompt 에서 regasm 프로그램을 이용해 등록할 것이다.

명령문은 다음과 같다.

regasm AClass.dll  /tlb  /codebase 


Html 
파일을 만들어 등록한 ActiveX 로 접근해서 사용해보자.

<html>

<head>

  <script language="javascript">

    <!-- Load the ActiveX object  -->

    var x = new ActiveXObject("ANamespace.AClass");

 

    <!-- Access the Method -->

    alert(x.FName());

    alert(x.SName());

 

    <!-- Access the Property -->

    alert(x.Age);

  </script>

</head>

<body>

</body>

</html>

 

하지만 위의 소스에 문제가 있는데 AutoDual 을 사용하지 않도록 권고하고 있다.

Auto 레이아웃 형식은 공용 언어 런타임에 의해 관리된다.

이들 형식의 레이아웃은 .NET Framework 버전 간에 변경될수 있으므로 특정 레이아웃이

필요한 COM 클라이언트에서는 문제가 발생할수 있다. StructLayoutAttribute 특성을 지정하지

않으면 C#, Visual Basic  C++  컴파일러에서 값 형식에 대하 Sequential 레이아웃으로

지정해버린다. 이규칙 위반 문제를 해결하려면 ClassInterfaceAttribute 특성의 값을

None 으로 변경하고 인터페이스를 명시적으로정의한다.

 

위와 같은 내용으로 소스를 수정하면 다음과 같다.


using
 System;

using System.Runtime.InteropServices;

namespace ANamespace

{

 

    public interface ASignatures

    {

        string FName();

        string SName();

        int Age { get;}

    }

 

    [ClassInterface(ClassInterfaceType.AutoDual)]

    public class AClass : ASignatures

    {

        public string FName()

        {

            return "Imran";

        }

        public string SName()

        {

            return "Nathani";

        }

        public int Age

        {

            get { return 24; }

        }

    }

 

    public interface IExplicitInterface

    {

        string FName();

        string SName();

        int Age { get; }

    }

 

    [ClassInterface(ClassInterfaceType.None)]

    public class BClass : IExplicitInterface

    {

        public string FName()

        {

            return "Imran";

        }

        public string SName()

        {

            return "Nathani";

        }

        public int Age

        {

            get { return 24; }

        }

    }

 

}

 

그리고 RegAsm.exe 로 레지스트리에 dll 을 추가하게 되는데 자주 쓰이는 두가지 옵션만

알면된다.

/unregister : 레지스트리에서 해제한다.

/codebase : 레지스트리에 등록한다

반응형
반응형

/// <summary>
 /// NullDateTimePicker에 대한 요약 설명입니다.
 /// </summary>
 public class NullDateTimePicker : System.Windows.Forms.DateTimePicker
 {
  private struct HANDLE
  {
   public IntPtr PtrHwnd;
   public int IdFrom;
   public int Code;
  }

  private bool isNULL;
  private string nullValue = string.Empty;
  private DateTimePickerFormat format = DateTimePickerFormat.Long;
  private string customFormat = string.Empty;
  private string formatAsString = string.Empty;


  public NullDateTimePicker() : base()
  {
   base.Format = DateTimePickerFormat.Custom;
   NullValue = "";
   Format = DateTimePickerFormat.Long;
   SetToNullValue();
  }

  public new Object Value
  {
   get
   {
    if (isNULL)  return null;
    else   return base.Value;
   }
   set
   {
    if (value == null || value == DBNull.Value)  SetToNullValue();
    else
    {
     SetToDateTimeValue();
     base.Value = (DateTime)value;
    }
   }
  }

  public new DateTimePickerFormat Format
  {
   get { return format; }
   set
   {
    format = value;
    if (!isNULL) SetFormat();
    OnFormatChanged(EventArgs.Empty);
   }
  }
 
  public new String CustomFormat
  {
   get { return customFormat; }
   set { customFormat = value; }
  }

 
  public String NullValue
  {
   get { return nullValue; }
   set { nullValue = value; }
  }

  
  private string FormatAsString
  {
   get { return formatAsString; }
   set
   {
    formatAsString = value;
    base.CustomFormat = value;
   }
  }

  private void SetFormat()
  {
   CultureInfo ci = Thread.CurrentThread.CurrentCulture;
   DateTimeFormatInfo dtf = ci.DateTimeFormat;
   switch (format)
   {
    case DateTimePickerFormat.Long:
     FormatAsString = dtf.LongDatePattern;
     break; 
    case DateTimePickerFormat.Short:
     FormatAsString = dtf.ShortDatePattern;
     break;
    case DateTimePickerFormat.Time:
     FormatAsString = dtf.ShortTimePattern;
     break;
    case DateTimePickerFormat.Custom:
     FormatAsString = this.CustomFormat;
     break;
   }
  }

  private void SetToNullValue()
  {
   isNULL = true;
   base.CustomFormat = (nullValue == null || nullValue == string.Empty) ? " " : "'" + nullValue + "'";
  }

  private void SetToDateTimeValue()
  {
   if (isNULL)
   {
    SetFormat();
    isNULL = false;
    base.OnValueChanged(new EventArgs());
   }
  }
  
  protected override void WndProc(ref Message m)
  {
   if (isNULL)
   {
    if (m.Msg == 0x4e)                       
    {
     HANDLE nm = (HANDLE)m.GetLParam(typeof(HANDLE));
     if (nm.Code == -746 || nm.Code == -722)   SetToDateTimeValue();
    }
   }
   base.WndProc(ref m);
  }

  protected override void OnKeyUp(KeyEventArgs e)
  {
   if (e.KeyCode == Keys.Delete)
   {
    this.Value = null;
    OnValueChanged(EventArgs.Empty);
   }
   base.OnKeyUp(e);
  }

  protected override void OnValueChanged(EventArgs eventargs)
  {
   base.OnValueChanged(eventargs);
  }
 }

반응형
반응형

서버에서 이미지를 연속적으로 받아와서 작업하는 부분이 있었습니다.

그래서 WebClient.DownloadFileAsync를 사용해서 이미지를 다운받았지요.

 

헌데, 첫번째 이미지는 제대로 가져오지 못하고, 두번째 이미지는 제대로 받아오는 것입니다.

도대체 어떻게 된 것인지.. 막막했습니다.

환경 및 조건을 바꾸어가며 갖가지 상황에서 테스트를 해보앗지만 결과는 동일했습니다.

 

한참을 찾아본 결과 MSDN 에 답이 있었네요.

 

MSDN 내용 입니다.

 

WebClient 인스턴스는 기본적으로 선택적 HTTP 헤더를 보내지 않습니다. 
요청에 선택적 헤더가 필요한 경우에는 헤더를 Headers 컬렉션에 추가해야 합니다. 
예를 들어, 응답에 쿼리를 포함하려면 사용자 에이전트 헤더를 추가해야 합니다. 
또한 사용자 에이전트 헤더가 없으면 서버에서 500(내부 서버 오류)을 반환할 수 있습니다.

 

즉, 윈도우 서버나 리눅스 서버나 안되는 다운로드가 안되는 경우 아래와 같이 하시면 됩니다.

 

 

WClient = new System.Net.WebClient();

 

WClient.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)");


이 한줄로 고생 많이 했네요.

MSDN 에서와 같이 헤더가 추가 안되어 넘어오는 경우

500(내부서버오류)를 반환합니다.

즉, 파일명만 있는 0 byte 가 저장만 되는 거죠.

 

헤더 추가 하시면 다운로드가 잘 됩니다.

반응형
반응형

C#을 이용해서.. 간단하게 키보드의 한글값과 영문값을 매치시키는 방법을 고민고민하다가..

아래와 같이 해결하였습니다. 혹여 더 좋은 방법 있으신 분은 피드백 부탁드립니다. ^^;

이를테면.. "가나다"라고 입력하면 "rkskek" 이런식으로 저장되게 말이죠.

사실.. 이 부분은.. 여러모로 찾아보았으나, 달리 특별한 방법으로 해결한 것은 아닙니다.

 

아래와 같이 매치시킬 수 있는 테이블을 직접 만듭니다. 좀 무식하죠... ^^;

 

Dictionary<Char, Char> DicKey = new Dictionary<Char, Char>();

DicKey.Add('ㅁ', 'a');

DicKey.Add('ㅠ', 'b');

.

.

.

DicKey.Add('ㅋ', 'z');

 

이런식으로 만들어 두고..

한글을 입력받았을때..

 

Char eng = DicKey['ㅁ'];

 

eng의 결과는 'a'가 됩니다. ^^;

반응형
반응형

완전샤푸님의 블로그에서 발췌하였습니다.

눈에 보이는 괜찮은 팁이 몇 가지 있네요. ^^

 

 

 

- Form

 

 

1. MDI 폼의 경우 자식 폼에 MDI 부모 품을 설정 하는 방법
// 자식 폼의 생성자에서 부모 폼의 인스턴스를 넘겨 주어 설정하도록 한다.

public ChildForm( MainForm frm )

{

        InitializeComponent();


        this.MdiParent = frm;

……….

}





2. 다이얼로그 폼 사용

LogInForm frm = new LogInForm();

frm.StartPosition = FormStartPosition.CenterScreen;  // 다이얼로그 폼을 중심으로 이동

frm.ShowDialog();

                     

if( DialogResult.OK == frm.DialogResult )

{

      ………………………………………

}







- 컨트롤



1. 리스트, 리스트뷰 컨트롤



- 컬럼 지정

: 리스트 및 리스트 뷰 컨트롤의 컬럼을 프로그래밍으로 지정 할 수 있지만 디자인 모드에서 더욱 쉽게

추가 할 수 있다. 예는 리스트 뷰로 하지만 리스트 컨트롤과 방법은 같다.

리스트 뷰 컨트롤을 지정한다.


속성 창에서 ‘Colummns’ 속성을 클릭 한다.



‘ColumnHeader 컬렉션 편집기가 나타난다.


여기서 컬럼을 추가 하기 위해 ‘추가’버튼을 누르면 오른쪽에 속성을 주는 부분이 나온다. 컬럼명과 넓이 등을 지정하면 된다.

* 프로그래밍적 방법
ListView.Columns.Add( "이름", 40, HorizontalAlignment.Center );





- 데이터 모두 삭제
ListView.Items.Clear();




- 데이터 추가

ListViewItem lvi = new ListViewItem();

lvi.SubItems.Add( “최흥배” );

lvi.SubItems.Add( “프로그래머팀” );

lvi.SubItems.Add( “서버파트” );

ListView.Items.Add( lvi );

ListView.Refresh(); 




- 데이터 추가 2

: 위의 방식은 컬럼의 첫번째가 이미지 리스트인 경우는 좋지만 리스트 뷰의 첫 컬럼에 어떤 문자를

나타내고 싶은 경우는 되지 않는다. 이런 경우 ListVieeItem의 생성자의 인자에 첫 컬럼에 나타내고 싶은

문자를 지정해 줘야 한다.

ListViewItem lvi = new ListViewItem( iCount.ToString() );

lvi.SubItems.Add( “최흥배” );

lvi.SubItems.Add( “프로그래머팀” );

lvi.SubItems.Add( “서버파트” );

ListView.Items.Add( lvi );

ListView.Refresh(); 




- 삽입된 모든 데이터 순회
int iItemNum = ListView.Items.Count;

for( int i = 0; i < iItemNum; ++i )

{

        iYear = Convert.ToInt32(ListView.Items[i].SubItems[ 0 ].Text ); 

        ………..

|




- 기존 데이터 수정

……….

ListView.Items[i].SubItems[ 0 ].Text = iYear.ToString();

……..




- 특정 데이터 삭제 ( 순회 방법을 foreach를 사용함 )

………

foreach( ListViewItem lvi in ListView.Items )

{

        if( lvi.SubItems[ 0 ].Text == “2005” )

               ListView.Items.Remove( lvi );

}

…………




- 리스트 뷰의 특정 행을 선택한 경우 알고 싶을 때
ListView.SelectedListViewItemCollection  Items = ListView.SelectedItems;


// 리스트 뷰의 컨트롤 속성이 멀티 선택 가능 상태에서 복수 개 선택을 하였다면 선택된 것이 다 나온다.
foreach( ListViewItem lvi in Items )

{

…….

}





2. 콤보 박스


- 콤보 박스의 데이터 모두 삭제

: combobox.Items.Clear();




- 데이터 추가

: combobox.Items.Add( “LIFEOnline” );




- 목록 중 지정된 데이터 목록을 찾아서 선택 되도록 하기

int index = combobox.Items.IndexOf(“LIFEOnline” );

if( index < 0 )

return;


combobox.SelectedIndex = index;







3. 그리드 컨트롤


- 그리드 컨트롤을 실행 시 데이터 추가

DataGrid grid = new DataGrid();

DataTable dt = new DataTable();

DataRow dr;



// 컬럼 헤드를 추가

dt.Columns.Add( new DataColumn("아이템", typeof(string)) );

dt.Columns.Add( new DataColumn("Code", typeof(Int32)) );

                                

// 레코드 추가                                 

dr = dt.NewRow();

   

dr[ 0 ] = “칼”;  // 아이템 컬럼에 아이템 이름 추가

dr[ 0 ] = 110;    // 코드 컬럼에 코드 번호 추가

                                

dt.Rows.Add(dr);  // 레코드를 추가 한다.



DataView dv = new DataView(dt); // 데이터 뷰를 만든다.

grid.DataSource= dv;               // 그리드 컨트롤에 추가



- 그리드 컨트롤의 컬럼 스타일 지정

그리드 컨트롤에 데이터를 넣르면 컬럼이 지멋대로 되는 경우가 있다.. 이럴 때 원하는 스타일로

컬럼을 지정하면 된다..다만 꼭 데이터를 다 넣은 후에 해야 된다. 그전에 하면 데이터를 넣으면서
원하지 않는 상태로 변경되어 버린다.

…………………………………………………………….

DataGridTableStyle gtStyle1 = new DataGridTableStyle();  



gtStyle1.GridColumnStyles.Add(new DataGridTextBoxColumn());

gtStyle1.GridColumnStyles[0].MappingName = “아이템”; // 이 이름이 컬럼 스타일을 바꾸기를 원하는 컬럼의

                                                                          // 텍스트와 꼭 같아야 된다.

gtStyle1.GridColumnStyles[0].HeaderText = “아이템”;    // 컬럼의 텍스트를 지정한다.

gtStyle1.GridColumnStyles[0].Alignment = HorizontalAlignment.Center; // 중간 정렬

gtStyle1.GridColumnStyles[0].Width = 70;                               // 폭 지정

gtStyle1.GridColumnStyles[0].NullText = string.Empty;




gtStyle1.GridColumnStyles.Add(new DataGridTextBoxColumn());

gtStyle1.GridColumnStyles[0].MappingName = “Code”;    // 이 이름이 컬럼 스타일을 바꾸기를 원하는 컬럼의

                                                                 // 텍스트와 꼭 같아야 된다.

gtStyle1.GridColumnStyles[0].HeaderText = “Code”;       // 컬럼의 텍스트를 지정한다.

gtStyle1.GridColumnStyles[0].Alignment = HorizontalAlignment.Center; // 중간 정렬

gtStyle1.GridColumnStyles[0].Width = 70;                               // 폭 지정

gtStyle1.GridColumnStyles[0].NullText = string.Empty;



grid.TableStyles.Add(gtStyle1);            // 그리드 컨트롤에 세팅 한다.

……………………………………………………………..










- ADO.NET

1. 오라클 DB 연결

string strCommonConnection = “Data Source=ORA10;User ID=admin;assword=1111”;

OracleConnection OraCommonDBConnt = new OracleConnection( strCommonConnection );

OraCommonDBConnt.Open();




2. 오라클 DB 끊기

if( ConnectionState.Open == OraCommonDBConnt.State  )

        OraCommonDBConnt.Close();




3. DataSet을 사용한 쿼리 작업

OracleDataAdapter OraDataAdapter = new OracleDataAdapter();

OracleCommand cmd = new OracleCommand();

cmd.Connection = OraCommonDBConnt;

cmd.CommandText = “SELECT * FROM Member”;

OraDataAdapter.SelectCommand =  cmd;

OraDataAdapter.Fill( ResultDataSet , strTableName );




4. DataReader를 사용한 쿼리 작업

OracleDataAdapter OraDataAdapter = new OracleDataAdapter();

OracleCommand cmd = new OracleCommand();

cmd.Connection = OraCommonDBConnt;

cmd.CommandText = “SELECT * FROM Member”;

DataReader outDataReader = cmd.ExecuteReader();

               

if( false == outDataReader.HasRows )

return false;


………….

// 원하는 필드의 인덱스 번호를 알아낸다.

int IndexDex   = outDataReader.GetOrdinal("Dex");

…………..




while( dataReader.Read() )

{

   …………………..

    CharInfo.DEX = outDataReader.GetInt32( IndexDex );

   ……………….

}




5. 테이블의 데이터 모두 삭제

string strContext = "DELETE FROM " + TableName;

OracleCommand cmd = new OracleCommand();

cmd.Connection = OraCommonDBConnt;

cmd.CommandText = strContext;

cmd.ExecuteNonQuery();




6. DataSet의 내용을 DataGrid 컨트롤에 넣기

GridQueryResult.SetDataBinding( ResultDataSet, strTableName );




7. 간단하게 DataSet을 이용한 테이블의 데이터 갱신

// 이전에 쿼리 작업을 한 DataAdapter를 사용해야 된다. 그렇지 않을 경우 DataAdapter에 업데이트 및 삭제 로직을

// 등록 해줘야 된다.

// 이 작업은 쿼리를 하여 DataGrid 컨트롤에 넣은 경우 DataGrid의 데이터를 수정 한 후 이 내용을 DB에 업데이트

// 하고 싶을 때 사용한다.

OracleCommandBuilder cb = new OracleCommandBuilder( OraDataAdapter ); 

cb.RefreshSchema();

OraDataAdapter.Update( dataset, TableName );




8. DataSet의 내용을 XML 파일로 저장

DataSet ds = new DataSet();

……….

ds.WriteXml( filename );
// 이후 위의 7번 방식을 이용해서 데이터를 추가 한다.

……





9. 테이블의 모든 데이터를 지우고 XML의 데이터를 추가 하기

// 테이블의 레코드를 모두 지운다.

……….

// ds 라는 DataSet에서 XML 파일을 읽어 들인다.

DataSet ds = new DataSet();

ds.ReadXml( textBoxFilePath.Text );










- 파일



1. 클래스 단위로 파일에 쓰기

이 직렬화 방식은 꼭 .NET 플랫폼에서 서로 파일을 읽고 쓸 때만 사용 가능하다.
만약 .NET으로 만든 프로그램에서 아래와 같이 파일을 만들고 이것을 네이티브에서

읽으면 앞에 다른 값이 들어가 있다( 정확하게는 직렬화 되는 클래스의 메타 정보가

들어가 있다 ).


FileStream GloveFile = new FileStream( "0.ipt", FileMode.Create);

BinaryFormatter formatter = new BinaryFormatter();

formatter.Serialize( GloveFile, ItemFileclass );





2. 현재 실행 하고 있는 프로그램의 실행 경로 얻기

Environment.CurrentDirectory

를 이용하면 실행 경로를 얻을 수 있다.







- 네트워크

1. 웹에 있는 파일을 받기

정확하게 말하면 http 프로토콜을 이용하여 웹에 있는 파일을 다운로드 하는 방식을 말한다.

WebRequest myWebRequest = WebRequest.Create("http://jacking75.cafe24.com/Index.hml"); 

WebResponse myWebResponse = myWebRequest.GetResponse(); 



Stream ReceiveStream = myWebResponse.GetResponseStream();



ReceiveStream 객체를 파일 스트림을 이용하여 파일로 저장 하던가 다른 스트림으로 사용하면 된다.








- ETC



1. C#에서의 XML 주석 코드 제작을 위한 주석 작성 요령

: public bool IsEnableExecute( int iReqList )
{

    …………

}

가 있다면 

/// <summary>

/// 현재 수행하는 기능을 수행 가능한가

/// <summary>

/// <param name="iReqList">수행할 기능의 인덱스</param>

/// <returns name="true">수행가능</returns> 

/// <returns name="false">수행불능</returns>

public bool IsEnableExecute( int iReqList )
{

    …………

}

이렇게 작성한다.




2. 다른 클래스에 있는 const로 정의한 상수를 이용 방법
: 상수는 다음과 같이 정의 되어 있다.

public class PacketDefine 

{

   Public const int Packet_First = 0;

   ………..

}



이것을 Command 클래스에서 사용 할려면

…………

Int packetfirst = PacketDefine.Packet_First;

………….


사용한다. 




3. 데이터 변환.

: 데이터 변환을 위해서는 Convert의 멤버를 사용한다.

Convert.Toxxx( xxx )를 사용하면 된다. 
예) 스트링을 int 변환
Convert.ToInt32( string );




3. 바이트 배열을 지정된 위치와 크기로 복사할 경우
: Buffer.BlockCopy( ……. );




4. 클래스의 크기를 알고 싶을 때

: Marshal.SizeOf(LoginPacket)

LoginPacket는 인스턴스 화된 객체이어야만 한다. LoginPacket의 클래스인 LOGIN_PACKET를 사용하면 안된다.




5. 외부 프로그램 실행

: 여기서 인터넷 익스플로어를 실행해서 본인의 홈페이지에 가는 것을 예를 들겠다.

System.Diagnostics.Process IEProcess = new System.Diagnostics.Process();

IEProcess.StartInfo.FileName = "iexplore.exe";

IEProcess.StartInfo.Arguments = "http://jacking75.cafe24.com ";

IEProcess.Start();



6. 메시지 박스

- 일반 메시지 박스 사용

MessageBox.Show( "클라이언트에서 사용할 스킬 정보를 파일로 저장 하겠습니까 ?" );



- YES / NO 버튼 사용

if( DialogResult.Yes == MessageBox.Show( "클라이언트에서 사용할 스킬 정보를 파일로 저장 하겠습니까 ?",

                                                            "이진 파일 저장", MessageBoxButtons.YesNo ) )



7. 한글 파일 출력 문제

- 정확한 이유는 모르지만 한글을 파일에 입력할 때 인코딩을 Default 방식으로 지정하면

한글 XP에서는 한글을 아스키 코드 값으로 제대로 인식하지만 윈도우 2003에서는 한글을

유니코드 방식으로 인식하여 한글 1글자를 아스키 코드 1글자로 인식하는 경우가 있다.


string strValue = “개”;

encodedBytes = System.Text.Encoding.Default.GetBytes(strValue);         



한글 XP에서 읽는다면 encodedBytes의 길이가 2개로 나오지만 윈도우 2003에서는

길이가 1로 된다.



이 문제를 해결할려면 인코딩 방식을 명시적으로 지정해야 된다.

string strValue = “개”;

encodedBytes = System.Text.Encoding.GetEncoding(949).GetBytes(strValue);




8. 폼의 마우스 커서 변경

- 화살표 마우스 커서      this.Cursor = Cursors.Arrow;

- 모래시계 커서                this.Cursor = Cursors. WaitCursor;

- 손 커서                         this.Cursor = Cursors. Hand;

- 기본 커서                      this.Cursor = Cursors. Default;

등등…….




9. 네이티브의 time(&time_t)에서 얻은 초단위의 시간을 C#에서 사용

- time함수를 이용하여 얻은 시간은 시작이 1970년부터이고 C#의 경우는

0년 1월1일 부터이다..그래서 서로 호환이 되지 않느다. 이것을 해결할려면

다음과 같이 하면 된다.



int iTime = C타임함수값;    
DateTime dt = new DateTime(1970, 1, 1, 9, 0, 0); // 한국은 GMT+9시간
dt = dt.AddSeconds(iTime);

반응형
반응형

지금까지 C#에서 메모리를 복사 하기 위해서 unsafe를 사용해서 포인터를 이용해서 메모리 복사를 하거나, 네이티브 코드를 dll import하여 사용했는데.. 검색해보니 지원되는 클래스가 있네요. ^^;

 

 


사용되는 클래스 : System.Buffer

 

static void Main(string[] pArg)    

{    

  byte[]   aSrc   = new byte[10];   // source buffer 를 생성합니다.    

  // source buffer 에 데이터를 담습니다.    

  aSrc   = Encoding.ASCII.GetBytes(string.Format("Test").ToCharArray());    

  byte[]   aDest  = new byte[10];   // destination buffer 를 생성합니다.    

  Buffer.BlockCopy(aSrc, 0, aDest, 0, aSrc.Length);    

}   


 BlockCopy 는 Array 인터페이스를 구현한 모든 클래스에 사용이 가능합니다.

또한.. Array.Copy와 차이를 여쭤보시는 분들이 계시기에 간단하게 이야기하자면..

BlockCopy가 Array.Copy에 비하여 약 2배 가까이 빠른 성능을 보입니다. (테스트 완료)

반응형
반응형


C#으로 제작된 FTP 클래스입니다.

첨부된 소스파일를 다운로드 하고, 프로젝트에 포함시킵니다.

 

 

사용하기 원하는 코드에서..

 

using FTP;

 

해주시고.

 

 

FTPclient 클래스를 사용하여 파일을 다운로드/업로드/삭제 하거나

디렉토리를 생성/삭제/탐색 할 수 있습니다.

 

메소드명이 명시적이니 쉽게 사용할 수 있을 것입니다.

반응형
반응형

데브피아 C#마을 조동현님께서 올리신 팁입니다.

개인 라이브러리에 추가해서 유용하게 잘 사용하고 있습니다.

 

아래 내용을 참고하면 아래와 같은 메세지 박스를 생성할 수 있습니다.

 

 

 

    using System;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;

    public class MessageBoxEx
    {
        delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr SetWindowsHookEx(int hook, HookProc callback, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll")]
        static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll")]
        static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll")]
        static extern IntPtr GetDlgItem(IntPtr hDlg, DialogResult nIDDlgItem);

        [DllImport("user32.dll")]
        static extern bool SetDlgItemText(IntPtr hDlg, DialogResult nIDDlgItem, string lpString);

        [DllImport("kernel32.dll")]
        static extern uint GetCurrentThreadId();

        static IntPtr g_hHook;

        static string yes;
        static string cancel;
        static string no;

 

        /// <summary>
        /// 메시지 박스를 띠웁니다.
        /// </summary>
        /// <param name="text">텍스트 입니다.</param>
        /// <param name="caption">캡션 입니다.</param>
        /// <param name="yes">예 문자열 입니다.</param>
        /// <param name="no">아니오 문자열 입니다.</param>
        /// <param name="cancel">취소 문자열 입니다.</param>
        /// <returns></returns>
        public static DialogResult Show(string text, string caption, string yes, string no, string cancel)
        {
            MessageBoxEx.yes = yes;
            MessageBoxEx.cancel = cancel;
            MessageBoxEx.no = no;
            g_hHook = SetWindowsHookEx(5, new HookProc(HookWndProc), IntPtr.Zero, GetCurrentThreadId());
            return MessageBox.Show(text, caption, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
        }

        static int HookWndProc(int nCode, IntPtr wParam, IntPtr lParam)
        {
            IntPtr hChildWnd;

            if (nCode == 5)
            {
                hChildWnd = wParam;

                if (GetDlgItem(hChildWnd, DialogResult.Yes) != null)
                    SetDlgItemText(hChildWnd, DialogResult.Yes, MessageBoxEx.yes);

                if (GetDlgItem(hChildWnd, DialogResult.No) != null)
                    SetDlgItemText(hChildWnd, DialogResult.No, MessageBoxEx.no);

                if (GetDlgItem(hChildWnd, DialogResult.Cancel) != null)
                    SetDlgItemText(hChildWnd, DialogResult.Cancel, MessageBoxEx.cancel);

                UnhookWindowsHookEx(g_hHook);
            }
            else
                CallNextHookEx(g_hHook, nCode, wParam, lParam);

            return 0;
        }
    }

 

엄청난 DllImport와 static이지요...

 

ex)

MessageBoxEx.Show("정지 하시겠습니까?", "정지", "야스", "노노", "취소닷!");

 

반응형
반응형

참조 추가 Microsoft Internet Controls(SHDocVw)와 Microsoft.mshtml 를 하고

 

using System.Runtime.InteropServices;

using SHDocVw;
using mshtml;

한다.

 

그 후

 

InternetExplorer ex = new InternetExplorer();      
ex.Visible = true;
Object obj = null;

ex.Navigate("http://cyworld.com", ref obj, ref obj, ref obj, ref obj);

 

위와 같이 익스플로러를 실행시키고 (싸이월드로)

굳이 익스플로러가 아니더라도.. WebBrowser를 사용하셔도 됩니다.

 

private void button3_Click(object sender, EventArgs e)
        {
            IHTMLDocument2 hd;
            hd = (IHTMLDocument2)ex.Document;
            IHTMLElementCollection hCollection = (IHTMLElementCollection)hd.all;
            object obj = "input";                    //input 태그 찾으려고
            IHTMLElementCollection he = (IHTMLElementCollection)hCollection.tags(obj);
            foreach (IHTMLElement helem in he)
            {
                if (helem.getAttribute("name", 0) != null)
                {
                    if (helem.getAttribute("name", 0).ToString() == "email")    //소스를 보고 name속성의 값을 적는다, 아이디 항목
                    {
                        helem.setAttribute("value", (Object)"아이디", 0);       //value 속성에 아이디를 대입
                    }

                    if (helem.getAttribute("name", 0).ToString() == "passwd")
                    {
                        helem.setAttribute("value", (Object)"비밀번호", 0);
                    }
                }
            }
        }

 

 

반응형
반응형

최근 메신저를 만들다가..

쪽지를 수신하는 부분에서... 다른 곳에서 작업을 하고 있을 때..

쪽지가 도착하면 포커스가 빼앗기는 상황이 발생하더군요.

포커스를 빼앗기면 안되는데 말이죠..

 

이를테면 쪽지를 쓰고 있는데.. 쪽지가 도착하면 새로운 폼이 등장하게 되면서..

포커스를 빼앗기는 것 입니다.

 

이 부분을 해결하는데 생각보다 꾀 많은 시간이 투자되었네요.

 

일단 발견한 방법은 2가지 입니다.

 

1. Win32API를 사용한다.

2. ShowWithoutActivation 프로퍼티를 상속받아서 Child Form Class를 구현한다.

 

그럼 차례대로 소개하도록 하겠습니다. 그리 어렵지 않습니다.

 

 

1. Win32 API - ShowWindow함수 사용

 

//아래 처럼 user32.dll을 dll import합니다.

[System.Runtime.InteropServices.DllImport("user32.dll")]

public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

 

//그리고 아래처럼 사용하시면 되겠습니다.

RecvMemoWnd memo = new RecvMemoWnd (strTitle, strContent, strTime, strSender);

ShowWindow(memo .Handle, WM_SHOWNOACTIVATE); //WM_SHOWNOACTIVATE = 4

 

 

2. 닷넷 - ShowWithoutActivation를 오버라이드하는 Child Form Class

 

public class Test : Form

{

   bool showWithoutActivation = false;

   protected override bool ShowWithoutActivation

   {

      get

      {

         return showWithoutActivation;

      }
   }

 

   public void Show(bool activate)

   {

      showWithoutActivation = !activate;

      Show();
   }
}

 

<-------------------------------------------------------------------->

 

Test test = new Test();

test.Show(false);

 

 

어렵지 않네요. 다만 자료가 많이 않아서 시간이 조금 걸렸을 뿐...

반응형
반응형

요즘 프로젝트가 진행중인데..

.net이 막강하다고는 하지만 상용프로그램을 개발하다보니 어쩔 수 없이 WinAPI를 사용하게 될 수 밖에 없더군요. 예전에 API공부할 때는 정말 답답하고 그랬었는데, 참 유용하게 써먹게 되는 것 같습니다. 실제로 C#에서도 아래와 같은 방법으로 WinAPI를 그대로 사용할 수 있습니다. SetWindowPos()를 사용하기 위해서 검색하다가 데브피아에 정리가 잘된 자료가 있어서 가져왔습니다.

첨부된 파일은 HOONS 닷넷의 박세희님이 제공해주신 자료로 자주 사용하는 WinAPI를 정리하여 둔 것입니다. 얼핏봐도 자주쓰는 함수들이 많이 보이네요.. ^^

 

C#에서 Win32 API 사용하기

개요

Win32 API를 불러올 때, 함수의 명칭, 인자, 리턴 값을 가지고 불러오게 되어 있다. 하지만, C#에서 타입들이 모두 객체(Object)의 형식이며, 일반적인 C 의 데이터 형과 상이한 모양을 가진다. 이러한 문제들을 해결할 수 있는 것이 PInvoke 기능이다.

PInvoke( Platform Invocation Service)는 관리화 코드에서 비관리화 코드를 호출할 방법을 제공한다. 일반적인 용도는 Win32 API의 호출을 위해 사용한다.

namespace PinvokeExample

{

using System;

             using System.Runtime.InteropServices; // 반드시 입력해야 한다.

             public class Win32

             {

                           [DllImport(“user32.dll”)]

                           public static extern int FindWindow(string a, string b);

                           

             }

}

위 예제는 FindWindow라는 user32.dll C함수를 사용하는 모습을 보여주고 있다. 실제 FindWindow의 선언은 다음과 같다.

             HWND FindWindow(LPCSTR swClassName, LPCSTR swTitle);

HWND는 윈도우 핸들을 표현하는 32비트 정수 이므로, int형으로 치환되고 LPCSTR 형은 NULL로 끝나는 문자열을 표현한다. 이때 PInvoke string을 자동으로 LPCSTR로 치환해 주는 역할을 하게 된다.

이 문서에서는 이처럼 Win32 API 함수의 여러 유형들을 어떻게 C#에서 사용 할 것인지에 대하여 알아보자.

WIN32 데이터형의 치환

Win32 API에서 일반적으로 사용하고 있는 데이터형은 모두 C#의 데이터 형으로 치환될 수 있다.

Win32 API TYPE

C#

BOOL, BOOLEAN

bool

BYTE

byte

CALLBACK

delegate

COLORREF

int

DWORD

int

DWORD_PTR

long

DWORD32

uint

DWORD64

ulong

FLOAT

float

HACCEL

int

HANDLE

int

HBITMAP

int

HBRUSH

int

HCONV

int

(모든 HANDLE 타입) Hxxxx

int

LPARAM

long

LPCSTR

[in] string [out] StringBuilder

LPBOOL

ref bool

이외 LP* 

ref 형식

UINT

uint

Uxxxx

unsigned 타입들..

WORD

Short

WPARAM

Uint

Structure 의 전달

예를 들어 POINT 형의 경우,

typedef struct t_Point {

             int x;

             int y;

} POINT;

이것은 기본적으로 다음과 같이 선언될 수 있다.

[순차적]

[StructLayout(LayoutKind.Sequential)]
public struct Point {
      public int x;
      public int y;
}

[명시적]

[StructLayout(LayoutKind.Explicit)]
public struct Point {
      [FieldOffset(0)] public int x;
      [FieldOffset(4)] public int y;
}

일차적으로 할당되는 메모리 레이아웃이 동일하다면, C#에서 바로 받아 들이 수 있다.

// BOOL SetWindowPos(POINT pos); 이런 함수가 있다고 가정하면… ^^

[DllImport (“user32.dll”)]

public static extern bool SetWindowPos(Point pos);

사용할 함수 이름 바꾸기

여기서 함수의 이름을 바꿔서 사용하고 싶다면 다음과 같이 변경하면 된다.

// BOOL SetWindowPos(POINT pos);

[DllImport (“user32.dll”, EntryPoint = “SetWindowPos”)]

public static extern bool ShowAt(Point pos);

레퍼런스형 전달하기

LPPOINT형은 POINT의 포인터 형이므로 ref Point와 같이 사용 할 수 있다. 실제 사용하는 형식은 다음과 같다.

C 언어의 포인터의 경우 레퍼런스로 사용하려고 하면, ref 키워드를 사용하는 방법이 있다.

// BOOL SetWindowPos(HWND hWnd, LPRECT lpRect);

[DllImport(“user32.dll”)]

public static extern bool SetWindowPos(int hWnd, ref Rect lpRect);

Out형 함수 인자 사용하기

MSDN 같은 곳에서 함수의 선언을 살펴보면 다음과 같은 형식의 함수를 볼 수 있을 것이다. 이러한 형식은 레퍼런스 형으로 결과를 함수의 인자에 보내겠다는 말이다. 이러한 형식은 Win32 API에서 많이 쓰이고 있고, 포인터를 사용하므로, 많은 주의를 기울여야 한다.

BOOL GetWindowRect(
  HWND hWnd,      // handle to window
  LPRECT lpRect   // window coordinates
);

Parameters

hWnd

[in] Handle to the window.

lpRect

[out] Pointer to a RECT structure that receives the screen coordinates of the upper-left and lower-right corners of the window.

여기서 LPRECT는 앞 절에서 설명한 Structure의 전달을 참고하여 치환 될 수 있다.

여기서 lpRect RECT의 포인터이며, GetWindowRect 함수 내에서 이 포인터에 직접 값을 쓰게 되어 있다.즉 이 포인터는 값을 기록하기 위한 인자이지, 값을 전달하기 위한 인자는 아닌 것이다. 이것은 또 다른 C#레퍼런스 연산자인 out 키워드를 사용하여 쉽게 해결 할 수 있다.

public static extern bool GetwindowRect(int hWnd, out Rect lpRect);

실제 사용하는 모습은 다음과 같다.

public static extern bool GetWindowRect(int hWnd, out Rect lpRect);

public static void UseFunction() {

        Rect _rect; // 값을 대입하지 않아도 된다.

        Win32.GetWindowRect(hwnd, out _rect);

}

참고로 ref 키워드는 입력과 출력 둘 다 사용 할 수 있다. 그러나 ref를 사용하는 변수가 값이 설정되어 있다는 가정을 하고 있으므로, 이전에 반드시 어떠한 값을 입력해야 한다.

실제 사용 예는 다음과 같다.

public static extern bool GetWindowRect(int hWnd, ref Rect lpRect);

public static void UseFunction() {

        Rect _rect = new Rect(); // 꼭 값을 대입해야 한다.

       

        _rect.top = 20; _rect.left = 30;

        _rect.bottom = 50; _rect.right = 60;

        Win32.GetWindowRect(hwnd, ref _rect);

}

여기서 잠깐

대중없이 Rect라는 구조체가 나오는데 이는 API에서 RECT형을 C#으로 바꾸어 사용하는 structure이다. 앞의 예제들은 다음과 같은 선언을 하였다고 가정한다.

[StructLayout(LayoutKind.Explicit)]
public struct Point {
      [FieldOffset(0)] public int top;
[FieldOffset(4)] public int left;
[FieldOffset(8)] public int bottom;
[FieldOffset(12)] public int right;

}

CALLBACK 함수의 선언

C 언어에서 콜백 함수는 함수 포인터로 존재하게 된다. 이것은 함수 인스턴스의 포인터로, 함수 자체를 전달하게 되는 방식이다. 대표적으로 사용되는 부분은 EnumWindows 함수이다.

// BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARMAM IParam)

이 함수는 현재 열려 있는 모든 윈도우 핸들을 열거하기 위한 함수로 실제 처리하는 부분은 함수 포인터, 즉 콜백함수인 lpEnumFunc에서 처리하게 되어 있다. WNDENUMPROC 타입의 선언은 다음과 같다.

// typedef BOOL (CALLBACK* WNDENUMPROC)(HWND, LPARAM);

public delegate bool Callback(int hWnd, long lParam);

이러한 콜백 함수 역할을 하는 C#의 프리미티브는 delegate이다. CALLBACK delegate로 지환된다.

결과적으로 다음과 같이 사용하게 된다.

namespace ada.appshare

{

             public delegate bool Callback(int hwnd, int lParam);

             

             internal class Win32

             {

                

                           internal static extern int EnumWindows(CallBack x, int y);

                           [DllImport("user32.dll")]

                public static bool EnumWindowsCallback(int hWnd, int lParam)
                {

                        System.Console.WriteLine(“” + hWnd);

                        return true;

                }

                 

             }

        public static void Main(String []args)

        {

                Win32.Callback call
= new Win32.Callback(Win32.EnumWindowsCallback);

                Win32.EnumWindows(call, 0);

        }

}

반응형
반응형

using System.Runtime.InteropServices;
using Microsoft.Win32;

// ---- ini 파일 의 읽고 쓰기를 위한 API 함수 선언 ----
[DllImport("kernel32.dll")]
private static extern int GetPrivateProfileString(    // ini Read 함수
            String section,
            String key,
            String def,
            StringBuilder retVal,
            int size,
            String filePath);

[DllImport("kernel32.dll")]
private static extern long WritePrivateProfileString(  // ini Write 함수
            String section,
            String key,
            String val,
            String filePath);

 

/// ini파일에 쓰기

public void G_IniWriteValue(String Section, String Key, String Value, string avsPath)

{
    WritePrivateProfileString(Section, Key, Value, avsPath);
}

 

/// ini파일에서 읽어 오기

public String G_IniReadValue(String Section, String Key, string avsPath)

{

    StringBuilder temp = new StringBuilder(2000);

    int i = GetPrivateProfileString(Section, Key, "", temp, 2000, avsPath); 

 

    return temp.ToString();

}

반응형
반응형

1:1 음성대화 기능을 구현을 위해서 검색하다가 발견했습니다.

깔끔하게 정리가 잘 되어 있네요.

저 같은 경우는 DriectPlay만 사용하면 되겠네요. ^^

아래 링크에서 Direct X SDK를 다운로드 하실 수 있습니다.

 

다운로드 : http://www.microsoft.com/downloads/details.aspx?FamilyID=08c586cd-ca80-4391-82af-5c4125dedb7f&DisplayLang=en


 

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

 

 

원문 : http://kin.naver.com/detail/detail.php?d1id=1&dir_id=10115&eid=VnHbfGFZuJA/Ymvjr6uhVPpr4b6FhJY2&qb=QyMgRGlyZWN0UGxheQ==&pid=fh3I2soi5U4sssbZKR0sss--239596&sid=SY36z-KhjUkAAGX8ydM

 

 

 

▶ C# 에서 DirectX 이 의미하는 것은?


C#, Visual Basic.NET, C++ managed Extensions, JScript .NET 과 같은 .NET 기반의 언어를 통해서 Managed DirectX 를 이용하여 멋진 그래픽 기반의 프로그램을 만들 수 있습니다.


즉, .NET 프레임워크를 기반으로 하는 DirectX 라고 보시면 됩니다. 그래서 용어를 Managed DirectX 라고 합니다. 원래 .NET 프레임워크를 바탕으로 작성된 코드를 관리되는 (managed) 코드라고 하듯, DirectX 도 그렇게 불립니다.


현재는 Managed DirectX 코드 예제는 DirectX August 2007 SDK 버전까지만 지원됩니다. 그 이후로 나오는 DirectX November 2007 SDK 이나 DirectX March 2008 SDK에서는 더 이상 Managed DirectX 코드 예제나 문서를 찾아볼 수 없다는 것입니다.


저의 짧은 생각으로는, 마이크로소프트가 XNA Framework 를 적극 지원하려고 MDX (Managed DirectX) 를 소홀히 하는 것은 아닌가 하는 생각도 들구요.


아쉬운 대로, 최신(?) 버전의 DirectX SDK 인 DirectX August 2007 SDK 를 설치한다고 가정하겠습니다.


▶ C# 에서 Managed DirectX 를 사용하는 것은?


C# 은 .NET 프레임워크를 지원하는 언어이므로, 모든 작업은 간단하게 진행됩니다.


기존의 unmanaged (.NET 프레임워크에서 관리하지 않고 플랫폼(Win32 등) 에서 제공하는 API 등으로 만들어진 것을 managed 와 대조하여 부릅니다) 언어인 VC++ 프로젝트로 DirectX 라이브러리를 설정하고 링크하는 것에 비해 매우 간단해 졌다고 볼 수 있습니다.


[그림 1]을 보면 usingMDX 라는 이름의 프로젝트를 Windows 응용 프로그램 형식으로 생성했습니다. 여기서 사용한 개발툴은 Microsoft Visual Studio 2005입니다.


[그림 1] Visual C#에서 Windows 응용 프로그램 프로젝트 usingMDX 생성하기


화면 왼쪽에 배치되어 있는 솔루션 탐색기를 살펴보면 참조가 있습니다.


[그림 2] 를 보겠습니다.


[그림 2] 솔루션 탐색기


참조에 마우스 오른쪽 버튼을 눌러 나오는 메뉴의 참조 추가를 선택하면 [그림 3] 과 같은 창이 뜹니다.


[그림 3] 참조 추가 윈도우


여기에 .NET 탭의 Managed DirectX 참조 라이브러리를 추가시켜주면, 프로젝트에서 간단하게 MDX 를 사용할 수 있게 됩니다.


기존의 VC++ 에 비하면 매우 간단해졌다고 볼 수 있다.


기본적으로 [그림 4]처럼 3개의 라이브러리를 추가하면 되겠습니다.

 


[그림 4] Managed DirectX 를 프로젝트에 추가하는데 필요한 대표적인 라이브러리


확인 버튼을 누르고 다시 솔루션 탐색기 참조를 살펴보면 [그림 5]처럼 변경되었음을 알 수 있습니다.


[그림 5] 추가된 라이브러리


추가된 라이브러리의 구성요소는 해당 개체를 더블클릭하여 개체 라이브러리에서 살펴볼 수 있습니다.


이제 소스 코드에 이 라이브러리의 네임스페이스를 적어두면 편리하게 사용할 수 있습니다.


using Microsoft.DirectX;

using Microsoft.DirectX.Direct3D;


▶ Managed DirectX 의 네임스페이스는 무엇을 나타내나요?


[표 1]을 보시면 각 네임스페이스의 개요를 나타냈습니다.


자세한 사항은 DirectX SDK 문서를 참조하시면 되겠습니다.


[표 1] Managed DirectX 의 네임스페이스 개요

Microsoft.DirectX

부모 네임스페이스로서, 모든 공통된 코드를 포함한다.

Microsoft.DirectX.Direct3D

Direct3D 그래픽 API 와 D3DX 도우미 라이브러리

Microsoft.DirectX.DirectDraw

DirectDraw 그래픽 API

Microsoft.DirectX.DirectPlay

DirectPlay 네트워킹 API => DirectX SDK March 2008 보면 이제 지원안한다고 함

Microsoft.DirectX.DirectSound

DirectSound 오디오 API.

Microsoft.DirectX.DirectInput

DirectInput 사용자 입력 API.

Microsoft.DirectX.AudioVideoPlayback

간단한 오디오와 비디오 플레이백 API

Microsoft.DirectX.Diagnostics

간단한 진단용 API


▶ 이제 코딩은 어떻게 하나요?


VC++ 로 코딩을 해 본적이 있다면, 유사하게 할 수 있답니다.


자세한 사항은 DirectX SDK 문서를 참조하시면 되겠습니다.

반응형
반응형

C#으로 요즘 한참 무엇인가를 만들고 있다.

텍스트와 이미지를 함께 출력해야하는 부분이 있어서 RichTextBox를 사용하였다..

그런데 이것이 왠 일인가.. 한글이 마구마구 깨져서 출력이 된다.

예를 들어 "한글"이라고 입력하면 "ㅎㅏㄴ그ㄹ" 이런식으로 입력이 되는 것이다.

 

RichTextBox는 말 그대로 TextBox보다 더 풍부한 기능을 지원해주는 윈폼 컨트롤이다.

그런데 이 녀석.. 한글에게는 인색하다.

 

아마 위처럼 한글이 깨짐의 문제때문에 이 글을 보고 있다면..

RichTextBox의 이벤트 처리시에 분명히.. Text.Length 속성을 사용했을 것이다.

이를 해결하기 위해서는 TextLength 속성을 이용하면 되겠다.

Text의 Length 프로퍼티가 아닌... RichTextBox의 TextLength 속성을 사용하면 된다..

이 것때문에 오늘도 시간이 상당히 허비되었다.

 

C언어 때부터 존재하던 문제라고 하던데..... 아직까지 해결이 안되있는걸 보면.. 가슴이 쓰라리다.

그리고 추가적이 한 가지 알게된 것이 있는데..

KeyPress이벤트는 발생하지 않으니.. 대신에 다른 Key이벤트를 사용하는 것이 좋다는 것.

반응형

+ Recent posts

반응형