. 레코드 초기화

취소 레코드의 타입은 정의했고 다음은 이 레코드를 관리하기 위한 변수를 추가하도록 하자. 다음 세 개의 변수를 CApiEdit 클래스에 선언하여 멤버로 포함시킨다.

 

class CApiEdit

{

     ....

     UndoRecord *pUR;

     int URSize;

     int nowur;

 

편집 동작 하나에 대해 하나의 취소 레코드가 필요하며 편집은 연속적으로 이루어지므로 배열을 구성해야 한다. 배열의 크기를 미리 정할 수 없으므로 일단 포인터 변수 pUR을 선언하고 이 포인터에 배열을 할당하여 사용할 것이다. 편집 동작이 많아지면 실행중에 배열크기를 늘려야 하므로 할당된 크기를 URSize에 저장한다.

nowur은 현재 기록하고 있는 레코드 배열의 첨자이며 이 레코드를 현재 레코드라고 한다. 현재 레코드의 정확한 성격을 규정하는 것은 상당히 어려운 일인데 nowur은 지금 작성중인 레코드 또는 방금 취소한 레코드로 정의하였다. 다음 작성할 레코드가 아니고 다음 취소할 레코드를 가리키는 것도 아니며 항상 현재 사용하고 있는 레코드를 가리킨다. 이 변수를 어떻게 정의하는가에 따라 기록 후 레코드를 이동할 것인가 아니면 레코드를 먼저 이동하고 기록을 할 것인가의 미묘한 차이가 발생하게 된다. 생성자에서 일단 pUR NULL로 초기화한다.

 

CApiEdit::CApiEdit()

{

     ....

     pUR=NULL;

}

 

동적으로 할당되는 배열이기 때문에 처음부터 NULL이어야 하며 생성자에서 쓰레기값을 없애기 위해 NULL로 초기화했다. 이 변수를 의미있는 값으로 초기화하는 일은 문서가 처음 작성될 때인 InitDoc에서 해야 한다. InitDoc에서 초기화를 하므로 WM_CREATE에서는 따로 초기화를 할 필요가 없다.

 

void CApiEdit::InitDoc()

{

     if (pUR) {

          for (i=0;;i++) {

              if (pUR[i].action == UR_NONE)

                   break;

              if (pUR[i].data)

                   free(pUR[i].data);

          }

          free(pUR);

     }

     URSize=100;

     pUR=(UndoRecord *)malloc(sizeof(UndoRecord)*URSize);

     memset(pUR,0,sizeof(UndoRecord)*URSize);

     nowur=0;

     ....

 

문서 사용중에 재초기화를 하는 경우도 있으므로 pUR 배열이 이미 할당되어 있으면 할당을 취소한다. 이때 레코드의 멤버인 data도 할당을 취소해야 한다. 레코드의 초기 크기는 100으로 잡았으며 이 크기만큼 배열을 할당한다. 편집중에 더 필요하면 이 크기는 동적으로 늘어나게 된다. data 멤버는 레코드 할당시에 같이 할당하는 것이 아니라 레코드에 기록하기 직전에 필요한 크기만큼 할당한다. ApiEdit가 파괴되기 직전에 모든 취소 레코드들은 해제되어야 하는데 OnDestroy에 다음 코드를 작성한다.

 

void CApiEdit::OnDestroy(HWND hWnd)

{

     ....

     if (pUR) {

          for (int i=0;;i++) {

              if (pUR[i].action == UR_NONE)

                   break;

              if (pUR[i].data)

                   free(pUR[i].data);

          }

          free(pUR);

     }

}

 

InitDoc에서 pUR을 해제하는 코드와 동일하며 별도의 함수로 분리할 수도 있다.