2009. 7. 7. 11:26

Scriptable COM Object 설계 시 고려해야 할 점

Eric's Complete Guide To Type Signatures Of Scriptable Object Models

 

: 이 글은 마지막에 링크된 주소의 글을 번역한 것이다. 번역이 미숙하더라도 이해바람.

 

내가 수년 동안 받은 많은 질문들에 대해서 소개한다.

 

"VBScript JScript 둘 다에서 쉽게 호출될 수 있도록 하기 위해서는 어떻게 객체를 디자인 하는가?"

 

COM 은 매우 복잡한 타입 시스템을 정의하고 스크립트 엔진은 그 타입 시스템의 하위 집합만을 지원한다. C++ 에서 쉽게 호출될 수 있는 객체를 생성하는 것은 가능하지만 VB6, VBScript,  그리고 특별히 JScript 와 같은 다른 언어에서 쉽게 호출되지 않을 수 있다.

 

나는 여러번 개인적인 이슈에 대하여 블로그에 글을 올렸다; 지난달에 그에 관해 설명하는 문서를 요청 받았다. 뒤에 좀더 자세한 설명을 위한 메인 기사에 관한 링크를 제공할 것이다.

 

이것은 기본적으로 "해야할 것 들"에 대해서가 아니라 "하지 말아야 하는 것"에 대한 목록이다. 또한 직관적이고, 발견될 수 있는, 테스트 가능한, 문서화할 수 있는, 확장할 수 있는, 등등의 객체 모델을 디자인 하는 것에 관해 언급해야 할 것들이 굉장히 많이 더 존재한 다는 것을 기억하라. 언젠가 그것에 관해 이야기 할지도 모르지만, 오늘은 메소드 타입 원형의 구현자(the implementor of method type signatures) 가 반드시 피해야 하는 매우 기초적인 질문에 관해서만 언급할 것이다.

 

Numeric types

 

VBScript VT_I2(short signed integer), VT_I4(long signed integer), VT_R4(single float), VT_R8(double float), VT_CY(currency), 그리고 VT_UI1(unsigned bye) 데이터에 대한 산술연산을 할 수 있다. 8-바이트 정수, unsigned integers, signed bytes 그리고 fixed-point decimals 는 지원되지 않는다.

 

대조적으로, Jscript bytes, shorts, singles, currencies 그리고 unsigned integers 를 즉시 VT_I4 또는 VT_R8 중 하나로 (알맞은 것으로) 즉시 변환한다, 그리고 그것들을 가지고 연산을 수행한다.

 

일반적으로, 스크립트 엔진이 비록 특정 타입에 대한 연산을 지원하지 않더라고, 여전히 그 값을 저장하고 그것을 파라미터로 전달할 수 있다. (?: you can still store the value and pass it around.) 한 객체에서 VT_DECIMAL 값을 얻기 위한 접착제(glue)”로서 스크립트를 사용할 수 있고 그것을 다른 객체에 전달한다.

 

만약 당신의 객체 모델이 fixed-point decimals(VT_DECIMAL)을 사용한다면, 스크립트에서 객체를 사용하는 것은 어려울 것이다. 거의 모든 floating point 산술 연산은 에러가 생긴다는 것을 기억하라. 당신의 객체 모델이 currencies 의 의존적이라면 Jscript 는 원하는 목적을 실패하게끔 할 수 있다. 원칙적으로는, double long 만 지원한다.

 

좀더 많은 정보를 위해서는 아래 링크를 보라.

http://blogs.msdn.com/ericlippert/archive/2003/09/15/53000.aspx

 

Dates

 

VBScript Jscript 는 날짜를 다룸에 있어 완전히 다른 코드를 사용한다. 두 시스템은 좋았어(gotchas)”로 가득하다. 코드가 COM 에서 사용되는 표준 VT_DATE를 사용하여 date를 조작한다면, Jscript 는 그것들을 자동적으로 내부 date 포맷으로 변환할 것이다. 일반적으로 그것을 다루는 방법이 있긴 하지만, 그 코드는 약간 트릭키 할 수 있다.

 

