본문 바로가기
개발

Visual C++로 XPCOM 컴포넌트 만드는 방법

by 솜씨제이 2007. 7. 19.

모질라 파이어폭스에서 사용하기 위한 XPCOM 컴포넌트를 만들기 위해서 Visual C++를 사용할 수 있는 방법에 대한 설명입니다. 일반적으로 XPCOM을 만드는 경우 GCC를 많이 사용하겠지만 Windows 환경이라면 역시 Visual C++을 이용해서 XPCOM을 만들 수 있다면 더 편리할 것입니다.
모질라 개발자 사이트에 있는 내용을 참고하였고 XPCOM 개발에 대한 기본적인 지식이 있는 것으로 전제합니다. XPCOM에 대한 자세한 내용은 Mozilla Developer Center를 참고하시기 바랍니다.

개발 환경 설정

먼저 Visual C++이 설치되어 있어야 합니다. Microsoft에서 무료로 배포하는 Visual C++ Express를 사용할 수도 있습니다. 여기서는 Visual C++ 2005를 사용했습니다.
다음으로 Gecko SDK를 설치해야 합니다. gecko-sdk-win32-msvc-1.8.0.4.zip을 다운로드해서 프로젝트의 상위 폴더에 압축을 풀어 줍니다. 압축을 풀면 gecko-sdk라는 폴더가 생성됩니다.
다음으로 Gecko SDK에 있는 툴(xpidl)을 사용하기 위해서 wintools.zip에 포함된 glib-1.2.dll과 libIDL-0.6.dll을 Gecko SDK 폴더에 있는 bin 폴더(gecko-sdk\bin)에 복사해줍니다.

VC++ 프로젝트 생성

먼저 VC++ Win32 DLL 프로젝트를 Gecko SDK의 압축을 해제했던 폴더에 생성합니다. 프로젝트 속성의 구성 속성에서 다음 속성값을 변경해줍니다.

  • C/C++ >  추가 포함 디렉터리에 "..\gecko-sdk\include"를 추가합니다.
  • C/C++ > 전처리기 > 전처리기 정의에 "XP_WIN;XP_WIN32"를 추가합니다.
  • 링커 > 일반 > 추가 라이브러리 디렉터리에 "..\gecko-sdk\lib"를 추가합니다.
  • 링커 > 입력 > 추가 종속성에 "nspr4.lib xpcom.lib xpcomglue_s.lib"를 추가합니다.
  • C/C++ > 미리 컴파일된 헤더 > 미리 컴파일된 헤더 만들기/사용을 미리 컴파일된 헤더 사용 안 함으로 설정합니다.(프로젝트를 생성할 때 빈 프로젝트로 생성하면 디폴트값)
  • XPCOM IDL 파일은 사용자 지정 빌드를 설정합니다.(속성 설정 방법은 아래에 다시 설명하겠습니다)

간단히 설명하기 위해서 예제는 모질라 개발자 사이트에 있는 xpcom-test.zip을 사용하겠습니다.

XPCOM 컴포넌트 생성

먼저 컴포넌트 인터페이스에 대한 XPCOM IDL을 만듭니다.

#include "nsISupports.idl"

[scriptable, uuid(263ed1ba-5cc1-11db-9673-00e08161165f)]
interface ISpecialThing : nsISupports
{
  attribute AString name;

  long add(in long a, in long b);
};

XPCOM IDL에 대한 사용자 지정 빌드를 수행할 배치파일(*.bat)를 프로젝트 폴더에 만듭니다. Gecko SDK의 gecko-sk\bin에 있는 xpidl.exe를 실행하도록 다음과 같이 편집하면 됩니다. 프로젝트 폴더와 gecko-sdk 폴더가 같은 폴더에 있다고 할 경우입니다.(이 예제에서는 xpidl-build.bat로 생성합니다.)

..\gecko-sdk\bin\xpidl.exe -m header -I..\gecko-sdk\idl %1
..\gecko-sdk\bin\xpidl.exe -m typelib -I..\gecko-sdk\idl %1

다음으로 XPCOM IDL의 속성(구성 속성)에서 사용자 지정 빌드를 설정합니다.

  • 일반 > 도구에서 사용자 지정 빌드 도구를 선택합니다.(다음 속성 변경을 위해 적용 필요)
  • 사용자 지정 빌드 단계 > 명령줄에 "$(ProjectDir)xpidl-build.bat $(InputFileName)"를 입력합니다.
  • 사용자 지정 빌드 단계 > 출력에 .\$(InputName).h를 입력합니다.

C++로 XPCOM 컴포넌트를 구현합니다.

헤더 파일

#ifndef __SPECIALTHING_IMPL_H__
#define __SPECIALTHING_IMPL_H__

#include "comp.h"
#include "nsStringAPI.h"

