윈도우 앱개발을 향하여

블로그 이미지
윈도우 10 스토어에 앱을 개발해 올리는 것을 목표로 하고 있습니다. 비전공자가 독학으로 시도하는 일이어서 얼마나 걸릴지 모르겠지만... 아무튼 목표는 그렇습니다!!
by 코딩하는 경제학도
  • Total hit
  • Today hit
  • Yesterday hit

    C#은 객체 지향 패러다임(object-orientation paradigm)을 풍부하게 구현하는 형식에 안전한 범용 객체 지향 프로그래밍 언어이다. 객체 지향 패러다임에는 캡슐화(encapsulation), 상속(inheritance), 다형성(polymorphism)이 포함된다. 캡슐화는 객체(object) 주변에 경계선을 만들어 객체의 외부(공개) 행동과 내부(비공개) 구현 세부사항을 분리하는 것을 뜻한다.


- 통합된 형식 체계

C# 프로그램의 근본적인 구축 요소는 소위 형식(type)이다. 형식은 자료와 함수들을 하나의 단위로 캡슐화한 것으로 C#은 하나의 통합된 형식 체계(unified type system)을 갖추고 있다. 이 체계에서 모든 형식은 궁극적으로 하나의 공통 기반 형식을 공유한다. (== 모든 형식은 동일한 기본 기능 집합을 가지고 있다.)


- 클래스와 인터페이스

C#은 클래스 말고도 여러 종류의 형식이 있다. 그 중 하나가 인터페이스이다. 인터페이스는 다중 상속이 필요한 경우 유용하다.


- 속성, 메서드. 이벤트

C#에서 메서드(method)는 속성(property)과 이벤트(event)를 비롯한 여러 함수 멤버(function member) 중 하나일 뿐이다. 속성은 객체의 상태 일부를 캡슐화하는 함수 멤버이고 이벤트는 객체의 상태가 변했을 때 수행할 동작을 단순화해주는 함수 멤버이다.



    C#은 객체 지향 뿐 아니라 함수형 프로그래밍에서도 영향을 받았다.

- 함수를 값으로 취급할 수 있다.

대리자(delegate)를 이용하면 함수를 값으로서 다른 함수에 전달하거나 돌려받을 수 있다.


- 순수형 패턴을 지원한다.

함수형 프로그래밍의 핵심은 값이 변하는 변수보다는 선억신(declarative) 패턴을 사용하는 것이다. C#에는 람다 표현식(lambda, 익명 함수를 즉석에서 작성)과 질의 표현식(query expression, 목록(list) 또는 반응식(reactive) 프로그래밍을 수행), 불변이 형식(immutable, 읽기 전용 형식) 등과 같은 기능을 지원한다.


    C#은 정적 형식 적용(static typing)을 지원함으로써 형식에 안전한(type-safe) 언어이다(강한 형식 적용 언어, 형식에 매우 엄격, 컴파일 타임과 런타임에서의 형식 안전성 강제). 강한 형식 적용은 C# 코드를 sandbox(보안의 모든 측면을 호스트가 제어하는 환경) 안에서 실행하는 능력에도 중요하다.

(dynamic 키워드로 일부 코드 형식을 동적으로 결정하는 것도 가능하다.)


    C#은 런타임에 의존해서 메모리를 자동으로 관리함다. CLR(Common Language Runtime, 공용 언어 런타임)에는 프로그래머가 작성한 프로그램의 일부로서 실행되는 쓰레기 수거기(garbage collector)가 있다. 이 수거기는 더 이상 참조되지 않는 객체들의 메모리를 재확보한다. (객체의 메모리 해제 의무 없어짐, 포인터 관련 문제 사라짐) (성능을 위해 포인터를 사용한다면 unsafe 블럭에서만 가능하다.)


- C#과 CLR의 관계