자세한 정보는 아래를 보라.

http://blogs.msdn.com/ericlippert/archive/2003/09/16/53013.aspx
http://blogs.msdn.com/ericlippert/archive/2003/10/06/53150.aspx

 

Object Types

 

IDispatch 가 아닌 인터페이스를 노출하는 객체는 VBScript Jscript 에서 사용될 수 없다. VT_UNKNOWN 을 넘긴다면, 즉시 그것을 VT_DISPATCH 로 변환하려고 시도한다. Scriptable 객체 모델은 전적으로 dispatchable 해야 한다.

 

-디폴트(non-default) 디스패치 인터페이스는 나쁘다. Jscript 는 비-디폴트 디스패치를 지원하지 않는다. VBScript 는 하나가 주어진다면 비-디폴트 디스패치를 사용하긴 하지만, 디폴트 디스패치로부터 디스패치를 얻기 위한 어떠한 방법도 제공하지 않는다. 다중으로 분리된 디스패치 인터페이스를 지원하는 객체를 작성하지 말라.

 

자세한 정보는 아래를 보라.

http://blogs.msdn.com/ericlippert/archive/2003/10/10/53188.aspx

 

 빠뜨린 인자, 빠뜨린 정보

 

VBScript 는 빠뜨린 인자를 지원한다. 메소드를 아래와 같이 호출 할 수 있다.

 

x = foo.bar(123,  , 456)

 

그러면 VBScript PARAMNOTFOUND 가 설정된 에러 필드를 가진 파라미터 VT_ERROR 를 넘길것이다. 그러고 나서는 Callee 가 그 문제를 다루는 책임이 있고, 그 인자를 알맞은 디폴트 값으로 채운다.

 

Jscript 는 빠뜨린 인자를 지원하지 않는다. 12개의 인자를 가지고 그들 중 일부는 빠뜨릴 수 있다고 예상하는 객체 모델은 Jscript 에서는 사용하기가 어렵다. (그리고 그들은 아마도 매우 나쁘게 설계된 메소드이다.)

 

Jscript VBScript 모두 이름지어진 인수(named arguments)를 지원하지 않는다.

 

빠뜨린 인자를 전달하는 일반적인 대안은 VBScript 에서는 Nothing, Null, 또는 Empty 를 넘기는 것이고, Jscript 에서는 null 또는 undefined 를 넘기는 것이다. Null null VT_NULL 을 전달하고, Empty undefined VT_EMPTY 를 전달한다, 그리고 Nothing 은 디스패치 객체 포인터 값이 없는 VT_DISPATCH 를 전달한다. Jscript 에서 “null” 객체를 전달하는 쉬운 방법은 없다. 이것은 Jscript 의 디자인 결함이라고 생각한다, 하지만 우리는 현재 그것에서 벗어날 수 없다. 좋은 Scriptable 객체 모델의 설계자는 Jscript 에서 사용하는 것을 쉽게 하기 위해 Null Nothing 을 동일하게 다루는 것을 고려할 수도 있다.

 

또 다른 관련 이슈는 “empty/null  문자열문제이다. C에서, 빈 문자열과 널 문자열은 다르게 처리된다. VB6, VBScript, 그리고 Jscript 는 그렇지 않다. 널 문자열과 빈 문자열은 동일하다는 규약을 사용한다. 하지만 VB는 이 규약을 사용하지 않는 Win32 API 를 호춣랄 수 있다, 그래서 VB6 VBScript 는 실행시에 빈 문자열 또는 널 문자열을 넘기는 것을 허용한다. Jscript 는 이 기능을 가지고 있지 않다.

 

널과 빈 문자열을 구분하는 Dispatchable COM 객체 모델은 거의 확실히 버그가 있다. 그렇게 하지 마라.

 

자세한 정보는 아래를 보라.

 

http://blogs.msdn.com/ericlippert/archive/2003/09/12/52976.aspx
http://blogs.msdn.com/ericlippert/archive/2003/09/30/53120.aspx
http://blogs.msdn.com/ericlippert/archive/2003/10/01/53128.aspx

 

