헬마입니다.

이란은 제가 The Old New Thing 을 읽으면서 관심가지는 글들을 번역해서 올려놓는 란입니다.

글의 원문은 이곳입니다.
--------------------------------------------------------------------------------

인터페이스란 것은 계약이지만 이러한 계약은 양쪽 당사자 모두에게 해당된다는 것을 기억해야합니다. 대부분의 시간동안 인터페이스를 읽을 때 계약의 요청자 입장에서 보게되지만, 때때로 수행자 측면에서 계약을 읽는 것이 도움이 된다.

예를 들어, 제어판 어플리케이션을 위한 인터페이스를 보자.

거의 대부분의 시간을 이 문서를 읽는 동안 "난 제어판 어플리케이션을 작성하고 있다구" 라고 중엉거릴 것이다. 자, 예를 들어, 이 문서는 다음과 같이 말하고 있다.

제어판 어플리케이션을 처음으로 불러오는 어플리케이션을 제어할 때, 어플리케이션은 CPlApplet 함수에 대한 주소를 얻고 함수를 호출하고 메시지를 전달하는데 이 주소를 사용한다.

"난 제어판 어플리케이션을 작성하고 있다구" 라고 중엉걸릴때 이 의미는 "이크, CPlApplet 이라고 불리는 함수를 만들고 메시지를 받을 수 있도록 이 함수를 외부에 노출해야겠네" 이다.

하지만, "난 제어판 어플리케이션을 호스팅하구 있어" 라고 중엉거린다면, 이 의미는 " 이크, 어플리케이션의 CPlApplet 함수의 주소를 얻기 위해 GetProcAddress() 를 호출하고 이 함수에 메시지를 전송할 수 있군." 이다.

유사하게, "메시지 처리" 섹션에서 제어 어플리케이션에서 제어판 어플리케이션으로 보내지는 메시지의 목록을 나타내고 있다. 만약 "난 제어판 어플리케이션을 작성하고 있어" 라면 "이크, 이 방법대로 이러한 메시지들을 받을 준비를 해야겠네"이다. 하지만, "난 제어판 어플리케이션을 호스팅하고 있어" 라면 목록에서 이 방법대로 이러한 메시지들을 보내야 겠군" 이다.

  마지막으로, "제어 어플리케이션은 FreeLibrary 함수를 호출하여 제어판 어플리케이션을 해제한다" 에서 "난 제어판 어플리케이션을 작성하고 있어" 라면 "종료에 대비해야겠군" 일테지만, "난 제어판 어플리케이션을 호스팅하고 있어" 라면 "DLL 을 해제하는 바로 그곳이군" 이다.

자 이제 시작해보자. 언제나처럼 우리의 프로그램으로 시작하고 WinMain 을 변경한다:

#include <cpl.h>


int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev,
                   LPSTR lpCmdLine, int nShowCmd)
{
  HWND hwnd;

  g_hinst = hinst;

  if (!InitApp()) return 0;

  if (SUCCEEDED(CoInitialize(NULL))) {/* In case we use COM */

      hwnd = CreateWindow(
          "Scratch",                      /* Class Name */
          "Scratch",                      /* Title */
          WS_OVERLAPPEDWINDOW,            /* Style */
          CW_USEDEFAULT, CW_USEDEFAULT,   /* Position */
          CW_USEDEFAULT, CW_USEDEFAULT,   /* Size */
          NULL,                           /* Parent */
          NULL,                           /* No menu */
          hinst,                          /* Instance */
          0);                             /* No special parameters */

      if (hwnd) {
        TCHAR szPath[MAX_PATH];
        LPTSTR pszLast;
        DWORD cch = SearchPath(NULL, TEXT("access.cpl"),
                     NULL, MAX_PATH, szPath, &pszLast);
        if (cch > 0 && cch < MAX_PATH) {
          RunControlPanel(hwnd, szPath);
      }
    }

    CoUninitialize();
  }

  return 0;
}

창을 나타내고 메시지 루프에 들어가는 대신, 우리는 제어판을 호스팅하는 것처럼 시작할 것이다. 오늘의 우리의 희생양은 (내게 필요한 옵션 제어판인) access.cpl 이다. 경로에서 프로그램을 찾은 후 RunControlPanel 에게 무거운 짐을 수행하도록 요청한다.