C#은 자동 메모리 관리와 예외 처리 같은 다양한 기능을 갖춘 런타임에 의존한다. C#의 설계는 해당 실행시점 기능들을 제공하는 마소 CLR설계와 밀접하게 대응한다(기술적으로는 C#과 CLR은 독립적이지만). 게다가 C#의 형식 시스템은 CLR의 형식 체계와 밀접하게 대응된다.


- CLR과 .NET Framework

.NET Framework는 CLR과 아주 다양한 라이브러리들의 집합으로 구성되어 있다. CLR은 관리되는 코드(managed code)를 실행하기 위한 런타임이다. C#은 여러 관리되는 언어 중 하나인데, 관리되는 언어로 작성한 소스 코드를 컴파일하면 관리되는 코드가 생성된다. 관리되는 코드를 실행 파일 또는 라이브러리 형태로 만들고 그것을 형식정보(메타자료)와 함께 하나의 패키지로 묶은 것을 어셈블리라고 부른다.


관리되는 코드는 중간 언어(intermediate language, IL)로 표현된다. 어셈블리를 적재할 때 CLR은 어셈블리에 담긴 IL코드를 해당 컴퓨터 고유의 기계어 코드로 변환한다. 이러한 변환을 담당하는 것이 CLR의 JIT(just-in-time)컴파일러이다.






AND

Getting Information About the Contents of a Folder (MSDN 번역)


지난 Getting a Folder's ID에서는 namespace object의 PIDL(pointer to an item identifier list)를 구하는 두 가지 접근방법(approaches)을 알아보았다. 그렇다면 PIDL을 얻은 뒤 이것으로 무엇을 할 수 있을까? A related question is: What if neither approach works, or is suitable for your application? The answer to both questions requires taking a closer look at how the namespace is implemented. The key is the IShellFolder interface.


목차

Using the IShellFolder Interface 

Enumerating the Contents of a Folder

Determining Display Names and Other Properties 

Getting a Pointer to a Subfolder's IShellFolder Interface  

Determining an Object's Parent Folder



- Using the IShellFolder Interface


이전 설명에서 namespace 폴더들을 object로 언급했다. 맞는 말이다, namespace 폴더는 COM(Component Object Model) object로 대표되기 때문이다. 각 folder object는 다양한 업무에 사용되는 많은 인터페이스를 노출시킨다(expose). 어떤 인터페이스는 선택가능해서 모든 폴더들이 노출시키지는 않지만, 모든 폴더는 반드시 IShellFolder라는 fundamental한 인터페이스를 노출시켜야만 한다(따라서 언제나 접근가능하다). 


Folder object를 사용하기 위한 첫 단계는 해당 폴더 object의 IShellFolder 인터페이스의 포인터를 얻는 것이다. Object의 다른 인터페이스를 제공하는 함수들을(methods) IShellFolder가 가지고 있다. 그 중 몇가지는 여기서 소개될 것이다.


IShellFolder 인터페이스의 포인터를 얻기 위해선 반드시 SHGetDesktopFolder함수를 호출해야한다. 이 함수는 namespace root(Desktop)의 IShellFolder 인터페이스를 가리키는 포인터를 반환한다. 일단 Desktop의 IShellFolder 인터페이스를 얻으면 그 다음부터는 다양한 방법으로 진행할 수 있다.


만약 관심있는 폴더의 PIDL을 이미 가지고 있다면(SHGetFolderLocation함수를 호출해서 얻었다던가..), 그 폴더의 IShellFolder 인터페이스를 Desktop의 IShellFolder::BindToObject method를 호출하여 얻을 수 있다.

만약 관심있는 폴더가 파일 시스템 object이고 그 경로를 알고 있다면 Desktop의 IShellFolder::ParseDisplayName method를 호출하여 해당 폴더의 PIDL을 얻을 수도 있다. 

만약 위의 두 가지 방법을 모두 사용할 수 없다면 다른 IShellFolder method로 해당 namespace를 탐색할 수도 있다. (Navigating the Namespace 참조)



- Enumerating the Contents of a Folder