More On Parameter Passing

 

“Out” 파라미터는 나쁘다. 스크립트가능한 객체 모델에서는 out 파라미터를 가지는 메소드는 작성하지 마라. Jscript out 파라미터를 전혀 지원하지 않는다. VBScript 경우에도 메모리 릭이 일어나는 시나리오가 있을 수 있다.

 

“In-out” 파라미터 역시 나쁘다.” – Jscript in-out 파라미터를 전혀 지원하지 않는다. VBScript 는 항상 VT_VARIANT | VT_BYREF 를 넘긴다, 그리고 IDispatch::Invok 의 디폴트 구현은 만일 메소드가 hard-typed byref 파라미터를 예상하고 있다면 타입 불일치(type mismatch)를 일으킬 것이다. 고유한 강제적인 로직을 작성하거나 인자를 variant 로 만들수 있지만, 둘 다 트릭키 하다. 전적츠로 그것을 피하는 가장 좋은 방법은 – out 또는 in-out 파라미터를 사용하지 않는 것이다.

 

“Out-retval” 값은 사실상 파라미터가 아니다 그것은 반환값이다 그래서 out-retval 은 괜찮다.

 

자세한 정보는 아래를 보라.

 

http://blogs.msdn.com/ericlippert/archive/2003/09/15/52996.aspx
http://blogs.msdn.com/ericlippert/archive/2003/09/15/53005.aspx
http://blogs.msdn.com/ericlippert/archive/2003/09/15/53006.aspx
http://blogs.msdn.com/ericlippert/archive/2003/09/29/53117.aspx

 

Arrays

 

배열은 나쁘다. Jscript VB-스타일의 배열에 대해 매우 빈약하게 지원한다. 다차원 vb스타일 배열은 Jscript 에서 처리하기가 특히 어렵다. 파라미터로 배열을 가지는 객체 모델을 작성하지 않으려고 노력하거나 배열을 반환하기만 하는 객체 모델을 작성하라. (이것은 큰 배열을 복사하는데 드는 성능 비용을 피할 수 잇기 때문에 역시 좋은 생각이다.)

 

VB6 foo(10 to 20, 4 to 6) 과 같은 임의의 인덱스 범위를 가진 배열을 생성할 수 있다. VBScript 는 그러한 배열을 사용할 수는 있지만 그것들을 생성할 수는 없다 모든 VBScript 0 에서 시작하는 배열을 생성한다.

 

스크립트 엔진은 variant 배열만 지원한다. 바이트의 배열은 underlying OS 에 의해 문자열로 변환될 수 있지만, 그것은 아주 엉망으로 만드는 것이다.

 

좀더 자세한 정보는 아래를 보라.

 

http://blogs.msdn.com/ericlippert/archive/2003/09/22/53061.aspx
http://blogs.msdn.com/ericlippert/archive/2003/09/22/53069.aspx
http://blogs.msdn.com/ericlippert/archive/2004/05/25/141525.aspx

 

Collections

 

VBScript Jscript 모두 IEumVARIANT 를 구현한 컬렉션을 지원한다. 다른 열거자는 지원하지 않는다.

 

자세한 정보는 아래를 보라.

http://blogs.msdn.com/ericlippert/archive/2003/09/22/53063.aspx

 

Method names

 

객체 모델 이름에 A~Z 0~9 문자만 사용하라. Unerbar 를 가진 이름은 나쁘다. VB 에서는 라인 결합자(line continuation, _ ) 와 아주 쉽게 혼될 되고, 보기가 흉하다. 피하라.

 

Jscript 또는 VBScript 예약어 또는 내장(built-in) 객체 모델 엘리먼트와 충돌하는 이름은 역시 나쁜 생각이다.

 

자세한 정보는 아래를 보라.

http://weblogs.asp.net/ericlippert/archive/2004/06/10/152831.aspx

 

빠뜨린 점이 분명 있다고 확신한다. 나중에 그 목록에 대해 다시 업데이트할 것을 약속한다.

 

원문 : http://blogs.msdn.com/ericlippert/archive/2004/07/14/183241.aspx