by 한빛리포터 2기, 김영환
능숙한 Palm OS 프로그래머라 할지라도 일반적으로 프로그램상 에러가 많이 발생한다. 능숙한 사람과 초보자간의 가장 큰 차이점은 그와 같은 문제를 다루는데 걸리는 시간이다. 만약 여러분이 이 플랫폼에 초보자라면 이 기사로부터 이와 같은 문제점을 피할 수 있는 방법보다는 잘못된 점을 찾고 그것을 고치는데 소요되는 시간을 절약할 수 있는 방법에 대해 배울 것이다. 만약 여러분이 Palm OS 프로그래밍에 좀더 익숙하다면, 여러분이 그동안 발견했던 문제점에 대한 해결책을 찾을 수도 있으며 아직 접하지 못 한 문제점에 대해서도 다룰 것이기 때문에 그냥 읽기 바란다. 좀더 새로운 문제에 대해 알고싶다면 오라일리에서 새로 출간한
『Palm OS Programming, 2nd Edition』을 읽어보기 바란다.
함정 #1: 폼 오브젝트 인덱스대신 폼 오브젝트 아이디를 사용하는 것
전부는 아니지만 대부분의 폼 매니저 루틴들은 오브젝트 아이디보다는 오브젝트 인덱스를 요구한다. 일반적인 에러들은 아이디에서 인덱스로 컨버트하는 것을 잊어버리는 것이다. 여기 컨버트에 실패하는 잘못된 코드가 있다.
myList = (ListPtr) FrmGetObjectPtr(form, MainPeopleList); // 나쁨
|
이 상황을 제대로 처리하기 위한 올바른 방법은 다음과 같다.
myList = (ListPtr) FrmGetObjectPtr(form,
FrmGetObjectIndex(form, MainPeopleList)); // 좋음
|
하나의 오브젝트 인덱스는 리스트에서 오브젝트들의 0....순으로 이어지는 범위에 있는 숫자이다. 따라서 그것은 일반적으로 작은 수이다. 반대로 오브젝트 아이디는 더 큰 숫자이다(일반적으로 1000보다 큼). 컨버전하는 것을 잊어버리는 사람들이 일반적으로 보게 되는 에러는 "index out of range: 1024"와 같은 것일 것이다. 인덱스에 대해 큰 수를 봤을 때 인덱스보다는 ID를 패스했다는 것이 중요한 실마리가 된다.
object ID나 object index 둘다 Ulnt16 type이 컴파일러에서 처리할 수 없기 때문에 나쁘게 만든다.
함정 #2: 이벤트 핸들링을 위해 언제 true/false를 해야 할 지 모르는 것
어떤 이벤트가 FrmHandleEvent에 의해 자동적으로 핸들링되는지 잊어버리는 것은 쉽다. 결과적으로 적절하지 못한 방법으로 true/false를 리턴하면 문제가 발생할 것이다. 이러한 상황은 이벤트 핸들러가 FrmDispatchEvent로부터 호출될때 발생한다. 만약 루틴이 false를 리턴하면 이벤트는 FrmHandleEvent으로 패스될 것이다. 어떤 이벤트가 개입되었느냐에 따라 그 시점에서 문제가 발생할 수도 있다. FrmHandleEvent은 특정 이벤트를 디폴드로 핸들링할 것이고 어느 이벤트가 디폴트 핸들링을 갖고 있는지 그렇지 않은지는 여러분에게 달려있다. 이것이 이벤트 핸들러로부터 true/false로 정확하게 리턴할 수 있는 유일한 방법이다.
여기 false를 리턴하는데 필요한 몇 가지 이벤트가 있다.
- ctlRepeatEvent: 반복적 작업을 계속하기 위한 false 리턴
- sclRepeatEvent: 스크롤 작업을 계속하기 위한 false 리턴
- popSelectEvent: 리스트에 선택되어진 아이템으로 부터 업데이트되는 컨트롤 라벨을 위한 false 리턴
여러분도 짐작하듯이 디폴트 프로세싱이 발생하지 않도록 true를 리턴할 시기가 몇 번 있다. PopSelectEvent가 좋은 예이다. 만약 일반적인 발행 루틴을 갖고있고 NULL을 LstSetListChoices으로 패스했다면 true를 리턴해야 한다. True가 없다면 디폴트 핸들링은 NULL 배열로부터 텍스트 읽기를 시도할 것이다.
물론 그와 같은 상황에서 CtlSetLabel을 사용해 컨트롤 라벨을 업데이트 하는 것은 여러분에게 달려있다. 이때 여러분은 다음과 같이 질문할 수도 있다. "그와 같은 경우에 사용할 올바른 텍스트는 무엇인가?" 대답은 여러분이 발행할 루틴에 있다. 그 안에 있는 텍스트를 얻기 위한 몇 가지 방법을 이미 알고있으므로 같은 방법을 사용해라.
함정 #3: 적당한 어플리케이션에 대한 필요성을 소홀히 하는 것
윈도우에서 등록된 컨디트(conduit)는 핸드헬드에서 같은 생성자 ID를 가지고 있는 애플리케이션이 없는 한 동기화 기간 동안 호출되지 않을 것이다. 핸드헬드에 성자 ID를 가지고 있는 데이터베이스가 있아는 것만으로는 충분하지 않다. 실질적인 애플리케이션이 필요하다. 컨디트가 항상 실행되는 Mac OS에서는 이것은 사실이 아니며 단지 상황을 흥미롭게 만들어가는 것뿐이다.
만약 항상 실행할 컨디트가 없다면 단지 컨디트를 실행하도록 유도하기 위해 존재하는 소형 애플리케이션을 만들어야 한다. 만약 유저가 그것을 보지 않기를 원한다면 항상 볼 수 없는 비트로 설정해놓을 수도 있다.
테스트를 도울 간단한 트릭이 있다. 여러분은 컨디트를 생성자 calc(계산기)로 등록할 수 있다. 그 애플리케이션은 항상 거기에 있으면서 컨디트를 실행하게 할 것이다. 그렇지만 최종 컨디트를 위해 생성자를 바꾸어 주어야 함을 기억해야 한다. 그리고 탑재된 컨디트에 대해서는 절대 calc를 사용할 수 없다.
함정 #4: 표준 C 라이브러시의 사용
표준 C 라이브러리를 이용할 수 있음에도 불구하고 일반적으로 잘 사용되지는 않는다. 대신 표준 C 루틴과 비슷한 Palm-OS용 API를 사용한다. Palm-OS 루틴을 선호하는 두 가지 이유는 다음과 같다.
- 코드는 애플리케이션보다는 오히려 ROM에 있다. 만약 표준 C 라이브러리를 사용하고 있다면 그것들은 애플리케이션으로 링크 되어 있어야 하고 애플리케이션은 필요이상으로 커지게 될 것이다.
- ROM 라이브러리 코드는 Palm-OS에 정통해 있다. 예를 들어 스트링 루틴은 멀티바이트 문자(예를 들어 히라가나 같은 일본어)를 인식해서 각각의 경우에 대해 적절한 것을 실행한다.
그렇다고 해서 Palm-OS 루틴과 C 루틴을 항상 정확하게 교환할 수 있다고는 볼 수는 없다. 표 1은 표준 C 루틴에 대한 Palm OS 루틴이 서로 다름을 보여준다.
표 1: 표준 C 루틴에 대한 Palm OS 루틴
표준 C 루틴 | Palm OS 루틴 | 부가 정보 |
strlen | StrLen | |
strcpy | StrCopy | |
strncpy | StrNCopy | 여분의 널(null) 종결자와 함께 패딩하지 말 것. |
strcat | StrCat | |
strncat | StrNCat | 마지막 매개변수는 복사할 문자의 숫자가 보다는 널 종결자를 포함한 스트링의 총 길이이다. 소스 스트링이 비어있다고 해도 여분의 널 종결자를 덧붙이지 말 것. |
strcmp | StrCompare | |
strncmp | StrNCompare | |
itoa | StrIToA | |
strchr | StrChr | |
strstr | StrStr | |
sprintf | StrPrintF | sprintf의 한정된 서브세트 예를 들어 no %f. |
svprintf | StrVPrintF | sprintf의 한정된 서브세트 예를 들어 no %f. |
malloc | MemPtrNew | |
free | MemPtrFree | |
memmove | MemMove | |
memset | MemSet | 경고: 마지막 두 매개변수는 개정되었음. |
memcmp | MemCmp | |
함정 #5: 팝업 트리거에 대한 잘못된 이벤트를 찾는 것
리스트들이 스스로 lstSelectEvent를 생성함에도 불구하고 팝업은 실행되지 않는다. 대신 그것들은 popSelectEvent를 생성한다.
유저가 팝업 트리거로부터 아이템을 선택할때 어떻게 말해야 될지를 모르겠다면 여러분은 이와 같은 문제를 가지고 있는 것이다. lstSelectEvent에 대한 코드는 운영체제가 popSelectEvent을 대신 전달하기 때문에 실행되지 않는다.
함정 #6: 첫번째 FrmDrawForm전에 그리는 것
폼의 첫번째 호출을 FrmDrawForm로 하기 전에 폼에서 어떤 것도 그릴 수 없는지에 대한 이유는 다음과 같다.
- 만약 Palm OS 3.5이상에서 모델 다이얼로그나 Palm OS 3.5보다 우월한save-behind 폼을 가지고 있다면 그 아래 영역은 첫번째 콜이 FrmDrawForm일 때까지 지워지지 않을 것이다. 따라서 당신이 하는 그리기는 재빠르게 지워질 것이다.
- 폼의 save-behind 비트가 설정되는 또다른 문제가 있다면 그 아래 영역은 첫번재 콜이 FrmDrawForm 일 때까지 저장되지 못한다. 만약 이미 첫번째 콜 전에 그리기를 했다면 저장된 지역은 그리기 영역을 포함하여 저장 할 것이다. 폼을 닫을때 복구 비트는 여분의 그리기 영역을 포함하기 때문에 원래 되어야할 모양과는 다른 형태로 저장된다.
- 버전 3.5 이후의 디버깅 롬은 그것을 허락지 않는다.(만약 여러분이 첫번째 FrmDrawForm 전에 그리기를 시도했다면 아마도 런타임 오류 메시지를 보게될 것이다)
대부분의 폼 오브젝트 API들은 그것들이 그릴 것과 그렇지 않을 것에 대해 인지하고 있다. (예를 들어 체크박스를 위한 CtlsetValue는 폼이 적어도 한번 그리기를 했을 경우에만 스크린 상태를 업데이트할 것이다.) 그렇지만 조심해야 할 호출도 있다. FldDrawField, TblRedrawTable 등과 같은 명백한 그리기 호출이 그것이다.
함정 #7: FrmDrawForm로 첫번재 호출을 한 후에 FrmSetFocus 하는 것을 잊는 것
Palm OS 3.5이상에서 버그들은 필드를 포커스하는 것과 관련하여 존재했다. 만약 첫번재 호출로 FrmDrawForm을 하기 전에 FrmSetFocus을 호출하면 삽입 필드는 포커스된 필드에 나타나지 않을 것이다. 이런 문제를 처리하기 위해 FrmDrawForm의 첫번째 호출 후에 FrmSetFocus를 호출해야 한다.
Palm OS 3.5이상에서 버그가 수정되었음에도 불구하고 버그는 FrmDrawForm을 첫번째로 호출 한 후 FrmSetFocus을 계속해서 호출하는데 영향을 미치지 않는다.
함정 #8: FrmCopyLabel 대신 CtlSetLabel을 사용하는 것
라벨이라는 단어는 품에서 실행되어 질때 두 가지 다른 인스턴스에서 사용된다. 첫번째 용도는 폼과 관련있는 것으로 스스로 라벨을 가질 수 있다(예를 들어 특정 폰트로 어떤 지역에 있는 텍스트). 두 번째 용도는 컨트롤 매니저에 의한 것으로 라벨이 컨트롤 할 때 사용된다. 이 용도는 컨트롤을 가질때 사용되는데 컨트롤의 텍스트를 변경하기 위하여 컨트롤 매니저 루틴인 CtlSetLabel을 사용하게 될 것이다.
그외의 경우(콘트롤이 없는 옛날 라벨을 가지고 있을때)에서는 FrmCopyLabel을 사용한다.
함정 #9: Palm OS 프로그래밍을 배우는 동시에 C를 배우려고 하는 것
대부분의 Palm OS 프로그래머들은 Palm OS 플랫폼에서 C 프로그매밍을 배우려는 것이 상당히 어렵다고 말한다. 만약 여러분이 능숙한 C 프록래머가 아니라면 단순한 환경에서 프로그래밍 언어를 배우는 것이 더 쉬울 것이다. C 언어를 배우기 위한 방법으로
CodeWarrior University라는 무료 학습 사이트의 "Learn Programming with C"라는 목록에서 프로그래밍 하는 방법과 C를 사용하는 방법에 대해 배울 수 있을 것이다.
함정 #10: 디버그 ROMs과 POSE 사용에 실패하는 것
POSE (Palm OS Emulator)와 Debug ROMs은 핸드헬드에서는 인지하지 못하는 많은 에러를 잡아내는 강력한 디버깅 조합을 만들어 낸다.
Palm OS Developers site에서 해당하는 도구를 다운 받을 수 있다.
Palm OS에 대한 엄청난 정보를 가지고 있지만 POSE는 Palm OS 디바이스의 하드웨어를 에뮬레이트 한다. 함수 호출, 메모리 저장이나 로드, 레지스터 액세스, 액세스를 인정하는 검공기 등을 볼 수 있다.
Debug ROMs은 Palm Os APIs가 실제적인 디바이스인 ROM에서 추가적인 체크를 하게 한다. 테스팅과 디버깅은 POSE와 Debug ROMs를 항상 함께 사용하는 것으로 시작해야 한다.
만약 이 도구를 사용하는 동안 에러가 나타난다면 그것을 수정해야 한다. 그것은 실제적인 디바이스에서 계속해서 나타날 문제가 될 수도 있으며 잠깐 나타났다 없어질 문제일 수도 있다. 또한 오늘날의 디바이스에서는 문제되지 않을 수도 있지만 미래의 디바이스에서는 문제가 될 수도 있기 때문에 에러는 항상 수정해 주는 것이 좋다.
네일 로드(Neil Rhodes)와
줄리 맥케한(Julie McKeehan)은 커스텀 프로그래밍과 Palm OS 강의를 전문으로 하는
Calliope Enterprise의 사장이다. 이 회사의 고객으로는 Palm, Symbol, Palm OS 라이센스를 다루는 회사와 개인 Palm 솔루션을 다루는 회사들이다. 이 두 사람은 프로그램밍 책을 많이 집필했다. 뿐만 아니라 Palm, Symbol 등등에 의해 사용되는 3개의 Palm OS 프로그래밍 클래스를 개발했으며 전 세계 개발자들에게 Palm OS 프로그래밍을 가르친다. 네일과 줄리는 8년간 핸드헬드 개발에 몰두해왔으며 이 분야에 있어서는 전문가이다.