void RunControlPanel(HWND hwnd, LPCTSTR pszPath)
{
  // Maybe this control panel application has a custom manifest
  ACTCTX act = { 0 };
  act.cbSize = sizeof(act);
  act.dwFlags = 0;
  act.lpSource = pszPath;
  act.lpResourceName = MAKEINTRESOURCE(123);
  HANDLE hctx = CreateActCtx(&act);
  ULONG_PTR ulCookie;
  if (hctx == INVALID_HANDLE_VALUE ||
      ActivateActCtx(hctx, &ulCookie)) {


    HINSTANCE hinstCPL = LoadLibrary(pszPath);
    if (hinstCPL) {
      APPLET_PROC pfnCPlApplet = (APPLET_PROC)
        GetProcAddress(hinstCPL, "CPlApplet");
      if (pfnCPlApplet) {
        if (pfnCPlApplet(hwnd, CPL_INIT, 0, 0)) {
          int cApplets = pfnCPlApplet(hwnd, CPL_GETCOUNT, 0, 0);
          //  We're going to run application zero
          //  (In real life we might show the user a list of them
          //  and let them pick one)
          if (cApplets > 0) {
            CPLINFO cpli;
            pfnCPlApplet(hwnd, CPL_INQUIRE, 0, (LPARAM)&cpli);
            pfnCPlApplet(hwnd, CPL_DBLCLK, 0, cpli.lData);
            pfnCPlApplet(hwnd, CPL_STOP, 0, cpli.lData);
          }
        }
        pfnCPlApplet(hwnd, CPL_EXIT, 0, 0);
      }

      FreeLibrary(hinstCPL);
    }

    if (hctx != INVALID_HANDLE_VALUE) {
      DeactivateActCtx(0, ulCookie);
      ReleaseActCtx(hctx);
    }

  }
}

일단 빨간 줄로 된것은 무시하자, 이에 대해선 후에 다시 얘기할 것이다.

우리가 한 것은 모두 호스트 측면에서 사양을 읽어 구현한 것이다. 그래서 라이브러리를 불러오고, 진입점을 찾은 후 CPL_INIT 로 호출한 다음에 CPL_GETCOUNT 로 함수를 호출했다. 만약 CPL 파일 안에 어떠한 제어판 어플리케이션이 들어있다면, 우리는 첫번째 것을 물어볼 수 있고, 어플리케이션을 더블 클릭하고 멈추게 한다. 결국 모든 일이 끝나면, 우리는 호스트 규칙에 따라 정리할 수 있으것이다. ( 일반적으로, CPL_EXIT 라는 메시지를 보냄으로써 ).

자 이제 빨간 부분을 제외한 모든 부분이 끝났다. 그럼 저 부분은 무엇인가?

빨간 부분은 사용자 메니페스트(manifest) 를 가지고 있는 제어판 어플리케이션을 지원하기위한 것이다. 이 부분은 윈도 XP에서 새로워진 것이고 MSDN의 이 부분에서 설명하고 있다.

만약 "RunDll32.exe 에 의해 실행되는 제어판 또는 DLL 에서 ComCtl32 버전 6 사용하기" 섹션을 내려받는다면 자원 번호 123 으로 취급되는 메니페스트를 첨부함으로써 제어판 호스트 측에 메니페스트를 제공할 수 있다는 것을 알 수 있다. 자, 이제 붉은 코드가 무슨 일을 하는지 보자 : 이 코드는 메니페스트를 불러와서 활성화시킨 후 제어판 어플리케이션이 메니페스트 활성화된 채로 동작할 수 있도록 불러오고 후에 자원을 해제한다. 만약 메니페스트가 없다면, CreateActCtx 는 INVALID_HANDLE_VALUE 를 반환한다. 우리는 이러한 오류를 취급하지 않았다 왜냐하면 아직 많은 프로그램이 메니페스트를 제공하지 않기 때문이다.

Published Friday, December 26, 2003 8:39 AM by oldnewthing

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

영어 공부 차원에서 하는 것이라 매우 미흡합니다. 오역등이 있다면 바로 바로 지적해주세요.
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

  1. BlogIcon toko jaket online 2012.11.08 11:36 신고 Address Modify/Delete Reply

    당신의 작문 능력과 더불어 웹 로그에 대한 레이아웃과 정말 영감을 함께 느낀다. 이 보상 주제뿐만 아니라 그것을 스스로를 수정 아세요? 어쨌든 우수한 우수한 기록을 유지, 그것은 모양과 같은 환상적인 블로그 오늘 취할 드문 것 ..

  2. BlogIcon sweater 2012.12.10 19:05 신고 Address Modify/Delete Reply

    이 주제 재료 내부에 개발 된 것으로 나타납니다 모든 일들과 함께 모든 관점은 일반적으로 상대적으로 새로 고침하는 중입니다. 그럼에도 불구하고, 내가 뭐라 구요,하지만 전체 제안에 더 힘을 실어주지 마, 모든이 적은 것도을 자극하지. 당신의 설명은 실제로 완전히 정당하지 현실에서 정말 일반적으로 포인트 완전히 특정하여 자기 없습니다 것을 나에게 보인다. 어떤 경우에는 내가 좋아하는 읽어 않았습니다.

티스토리 툴바