관심있는 폴더에 무엇이 포함되어 있는지 보기 위해서는 해당 폴더의 IShelFolder::EnumObjects method를 호출해야만 한다. 그러면 해당 폴더는 standard OLE enumeration object를 만들고 그것의 IEnumIDList 인터페이스를 반환한다. IEnumIDList 인터페이스는 Clone, Next, Reset, Skip 이라는 네 개의 인터페이스를 노출시키며 관심 폴더의 내용물을 열거하는데 사용된다. 그 과정은 다음과 같다.

  1. 해당 폴더의 IShellFolder::EnumObjects method를 호출하여 a pointer to an enumeration object's IEnumIDList interface를 얻는다.
  2. IEnumIDList::Next에 unallocated PIDL를 넘긴다. IEnumIDList::Next가 PIDL의 메모리를 할당한다. 그리고 IEnumIDList::Next가 반환하면 PIDL는 object's item ID와 terminating NULL characters를 담고있다(single-level PIDL, relative to the folder, not a fully qualified PIDL).
  3. IEnumIDList::Next가 내용물이 모두 열거되었음을 알리는 S_FALSE를 반환할 때까지 2단계를 반복한다.
  4. IEnumIDList::Release를 호출하여 enumeration object를 해제한다.
Note  It is important to keep track of whether you are working with a full or relative PIDL. Some functions and methods will accept either, but others will only take one or the other.


나머지 세 개의 IEnumIDList method(Reset, Skip, Clone)도 폴더의 내용물을 반복해서 열거할 때 유용하다. (They allow you to reset the enumeration, skip one or more objects, and make a copy of the enumeration object to preserve its state.)



- Determining Display Names and Other Properties


일단 폴더에 포함된 모든 PIDLs를 열거했다면 그것들이 어떤 종류의 object인지 알아낼 수도 있다. IShellFolder 인터페이스는 쓸모있는 메소드들을 많이 포함하고 있으며 그 중 몇가지를 여기서 소개한다.


One of the most useful properties is the object's display name. 해당 object의 PIDL를 IShellFolder::GetDisplayNameOf에 넘기면 object의 display name을 얻을 수 있다. 해당 object가 namespace의 부모폴더에 포함되어 있기 때문에 해당 object의 PIDL은 반드시 부모폴더와 연관되어 있다.


In addition to its display name, an object can have a number of attributes, such as whether it is a folder or whether it can be moved. You can retrieve an object's attributes by passing its PIDL to IShellFolder::GetAttributesOf. The complete list of attributes is quite large, so you should see the reference for details. Note that the PIDL that you pass to GetAttributesOf must be single-level. In particular, IShellFolder::GetAttributesOf will accept the PIDLs returned by IEnumIDList::Next. You can pass in an array of PIDLs, and GetAttributesOf will return those attributes that all objects in the array have in common.

If you have an object's fully qualified path or PIDL, SHGetFileInfo provides a simple way to retrieve information about an object that is sufficient for many purposes. SHGetFileInfo takes a fully qualified path or PIDL, and returns a variety of information about the object including:

  • The object's display name
  • The object's attributes
  • Handles to the object's icons
  • A handle to the system image list
  • The path of the file containing the object's icon


- Getting a Pointer to a Subfolder's IShellFolder Interface

You can determine whether your folder contains any subfolders by calling IShellFolder::GetAttributesOf and checking to see if the SFGAO_FOLDER flag is set. If an object is a folder, you can bind to it, which provides you with a pointer to its IShellFolder interface.

To bind to a subfolder, call the parent folder's IShellFolder::BindToObject method. This method takes the subfolder's PIDL and returns a pointer to its IShellFolder interface. Once you have this pointer, you can use the IShellFolder methods to enumerate the subfolders contents, determine their properties, and so on.


- Determining an Object's Parent Folder

If you have an object's PIDL, you may need a handle to one of the interfaces exposed by its parent folder. For example, if you want to determine the display name associated with a PIDL by using IShellFolder::GetDisplayNameOf, you must first retrieve the IShellFolder interface of the object's parent. It is possible to do this with the techniques discussed in the previous sections. However, a much simpler approach is to use the Shell function, SHBindToParent. This function takes the fully qualified PIDL of an object and returns a specified interface pointer on the parent folder. Optionally, it also returns the item's single-level PIDL for use in methods such as IShellFolder::GetAttributesOf.