#define SPECIALTHING_CONTRACTID "@starkravingfinkle.org/specialthing;1"
#define SPECIALTHING_CLASSNAME "SpecialThing"
#define SPECIALTHING_CID { 0x245626, 0x5cc1, 0x11db, { 0x96, 0x73, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f } }

class CSpecialThing : public ISpecialThing
{
public:
  NS_DECL_ISUPPORTS
  NS_DECL_ISPECIALTHING

  CSpecialThing();

private:
  ~CSpecialThing();

protected:
  /* additional members */
  nsString mName;
};

#endif

소스 파일

#include "comp-impl.h"

NS_IMPL_ISUPPORTS1(CSpecialThing, ISpecialThing)

CSpecialThing::CSpecialThing()
{
  /* member initializers and constructor code */
  mName.Assign(L"Default Name");
}

CSpecialThing::~CSpecialThing()
{
  /* destructor code */
}

/* attribute AString name; */
NS_IMETHODIMP CSpecialThing::GetName(nsAString & aName)
{
  aName.Assign(mName);
  return NS_OK;
}
NS_IMETHODIMP CSpecialThing::SetName(const nsAString & aName)
{
  mName.Assign(aName);
  return NS_OK;
}

/* long add (in long a, in long b); */
NS_IMETHODIMP CSpecialThing::Add(PRInt32 a, PRInt32 b, PRInt32 *_retval)
{
  *_retval = a + b;
  return NS_OK;
}

XPCOM 모듈 구현을 만듭니다.

#include "nsIGenericFactory.h"
#include "comp-impl.h"

NS_GENERIC_FACTORY_CONSTRUCTOR(CSpecialThing)

static nsModuleComponentInfo components[] =
{
  {
    SPECIALTHING_CLASSNAME,
    SPECIALTHING_CID,
    SPECIALTHING_CONTRACTID,
    CSpecialThingConstructor,
  }
};

NS_IMPL_NSGETMODULE("SpecialThingsModule", components)

이것으로 XPCOM 컴포넌트를 빌드할 수 있게 되었습니다.

파이어폭스에 확장 기능(Extension)으로 설치

이제 만들어진 컴포넌트를 부가 기능(Extension)으로 파이어폭스에 설치해봅시다.
먼저 다음과 같은 내용으로 install.rdf 파일을 생성합니다.

<?xml version="1.0" encoding="UTF-8"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 xmlns:em="http://www.mozilla.org/2004/em-rdf#">
  <Description about="urn:mozilla:install-manifest">
    <em:id>specialthing@starkravingfinkle.org</em:id>
    <em:name>specialthing</em:name>
    <em:version>1.0</em:version>
    <em:creator>Still</em:creator>
    <em:description>specialthing</em:description>
    <em:targetApplication>
      <Description>
        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <!-- firefox -->
        <em:minVersion>2.0</em:minVersion>
        <em:maxVersion>2.0.0.*</em:maxVersion>
      </Description>
    </em:targetApplication>
  </Description>
</RDF>

다음 내용으로 chrome.manifest를 생성합니다.

content specialthing content/
locale specialthing en-US locale/en-US/
skin specialthing classic/1.0 skin/
overlay chrome://browser/content/browser.xul chrome://specialthing/content/firefoxOverlay.xul

content 폴더를 만들고 다음 내용으로 firefoxOverlay.xul을 만듭니다.

<?xml version="1.0" encoding="UTF-8"?>
<overlay id="specialthing-overlay"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  <menupopup id="menu_ToolsPopup">
    <menuitem id="specialthing" label="SpecialThing"
              oncommand="
{
  try {
    const cid = '@starkravingfinkle.org/specialthing;1';
    var obj = Components.classes[cid].createInstance();
    obj = obj.QueryInterface(Components.interfaces.ISpecialThing);
  }
  catch (err) {
    alert(err);
    return;
  }

  var res = obj.add(3, 4);
  alert('3+4 = ' + res);

  var name = obj.name;
  alert('Name = ' + name);

  obj.name = 'New Name';
  name = obj.name;
  alert('Name = ' + name);
}
"/>
  </menupopup>
</overlay>

components 폴더를 만들고 해당 폴더로 프로젝트 폴더에 있는 xpt 파일과 빌드된 dll 파일을 복사합니다.
install.rdf 파일과 chrome.manifest 파일, contents 폴더, components 폴더를 zip 파일로 압축합니다.
압축한 zip 파일의 확장자를 xpi로 변경합니다.
xpi 파일을 파이어폭스에 드래그앤드롭하면 설치 화면이 나오고 화면에 따라 설치합니다.
파이어폭스를 다시 시작해서 도구 메뉴에서 SpecialThing을 선택하면 XPCOM을 실행한 결과를 확인할 수 있습니다.

댓글