rubrapack 매뉴얼←↑→

27 표, 키, 참조

.msi 안(6장)의 스트림은 대부분 표다: 패키지는 작은 데이터베이스다. Windows Installer 는 내가 적은 단계별 각본을 따르는 것이 아니라, 표를 읽고 무엇을 할지 스스로 알아낸다. 이 장은 표를 읽는 데 필요한 데이터베이스 개념 몇 가지를 설명한다.

27.1 표, 행, 열#

표는 격자다. 열마다 이름과 형식이 있고, 행 하나가 하나의 대상 - 파일 하나, 바로가기 하나, 레지스트리 값 하나 - 이다. 튜토리얼 첫 패키지(튜토리얼 2장)의 File 표를 rubrapack inspect hello.msi File 이 출력한 대로 보면:

File	Component_	FileName	FileSize	Version	Language	Attributes	Sequence
s72	s72	l255	i4	S72	S20	I2	i4
File	File
Hello	C_185f8db32271fe25f561	hello.exe	17920	1.2.3.4	1033	512	1

격자로 펼치면:

FileComponent_FileNameFileSizeVersionLanguageAttributesSequence
HelloC_185f8db32271fe25f561hello.exe179201.2.3.410335121

글의 둘째 줄이 열마다 형식을 준다:

형식뜻
s7272자까지의 문자열
l255255자까지의 지역화할 수 있는(번역이 바꿀 수 있는) 문자열
i2, i42 또는 4 바이트 정수(2장)
대문자 S, L, I같지만 칸이 비어 있어도("null") 된다

표준 표의 열 형식은 Windows Installer 가 정해 두었고, rubrapack 은 모든 값을 그것과 대조한다(lint, 튜토리얼 18장): i2 열에 100,000 은 들어가지 않는다.

27.2 기본 키: 행을 하나로 만드는 것#

셋째 줄 File File 은 표 이름과 기본 키 - 행마다 값이 다른 열(또는 열들) - 를 적는다. File 표에서는 열 File 이다: Hello 가 이 행의 이름이고 다른 어떤 행도 그 이름을 쓸 수 없다. 그래서 rubrapack 의 ID 는 겹치면 안 된다(튜토리얼 2장): [file.Hello] 에 적은 ID 가 이 키가 된다.

어떤 표는 열 둘을 함께 써야 한다. FeatureComponents 는 어느 컴포넌트가 어느 기능에 속하는지 적는다. 기능 하나에 컴포넌트가 여럿이고 컴포넌트 하나가 여러 기능에 들 수 있으므로, 둘의 짝만이 하나뿐이다:

Feature_	Component_
s38	s72
FeatureComponents	Feature_	Component_
Main	C_185f8db32271fe25f561

27.3 외래 키: 행을 가리키는 행#

이름이 _ 로 끝나는 열은 다른 표의 행의 키를 담는다 - 외래 키, 곧 참조다. 참조를 따라가면 표들이 하나의 그림으로 이어진다. 파일에서 시작해 참조를 따라가 보면:

File              Hello
  Component_  --> Component   C_185f8db32271fe25f561
                    ComponentId   {B80BEC59-F582-8F10-8EB1-638C6687B899}
                    Directory_  --> Directory   INSTALLDIR
                                      DefaultDir   Hello
                                      Directory_Parent --> Directory   ProgramFiles64Folder
                                                             DefaultDir  .
                                                             Directory_Parent --> TARGETDIR
                    KeyPath     --> File        Hello   (back to the start)
FeatureComponents Main + C_185f8db32271fe25f561
  Feature_    --> Feature     Main
                    Level  1   (installed by default)

소리 내어 읽으면: 파일 hello.exe 는 한 컴포넌트에 속하고, 그 컴포넌트는 ProgramFiles64Folder(Program Files) 안의 폴더 Hello 에 설치되며, 기능 Main 이 그 컴포넌트를 설치한다. 컴포넌트의 키 경로는 파일 자신이다: hello.exe 가 있으면 그 컴포넌트는 설치된 것으로 친다(튜토리얼 4장).

없는 행을 가리키는 참조는 Windows Installer 가 멈출 오류다 - rubrapack lint 가 어느 도구로 만든 .msi 에서든 검사하는 것 중 하나다.

27.4 내가 주는 키, rubrapack 이 만드는 키#

표에는 원본의 ID 가 그대로 나온다 - Hello, INSTALLDIR, Main. Windows Installer 에는 필요하지만 원본에 자기 표가 없는 행에는 rubrapack 이 키를 만든다: 파일마다 만드는 컴포넌트는 C_ 와 16진수 20자리, 글롭으로 찾은 파일은 F_ 와 16진수 20자리. 이 숫자는 그 대상의 자리의 해시(4장)에서 오므로 빌드마다 같다.

27.5 문자열은 한 번만: 문자열 풀#

표에는 되풀이되는 문자열 - INSTALLDIR, 컴포넌트 키, Hello - 이 가득하고, MSI 는 서로 다른 문자열을 한 번씩만 보관한다. 패키지의 모든 문자열이 문자열 풀이라는 목록 하나(스트림 둘, _StringPool 과 _StringData)에 있고, 표의 문자열 칸은 그 목록에서의 문자열 번호만 2 바이트로(아주 큰 패키지에서는 3 바이트로) 담는다. 튜토리얼 첫 패키지는 표 17개 전체에 서로 다른 문자열이 132개다:

C:\work\hello> rubrapack inspect hello.msi
code page: 65001
strings: 132
tables: 17

풀은 문자열마다 몇 칸이 쓰는지도 센다. 그 바이트는 제4부가 보인다.

27.6 표에 대한 표#

데이터베이스는 자기를 설명한다. 두 표가 다른 표들을 나열한다: _Tables 는 표마다 한 행, _Columns 는 모든 표의 열마다 형식과 함께 한 행이다. 셋째 표 _Validation 은 열마다 담을 수 있는 것 - 범위, 값이 가리키는 표, Identifier 나 Formatted 같은 범주 - 을 적는다. Windows Installer 는 설치할 때 이 표를 읽지 않고, 검증 도구가 자료를 이것과 대조한다. inspect 가 처음 두 줄에 출력하는 열 이름과 형식을 거기서 찾는다. 순서 표들 (InstallExecuteSequence, InstallUISequence, 그리고 관리용·광고용 설치를 위한 셋 더)은 설치의 단계를 순서대로, 단계마다 조건과 함께 나열한다(튜토리얼 9장과 13장) - 절차마저 표다.

27.7 IDT 텍스트 형식#

inspect 가 출력하는 글은 Windows Installer 자신의 IDT 형식이다: 머리 세 줄, 그다음 행마다 한 줄, 열은 탭으로 나눈다. Microsoft 의 Windows SDK 도구들이 표를 이 형식으로 들이고 내보내므로, rubrapack inspect 의 표를 다른 도구가 내보낸 것과 비교할 수 있다.

27.8 쓰이는 곳#