The following sample console application retrieves the PIDL of the System special folder and returns its display name.


#include <shlobj.h>

#include <shlwapi.h>

#include <iostream.h>

#include <objbase.h>


int main()

{

    IShellFolder *psfParent = NULL;

    LPITEMIDLIST pidlSystem = NULL;

    LPCITEMIDLIST pidlRelative = NULL;

    STRRET strDispName;

    TCHAR szDisplayName[MAX_PATH];

    HRESULT hr;


    hr = SHGetFolderLocation(NULL, CSIDL_SYSTEM, NULL, NULL, &pidlSystem);


    hr = SHBindToParent(pidlSystem, IID_IShellFolder, (void **) &psfParent, &pidlRelative);


    if(SUCCEEDED(hr))

    {

        hr = psfParent->GetDisplayNameOf(pidlRelative, SHGDN_NORMAL, &strDispName);

        hr = StrRetToBuf(&strDispName, pidlSystem, szDisplayName, sizeof(szDisplayName));

        cout << "SHGDN_NORMAL - " <<szDisplayName << '\n';

    }


    psfParent->Release();

    CoTaskMemFree(pidlSystem);


    return 0;

}


The application first uses SHGetFolderLocation to retrieve the System folder's PIDL. It then calls SHBindToParent, which returns a pointer to the parent folder's IShellFolder interface, and the System folder's PIDL relative to its parent. It then uses the parent folder's IShellFolder::GetDisplayNameOf method to retrieve the display name of the System folder. Because GetDisplayNameOf returns a STRRET structure, StrRetToBuf is used to convert the display name into a normal string. After displaying the display name, the interface pointers are released and the System PIDL freed. Note that you must not free the relative PIDL returned by SHBindToParent.





AND

Getting a Folder's ID  (MSDN 번역)


Namespace object를 사용하기에 앞서 PIDL(pointer to an item identifier list) 또는 (file system object인 경우만) path(경로)를 얻어 object들을 구별할 수 있어야 한다. 여기서는 object ID들을 얻는 두가지 간단한 방법을 소개한다.


모든 폴더에 대해 적용되는 강력한 접근방법은 IShellFolder interface를 이용하는 것이다(Getting Information About the Contents of a Folder 참조 - 다음 챕터에 소개).


목차

The OpenFiles Dialog Box

The SHBrowseForFolder Dialog Box

Special Folders and CSIDLs

A Simple Example of How to Use CSIDLs and SHBrowseForFolder



- The OpenFiles Dialog Box


사용자가 namespace를 탐색하고 폴더를 선택할 수 있도록 하기 위해서는 당신의 application이 IFileDialog interface를 사용해야 한다. 이 인터페이스를 FOS_PICKFOLDERS flag와 함께 호출하면 the Open Files common dialog box가 "pick folders" mode로 실행된다. (WIndow Vista이후 폴더 선택방식으로 권장되는 방법)



- The SHBrowseForFolder Dialog Box


사용자가 namespace를 탐색하고 폴더를 선택할 수 있도록 하기 위해서는 당신의 application이 단순히 SHBrowseForFolder를 호출하여 Open or Save As common dialog boxes방식으로 작동하는 UI를 가진 dialog box를 실행시키면 됩니다.


사용자가 폴더를 선택하면 SHBrowseForFolder는 폴더의 fully qualified PIDL을 반환하고 그것의 이름을 표시합니다. 만약 그 폴더가 파일 시스템에 포함되는 것이라면 application은 SHGetPathFromIDList함수를 호출하여 PIDL을 경로로 변환할 수 있습니다. Application은 특정 root folder만 선택적으로 보임으로써 사용자의 폴더 선택을 제한할 수 있습니다.

(SHBrowseForFolder Function 참조)



- Special Folders and CSIDLs


사용되는 폴더들 중 상당수는 시스템에 의해 특별히 설계된 것이다. 이 특수 목적 폴더들은 거의 모든 시스템에 포함되어 있거나 설령 없더라도 그 폴더의 이름과 위치가 정의되어 있어 언제든 추가될 수 있다. 이 특수 폴더들은 모든 시스템의 표준 가상 폴더들(standard virtual folders; Printer, My Documents, Network Neighborhood 등)이거나 표준 파일 시스템 폴더들(standard file system folders; Program files, System 등) 이다.


모든 시스템에 포함되어 있기는 하지만 시스템 상황에 따라 그 폴더의 위치는 다를 수 있다(For example, the System directory is C:\Winnt\System32 on some systems and C:\Windows\System32 on others.). 이런 차이가 있는 환경변수를 피하기 위해 쉘은  CSIDLs라는 특수 폴더를 구별하는 방법을 제공한다.


CSIDLs는 특수 폴더의 위치를 이름이나 위치, 시스템과 관계없이 분별하는 공통의 방법을 제공한다. 환경변수와 달리 CSIDLs는 파일 시스템 폴더뿐 아니라 가상 폴더들에도 적용된다. 각 특수 폴더들은 고유의 CSIDL을 배정받는다. (For example, the Program Files file system folder has a CSIDL of CSIDL_PROGRAM_FILES, and the Network Neighborhood virtual folder has a CSIDL of CSIDL_NETWORK)


CSIDL은 몇몇 Shell function들과 함께 특수 폴더의 PIDL 또는 special file system folder의 경로를 얻어내는데 쓰인다. 만약 해당 폴더가 시스템에 존재하지 않는다면 CSIDL_FLAG_CREATE flag를 추가하여 해당 폴더를 만들 수도 있다. 

SHGetFolderLocation함수는 특수 폴더의 PIDL를 구하고, SHGetFolderPath함수는 파일시스템의 특수 폴더 경로를 구한다.

(SHGetSpecialFolderLocation/Path함수들은 Shell 5.0 버전 이후 위 두 함수의 래퍼함수에 불과하게 되었다. 대체되는 중)


- A Simple Example of How to Use CSIDLs and SHBrowseForFolder


LPITEMIDLIST PidlBrowse(HWND hwnd, int nCSIDL, LPSTR pszDisplayName)

{

    LPITEMIDLIST pidlRoot = NULL;

    LPITEMIDLIST pidlSelected = NULL;

    BROWSEINFO bi = {0};


    if(nCSIDL)

    {

        SHGetFolderLocation(hwnd, nCSIDL, NULL, NULL, &pidlRoot);

    }


    else

    {

        pidlRoot = NULL;

    }


    bi.hwndOwner = hwnd;

    bi.pidlRoot = pidlRoot;

    bi.pszDisplayName = pszDisplayName;

    bi.lpszTitle = "Choose a folder";

    bi.ulFlags = 0;

    bi.lpfn = NULL;

    bi.lParam = 0;


    pidlSelected = SHBrowseForFolder(&bi);


    if(pidlRoot)

    {

        CoTaskMemFree(pidlRoot);

    }


    return pidlSelected;

}


위 함수를 호출한 application은 SHBrowseForFolder함수가 필요로 하는 윈도우 핸들과 목표로 하는 특수 폴더의 CSIDL을 넘겨 검색할 root folder로 지정한다(그 목적은 검색 제한). 또한 pszDisplayName으로 문자열 버퍼를 넘겨 PidlBrowse가 반환될 때 선택된 폴더의 이름을 저장한다. 마지막에는 CoTaskMemFree함수로 사용한 IDList의 메모리를 해제해준다.




Getting a Folder's ID  (MSDN 번역)

AND

ARTICLE CATEGORY

분류 전체보기 (56)
Programming (45)
MSDN (4)
개발노트 (2)
reference (5)

RECENT ARTICLE

RECENT COMMENT

CALENDAR

«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

ARCHIVE