Delphi Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
델파이 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
FreePascal/Lazarus
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
델마당
볼랜드포럼 광고 모집

델파이 강좌/문서
Delphi Programming Tutorial&Documents
[113] 델파이 VCL 애플리케이션의 VCL.NET 마이그레이션
박지훈.임프 [cbuilder] 9168 읽음    2007-01-13 08:45
원문 : http://dn.codegear.com/article/32983

델파이 VCL 애플리케이션의 VCL.NET 마이그레이션


- 밥 스워트 (Bob Swart)




요약: 이 강좌에서는 볼랜드 델파이 2005와 VCL.NET을 이용하여 델파이 Win32 소스 코드, 유닛, (데이터베이스) 애플리케이션을 .NET 프레임워크로 마이그레이션하는 방법을 설명합니다.

서론

이 강좌에서는 델파이 2005에서 볼랜드 VCL을 프레임워크로 이용하여 실제 Win32 애플리케이션을 .NET 프레임워크로 마이그레이션할 것입니다. 델파이 7의 Demos 디렉토리로부터 가져온 많은 기존의 Win32 VCL 애플리케이션을 델파이 2005에서 열어서 VCL.NET을 이용하여 .NET 기반으로 마이그레이션하겠습니다.

이런 연습을 통해 몇가지 작지만 중요한 마이그레이션 관련 문제들을 보여줄 것입니다.

VCL과 VCL.NET

VCL이 .NET 프레임워크에서 사용할 수 있게 됨으로써 Win32 VCL 애플리케이션을 .NET으로 쉽게 마이그레이션할 수 있게 되었습니다. (VCL 프로젝트를 WinForms로 옮길 수도 있습니다)

델파이 2005는 BDS\3.0\Demos 디렉토리에 많은 예제 애플리케이션을 포함하고 있는데, 그중에 Delphi.NET 및 DelphiWin32 서브디렉토리가 있습니다. BDS\3.0\DelphiWin32\VCLWin32\ 디렉토리에는 몇가지 Win32 VCL 예제들이 포함되어 있는데, 그중 몇가지는 이미 .NET으로 마이그레이션되어 있으며 BDS\3.0\Delphi.NET\VCL 디렉토리에서 찾아볼 수 있습니다.

.NET으로 마이그레이션되지 않은 예제들 중 하나는 Threads 예제인데, 이것은 QuickSort, SelectionSort 및 BubbleSort 알고리즘을 멀티 쓰레드로 보여주는 것입니다. 이 Threads 프로젝트가 우리가 VCL.NET을 이용하여 .NET으로 마이그레이션할 Win32 VCL 애플리케이션입니다.

먼저, 필요한 파일들을 복사합니다.

- BDS\3.0\Demos\Delphi.NET\VCL 디렉토리에 새 서브디렉토리 Threads를 만듭니다. 지금 진행하는 마이그레이션의 결과는 델파이.NET VCL 프로젝트의 또다른 예제가 될 것입니다.

- BDS\3.0\Demos\DelphiWin32\VCLWin32\Threads 디렉토리의 모든 파일을 BDS\3.0\Demos\Delphi.NET\VCL\Threads 디렉토리로 복사합니다.

- thrddemo.bdsproj 파일을 삭제합니다. 이 파일은 이 프로젝트가 델파이 Win32 프로젝트라는 사실을 저장하고 있는데 우리는 .NET으로 마이그레이션하려고 하기 때문입니다.

이제 우리는 새 Threads 프로젝트를 작업하여 .NET으로 마이그레이션할 준비가 되었습니다.

- 델파이 2005를 시작시킵니다.

- Welcome Page의 Open Project 버튼을 클릭하고 조금전에 파일들을 복사한 BDS\3.0\Demos\Delphi.NET\VCL\Threads 디렉토리로부터 thrddemo.dpr 프로젝트 파일을 엽니다.

이 프로젝트에는 연결된 .bdsproj 파일이 없기 때문에, 델파이 2005 IDE는 이 프로젝트를 Win32 혹은 .NET 프로젝트중 어느 쪽으로 업그레이드할 지 여러분에게 물어봐야 합니다. 델파이2005는 아래와 같은 Project Upgrade 다이얼로그에서 이처럼 물어보게 됩니다.

thrddemo 프로젝트를 .NET으로 업그레이드하겠습니까?

- "Delphi for .NET" 항목을 선택하고 OK 버튼을 클릭합니다.

이렇게 하면 .NET 퍼스낼리티가 지정된 thrddemo.bdsproj 파일이 생성됩니다. 이제 이 프로젝트를 저장하면 새 퍼스낼리티 정보가 thrddemo.bdsproj 파일에 저장됩니다.

- 메인메뉴에서 File | Save All 항목을 선택하여 thrddemo 프로젝트를 저장합니다. 이 프로젝트에는 thrddemo.bdsproj 파일도 포함되어 있습니다.

- Ctrl+F9 키를 눌러 thrddemo 프로젝트를 처음으로 컴파일합니다.

컴파일 결과, 다음과 같이 11개의 워닝들과 5개의 에러가 발생할 것입니다.

[Warning] thrddemo.dpr(8): W1005 Unit 'Borland.Vcl.Forms' is specific to a platform
[Warning] ThSort.pas(6): W1005 Unit 'Borland.Vcl.Windows' is specific to a platform
[Warning] ThSort.pas(6): W1005 Unit 'Borland.Vcl.Messages' is specific to a platform
[Warning] ThSort.pas(6): W1005 Unit 'Borland.Vcl.Graphics' is specific to a platform
[Warning] ThSort.pas(6): W1005 Unit 'Borland.Vcl.Controls' is specific to a platform
[Warning] ThSort.pas(6): W1005 Unit 'Borland.Vcl.Forms' is specific to a platform
[Warning] ThSort.pas(6): W1005 Unit 'Borland.Vcl.Dialogs' is specific to a platform
[Warning] ThSort.pas(7): W1005 Unit 'Borland.Vcl.ExtCtrls' is specific to a platform
[Warning] ThSort.pas(7): W1005 Unit 'Borland.Vcl.StdCtrls' is specific to a platform
[Warning] SortThds.pas(6): W1005 Unit 'Borland.Vcl.Graphics' is specific to a platform
[Warning] SortThds.pas(6): W1005 Unit 'Borland.Vcl.ExtCtrls' is specific to a platform
[Error] SortThds.pas(18): E2397 Unsafe pointer only allowed if compiling with {$UNSAFECODE ON}
[Error] SortThds.pas(57): E2003 Undeclared identifier: 'Point'
[Error] SortThds.pas(65): E2396 Unsafe code only allowed in unsafe procedure
[Error] SortThds.pas(107): E2396 Unsafe code only allowed in unsafe procedure
[Fatal Error] ThSort.pas(39): F2063 Could not compile used unit 'SortThds.pas'

일단 워닝은 모두 무시하고 나중에 다시 살펴보겠습니다. 지금은 컴파일러 에러들을 수정해봅시다.

첫번째 에러는 SortThds.pas의 18 라인에서 발생한 "unsafe pointer only allowed if compiling with {$UNSAFECODE ON}" 에러입니다. 이 에러를 발생시킨 실제 라인은 TSortThread 클래스 정의에서 FSortArray를 PSortArray 타입으로 선언한 부분입니다.

type
  PSortArray = ^TSortArray;
  TSortArray = array[0..MaxInt div SizeOf(Integer) - 1] of Integer;

  TSortThread = class(TThread)
  private
    FBox: TPaintBox;
    FSortArray: PSortArray;

PSortArray는 TSortArray에 대한 포인터인데 포인터는 safe 타입이 아니기 때문에 에러가 발생한 것입니다. 이 에러 뒤에도 unsafe 포인터 타입의 사용에 관련된 여러 unsafe 에러들이 있다는 것을 볼 수 있습니다.

최종 결과는 unsafe 타입이나 unsafe 코드를 전혀 갖지 않게 되겠지만, 일단은 코드를 unsafe로 표시하고 넘어감으로써 컴파일러 에러를 쉽게 없앨 수 있습니다. 먼저 프로젝트가 성공적으로 컴파일되게 한 후 unsafe한 부분들을 safe 코드로 바꾸겠습니다.

- TSortThread 클래스 정의의 앞에 {$UNSAFECODE ON} 컴파일러 디렉티브를 추가합니다. 이렇게 하면 컴파일시 FSortArray 필드의 선언이 에러 없이 넘어가게 됩니다.

- Shift+F2 키를 눌러 프로젝트의 모든 파일들을 저장하고 다음으로 Shift+F9 키를 눌러 프로젝트를 리빌드합니다.

워닝役湧?무시하면, 4개의 에러가 남아있을 것입니다.

[Error] SortThds.pas(59): E2003 Undeclared identifier: 'Point'
[Error] SortThds.pas(67): E2396 Unsafe code only allowed in unsafe procedure
[Error] SortThds.pas(109): E2396 Unsafe code only allowed in unsafe procedure
[Fatal Error] ThSort.pas(39): F2063 Could not compile used unit 'SortThds.pas'

Point라는 것이 뭔지 모르겠다는 에러군요. 문제가 되는 실제 라인은 다음과 같습니다.

procedure PaintLine(Canvas: TCanvas; I, Len: Integer);
begin
  Canvas.PolyLine([Point(0, I * 2 + 1), Point(Len, I * 2 + 1)]);
end;

Point 함수에 대한 호출이 두번 나오는데, 어떤 이유인지 .NET 컴파일러가 Point 함수를 찾지 못한 거 같네요. 리팩토링의 Find Unit 기능을 써볼 좋은 기회입니다. 이 기능은 Point 함수 선언을 가진 유닛을 찾아 uses 절에 추가할 수 있게 도와줄 것입니다.

- 코드 에디터에서 커서를 'Point'에 위치한 후 마우스 오른쪽 클릭하여 Refactor 메뉴의 Find Unit 서브메뉴를 선택합니다.

Find Unit 다이얼로그가 나타나고 Search 부분에 Point가 이미 표시되어 있습니다. 여러 유닛들이 나열될 텐데 그중에 가장 Point의 선언을 가지고 있을 만한 것으로 Borland.Vcl.Types.Point가 보일 것입니다.

- Borland.Vcl.Types.Point 유닛을 선택하고 SortThds.pas 유닛에 추가될 uses 절에 따라 Interface나 Implementation 둘 중 아무거나 선택합니다.

Refactoring - Find Unit

- Shift+F2 키를 눌러 프로젝트의 모든 파일을 저장하고 다시 Shift+F9 키를 눌러 프로젝트를 리빌드합니다.

이제 3개의 에러가 남았습니다. 항상 그렇듯이, 마지막 에러는 앞의 두개의 에러가 발생했기 때문에 발생한 것입니다. 따라서 실제로는 수정할 에러는 2개 남은 것입니다.

[Error] SortThds.pas(70): E2396 Unsafe code only allowed in unsafe procedure
[Error] SortThds.pas(112): E2396 Unsafe code only allowed in unsafe procedure
[Fatal Error] ThSort.pas(39): F2063 Could not compile used unit 'SortThds.pas'

우리는 아직 FSortArray에서 unsafe 포인터를 사용하고 있으며, 이것이 2개의 에러가 발생한 이유입니다. 첫번째 에러는 Create 생성자의 코드에 관계되어 있는데, SortArray 인자의 주소를 얻어서 그것을 unsafe한 FSortArray 포인터에 대입하고 있습니다. 이 코드는 unsafe하며, Create 생성자를 unsafe 키워드로 표시하지 않으면 컴파일되지 않습니다.

- unsafe 키워드를 Create 생성자의 구현 부분에 추가합니다.

constructor TSortThread.Create(Box: TPaintBox; var SortArray: array of Integer); unsafe;
begin
  FBox := Box;
  FSortArray := @SortArray;
  FSize := High(SortArray) - Low(SortArray) + 1;
  FreeOnTerminate := True;
  inherited Create(False);
end;

- Shift+F2 키를 눌러 프로젝트의 모든 파일들을 저장하고 다음으로 Shift+F9 키를 눌러 프로젝트를 리빌드합니다.

이제 Create 생성자의 unsafe 코드 관련 에러는 사라졌습니다. 하지만 Create 생성자와 관련하여 또다른 에러가 나타났습니다.

[Error] SortThds.pas(72): E2305 'Self' might not have been initialized
[Error] SortThds.pas(112): E2396 Unsafe code only allowed in unsafe procedure
[Fatal Error] ThSort.pas(39): F2063 Could not compile used unit 'SortThds.pas'

이 에러는 우리가 몇가지 속성 초기화 작업을 한 후에 inherited constructor를 호출한 것과 관련이 있습니다. 하지만 그래야 할 마땅한 이유가 있지 않은 한, inherited constructor를 다른 코드보다 먼저 호출하는 것을 권합니다. 물론 이것은 쉽게 수정할 수 있습니다.

- inherited Create 호출을 Create의 가장 앞 라인으로 이동시킵니다. 다음과 같이 되었을 것입니다.

constructor TSortThread.Create(Box: TPaintBox; var SortArray: array of Integer); unsafe;
begin
  inherited Create(False);
  FBox := Box;
  FSortArray := @SortArray;
  FSize := High(SortArray) - Low(SortArray) + 1;
  FreeOnTerminate := True;
end;

- Shift+F2 키를 눌러 프로젝트의 모든 파일들을 저장하고 다음으로 Shift+F9 키를 눌러 프로젝트를 리빌드합니다.

이제 수정할 에러는 하나만 남았습니다. 다시 unsafe 코드 에러입니다.

[Error] SortThds.pas(112): E2396 Unsafe code only allowed in unsafe procedure
[Fatal Error] ThSort.pas(39): F2063 Could not compile used unit 'SortThds.pas'

이번에는 Execute 메소드에서 unsafe한 포인터 FSortArray에 ^ 연산자를 사용한 것이 문제입니다. 앞에서와 마찬가지로 이 메소드에 unsafe 키워드를 추가함으로써 에러를 없앨 수 있습니다.

- unsafe 키워드를 Execute 메소드의 구현 부분에 추가합니다.

procedure TSortThread.Execute; unsafe;
begin
  Sort(Slice(FSortArray^, FSize));
end;

- Shift+F2 키를 눌러 프로젝트의 모든 파일들을 저장하고 다음으로 Shift+F9 키를 눌러 프로젝트를 리빌드합니다.

[Error] SortThds.pas(114): E2454 Slice standard function not allowed for VAR nor OUT argument
[Fatal Error] ThSort.pas(39): F2063 Could not compile used unit 'SortThds.pas'

이번에는 좀 더 큰 문제입니다. 몇가지 이유로, Slice 함수는 .NET 환경에서 인자를 넘기는 방식에 문제가 있습니다. 실제로 하는 작업의 내용을 살펴보면 Slice 호출을 무시하고 FSortArray^를 그대로 Sort에 넘겨도 안전할 것으로 보입니다. Sort 메소드 안에서 배열의 실제 사이즈를 알아내기 위해 High와 Low를 사용하는데, 문제 없이 동작할 것입니다. (잠시 후에 이 코드를 safe한 매니지드 코드로 바꿀 것입니다)

- Slice 표준 함수를 이용하는 Sort 호출을 제거하고, 다음과 같이 FSortArray^ 만을 인자로 받는 Sort 호출로 바꿉니다.

procedure TSortThread.Execute; unsafe;
begin
//  Sort(Slice(FSortArray^, FSize));
  Sort(FSortArray^);
end;

- Shift+F2 키를 눌러 프로젝트의 모든 파일들을 저장하고 다음으로 Shift+F9 키를 눌러 프로젝트를 리빌드합니다.

이제 워닝들만 남았습니다.

[Warning] thrddemo.dpr(8): W1005 Unit 'Borland.Vcl.Forms' is specific to a platform
[Warning] ThSort.pas(6): W1005 Unit 'Borland.Vcl.Windows' is specific to a platform
[Warning] ThSort.pas(6): W1005 Unit 'Borland.Vcl.Messages' is specific to a platform
[Warning] ThSort.pas(6): W1005 Unit 'Borland.Vcl.Graphics' is specific to a platform
[Warning] ThSort.pas(6): W1005 Unit 'Borland.Vcl.Controls' is specific to a platform
[Warning] ThSort.pas(6): W1005 Unit 'Borland.Vcl.Forms' is specific to a platform
[Warning] ThSort.pas(6): W1005 Unit 'Borland.Vcl.Dialogs' is specific to a platform
[Warning] ThSort.pas(7): W1005 Unit 'Borland.Vcl.ExtCtrls' is specific to a platform
[Warning] ThSort.pas(7): W1005 Unit 'Borland.Vcl.StdCtrls' is specific to a platform
[Warning] SortThds.pas(6): W1005 Unit 'Borland.Vcl.Graphics' is specific to a platform
[Warning] SortThds.pas(6): W1005 Unit 'Borland.Vcl.ExtCtrls' is specific to a platform
[Warning] SortThds.pas(71): W1047 Unsafe code '@ operator'
[Warning] SortThds.pas(113): W1047 Unsafe code '^ operator'

대부분의 워닝들은 VCL.NET이 플랫폼에 한정적이라는 것을 의미하는데 이것은 놀랄 것도 아닙니다. 2개의 워닝은 좀 더 심각한데, unsafe한 코드인 @ 및 ^ 연산자를 사용하기 때문에 발생한 것입니다. 이 문제에 대해서는 나중에 다시 살펴보겠습니다. 지금은 워닝들을 무시하고 프로젝트를 실행해봅니다.

Threads 정렬 데모의 .NET 버전

이 애플리케이션은 총 세개의 쓰레드를 가진 네이티브 .NET 실행파일로서 실행됩니다.

하지만 이것은 100% safe 애플리케이션이 아니므로, 이제 그런 측면에서 작업해봅시다.

Safe 코드

unsafe 코드를 가진 애플리케이션은 PEVerify으로 체크할 때 실패합니다. 여러분은 이 상태를 중간 마이그레이션 결과로서 그대로 수용할 수도 있겠지만, 최종 목표로서 100% safe한 .NET 애플리케이션을 원할 수 있습니다.

- {$UNSAFECODE ON} 컴파일러 디렉티브와 Create 생성자 및 Execute 메소드에 있는 2개의 unsafe 키워드도 삭제한 후 unsafe한 코드 부분들을 수정할 준비를 합시다.

첫번째 문제(다른 모든 문제를 발생시키죠)는, 포인터 타입을 선언한 것입니다. TSortArray 선언을 "array of integer"으로 치환할 수 있습니다. 코드가 .NET 뿐만 아니라 Win32 컴파일러에서도 컴파일될 수 있도록 하고 싶다면 원래의 코드와 새 코드를 구분하기 위해 컴파일러 디렉티브를 사용할 수 있습니다.

- TSortArray의 타입 선언을 array of integer로 바꾸고 다음과 같이 이전의 WIN32 선언과 새 .NET 선언을 구별하기 위한 컴파일러 디렉티브를 사용합니다.

{$IFDEF WIN32}
  PSortArray = ^TSortArray;
  TSortArray = array[0..MaxInt div SizeOf(Integer) - 1] of Integer;
{$ELSE}
  TSortArray = array of Integer;
{$ENDIF}

- Shift+F2 키를 눌러 프로젝트의 모든 파일들을 저장하고 다음으로 Shift+F9 키를 눌러 프로젝트를 리빌드합니다.

이번에는, FSortArray의 선언에 대한 에러 메시지가 나타날 것입니다. 이제는 PSortArray가 알 수 없는 타입이기 때문입니다. .NET 환경에서는 FSortArray를 TSortArray 타입으로 선언할 수 있습니다. Using the .NET compiler, we can simply define FSortArray as being of type TSortArray.

- FSortArray 필드의 타입을 PSortArray에서 TSortArray로 바꿉니다. 만약 WIN32와 .NET 양쪽 모두에서 컴파일되도록 하기 위해 컴파일러 디렉티브를 사용하려 한다면, 다음과 같이 될 것입니다.

  TSortThread = class(TThread)
  private
    FBox: TPaintBox;
    FSortArray: {$IFDEF WIN32}PSortArray{$ELSE}TSortArray{$ENDIF};

- Shift+F2 키를 눌러 프로젝트의 모든 파일들을 저장하고 다음으로 Shift+F9 키를 눌러 프로젝트를 리빌드합니다.

이번에는 create 생성자에서 @ 연산자가 사용될 수 없다는 에러가 날 것입니다.

- 다음과 같이 Create 생성자에서 @ 연산자를 제거합시다.

constructor TSortThread.Create(Box: TPaintBox; var SortArray: array of Integer);
begin
  inherited Create(False);
  FBox := Box;
  FSortArray := {$IFDEF WIN32}@{$ENDIF}SortArray;
  FSize := High(SortArray) - Low(SortArray) + 1;
  FreeOnTerminate := True;
end;

- Shift+F2 키를 눌러 프로젝트의 모든 파일들을 저장하고 다음으로 Shift+F9 키를 눌러 프로젝트를 리빌드합니다.

마지막 에러는 Execute 메소드에서 ^ 연산자를 사용한 것에 대한 것입니다. .NET 컴파일러를 이용하는 경우 위에서처럼 제거할 수 있습니다. 다음과 같이 바꿉니다.

procedure TSortThread.Execute;
begin
//  Sort(Slice(FSortArray^, FSize));
  Sort(FSortArray{$IFDEF WIN32}^{$ENDIF});
end;

*Sort는 인자를 var 형태로 받으므로 여기서 전체 정수 배열을 전달하는 데 대해서는 걱정할 필요가 없습니다. (otherwise it would make sense to see if you could add a const keyword).

- Shift+F2 키를 눌러 프로젝트의 모든 파일들을 저장하고 다음으로 Shift+F9 키를 눌러 프로젝트를 리빌드합니다.

이제 unsafe code 에러는 모두 사라졌고 platform specific 워닝만 남은 상태입니다. 이제 이 예제는 VCL.NET을 이용하는 네이티브, 세이프, 매니지드 .NET 실행파일이 된 것입니다. Threads 데모에서는 빠르지만 깔끔하지 못한 마이그레이션을 보여드렸습니다. 다음으로 완전히 safe하고 매니지드한 마이그레이션 방식을 보여드리겠습니다.

데이터 액세스

지금까지 VCL 애플리케이션을 .NET으로 마이그레이션해봤습니다. 이제는 더 현실적이고 더 큰 규모의 애플리케이션으로 넘어가봅시다. 여기에는 데이터 액세스도 포함되므로, Delphi7\Demos\Db 디렉토리를 살펴봅시다. 이 디렉토리에는 몇가지 예제 애플리케이션들이 있는데, MastApp와 IBMastApp 예제가 가장 크고 또 가장 많은 유닛 및 폼을 포함하고 있습니다.

만약 델파이7이 없다면 BDS\3.0\Demos\DelphiWin32\Db 디렉토리에 있는 MastApp와 IBMastApp 예제를 이용하면 됩니다. (하지만 이미 새 프로젝트 포맷으로 변환되어 .bdsproj 파일이 있는 상태입니다)

MastApp 예제는 이미 .NET으로 마이그레이션되어 BDS\3.0\Demos\Delphi.NET\DB\MastApp 디렉토리에 존재하지만 IBMastApp 예제는 마이그레이션이 되어있지 않습니다.

그러므로 이번 예제로서 IBMastApp 예제를 Win32에서 .NET으로 마이그레이션해보도록 합시다. 이 예제는 단순하지 않은 데이터베이스 애플리케이션입니다.

먼저, 필요한 파일들을 복사합니다.

- BDS\3.0\Demos\Delphi.NET\VCL\Db 디렉토리 아래에 IBMastApp라는 새 디렉토리를 만듭니다. 우리 마이그레이션 작업의 결과는 델파이.NET VCL DB 프로젝트의 예제로 추가될 것입니다.

- BDS\3.0\Demos\DelphiWin32\VCLWin32\Db\IBMastApp 디렉토리의 모든 파일들을 BDS\3.0\Demos\Delphi.NET\VCL\Db\IBMastApp 디렉토리로 복사합니다.

- mastapp.bdsproj 파일을 삭제합니다. 이 파일은 해당 프로젝트가 델파이 Win32 프로젝트라는 정보를 가지고 있습니다. (우리는 Win32 대신 .NET으로 마이그레이션하려고 하고 있죠)

이제 IBMastApp 프로젝트를 작업하여 .NET으로 마이그레이션할 준비가 된 것입니다.

- 델파이 2005를 실행시킵니다.

- Welcome Page에서 Open Project 버튼을 클릭하여 BDS\3.0\Demos\Delphi.NET\VCL\Db\IBMastApp 디렉토리에서 mastapp.dpr 파일을 엽니다. (조금 전에 Win32 데모로부터 복사한 복사본입니다)

이 프로젝트는 .bdsproj 파일을 가지고 있지 않으므로, 델파이 2005 IDE는 이 프로젝트를 Win32 혹은 .NET으로 업그레이드할 지를 물어보게 됩니다. 다음 그림과 같은 Project Upgrade dialog가 나타날 것입니다.

mastapp 프로젝트를 .NET으로 업그레이드합니다

- 'Delphi for .NET' 항목을 선택하고 OK 버튼을 클릭합니다.

.NET 퍼스낼리티가 지정된 mastapp.bdsproj 파일이 생성됩니다. 이제 프로젝트를 저장하여 새 퍼스낼리티 정보가 mastapp.bdsproj 파일에 저장되도록 할 것입니다.

- File | Save All 항목을 선택하여 mastapp 프로젝트를 저장하면 새 mastapp.bdsproj 파일도 함께 저장됩니다.

데이터모듈 마이그레이션하기

먼저 데이터베이스가 정확한 위치를 가리키고 있는지부터 확인합니다. 이것은 애플리케이션을 처음 컴파일하려고 하기 전에 하는 것이 좋습니다. 일단 데이터베이스 연결이 정확하게 설정되고 나면 소스 코드의 마이그레이션에만 집중할 수 있게 됩니다.

- 프로젝트 매니저에서 DataMod.pas 파일을 더블클릭하여 데이터모듈을 엽니다.

데이터모듈은 데이터 액세스 기술로 인터베이스 익스프레스 컴포넌트들을 이용하고 있으며 다음의 그림처럼 디자인되어 있습니다.

디자인타임 VCL.NET 데이터모듈

데이터베이스 컴포넌트를 다시 설정할 필요가 있습니다. 이 컴포넌트는 오른쪽 아래편에 있습니다.

- 데이터모듈의 데이터베이스 컴포넌트(TIBDatabase 타입)를 클릭합니다.

- 데이터베이스 컴포넌트를 오른쪽 클릭하면 팝업메뉴가 나타나는데, 여기서 인터베이스익스프레스의 버전(9.09)을 볼 수 있고 또 데이터베이스 에디터를 선택할 수 있습니다. 데이터베이스 에디터를 선택하면 다음과 같은 다이얼로그가 나타날 것입니다.

데이터베이스 컴포넌트 에디터

데이터베이스의 패스가 D: 드라이브로 되어 있을 겁니다. 이걸 C: 드라이브로, 그리고 Borland 대신 Common Files로 바꾸어야 할 겁니다. 제 기본 설치대로라면, mastsql.gdb 파일은 C:\Program Files\Common Files\Borland Shared\Data\mastsql.gdb 위치에 있습니다. 여러분의 설정은 또 다를 수도 있죠.

- Test 버튼을 클릭하여 mastsql.gdb 데이터베이스로 연결이 되는지 확인합니다. 연결이 안된다면, that mastsql.gdb 파일이 지정된 경로에 존재하는지 확인하고 인터베이스가 실행중인지도 확인하십시오.

- Test 버튼을 눌렀을 때 연결이 성공하면 데이터베이스 컴포넌트 에디터를 닫습니다.

*VCL 프로젝트를 .NET으로 마이그레이션할 때마다 먼저 데이터모듈의 데이터 액세스 컴포넌트가 정확한 데이터베이스를 가리키고 있는지 확인해야 할 것입니다. 대부분의 VCL 데이터 액세스 컴포넌트는 VCL.NET 버전이 있습니다만, .NET에는 SQL 링크 지원이 없으므로 SQL 링크 기반의 프로젝트는 dbExpress나 dbGo for ADO, InterBaseExpress, 혹은 다른 VCL.NET 데이터 액세스 기술로 마이그레이션해야 합니다.

소스 코드 마이그레이션

데이터모듈과 특히 데이터 액세스 연결을 확인하고 나면 프로젝트를 처음으로 컴파일해볼 수 있습니다.

- Shift+F2 키를 눌러 모든 파일을 저장합니다.

- Ctrl+F9 키를 눌러 mastapp 프로젝트를 처음으로 컴파일합니다.

다음과 같이 17개의 워닝과 1개의 에러가 발생할 것입니다.

  [Warning] mastapp.dpr(23): W1005 Unit 'Borland.Vcl.Forms' is specific to a platform
  [Warning] MAIN.PAS(6): W1005 Unit 'Borland.Vcl.Windows' is specific to a platform
  [Warning] MAIN.PAS(6): W1005 Unit 'Borland.Vcl.Messages' is specific to a platform
  [Warning] MAIN.PAS(6): W1005 Unit 'Borland.Vcl.Graphics' is specific to a platform
  [Warning] MAIN.PAS(6): W1005 Unit 'Borland.Vcl.Controls' is specific to a platform
  [Warning] MAIN.PAS(7): W1005 Unit 'Borland.Vcl.Forms' is specific to a platform
  [Warning] MAIN.PAS(7): W1005 Unit 'Borland.Vcl.Dialogs' is specific to a platform
  [Warning] MAIN.PAS(7): W1005 Unit 'Borland.Vcl.Buttons' is specific to a platform
  [Warning] MAIN.PAS(7): W1005 Unit 'Borland.Vcl.StdCtrls' is specific to a platform
  [Warning] MAIN.PAS(7): W1005 Unit 'Borland.Vcl.Menus' is specific to a platform
  [Warning] MAIN.PAS(7): W1005 Unit 'Borland.Vcl.ExtCtrls' is specific to a platform
  [Warning] DataMod.pas(8): W1005 Unit 'Borland.Vcl.Windows' is specific to a platform
  [Warning] DataMod.pas(8): W1005 Unit 'Borland.Vcl.Messages' is specific to a platform
  [Warning] DataMod.pas(8): W1005 Unit 'Borland.Vcl.Graphics' is specific to a platform
  [Warning] DataMod.pas(8): W1005 Unit 'Borland.Vcl.Controls' is specific to a platform
  [Warning] DataMod.pas(8): W1005 Unit 'Borland.Vcl.Forms' is specific to a platform
  [Warning] DataMod.pas(8): W1005 Unit 'Borland.Vcl.Dialogs' is specific to a platform
  [Fatal Error] DataMod.pas(9): F1026 File not found: 'VarUtils.dcuil'

워닝들은 플랫폼에 의존적인 VCL.NET 유닛들을 uses 하고 있다는 사실을 알려줄 뿐이므로 무시할 수 있습니다. 이런 platform specific 워닝들을 피하려면 뜨지 않도록 설정할 수도 있습니다.

- Project | Options 메뉴를 클릭하고 Project Options로 갑니다. 다음 그림처럼 Compiler Messages 카테고리에서 "Platform Unit" 워닝의 체크를 빼면 됩니다. 이제부터는 프로젝트를 컴파일할 때마다 이 워닝들을 다시 보지 않게 됩니다.

프로젝트 옵션 - 워닝 메시지들

- Project | Build mastapp 메뉴를 선택하거나 Shift+F9 키를 눌러 빌드합니다. 앞에서 봤던 17개의 워닝은 나타나지 않겠지만 에러는 그대로 있을 것입니다.

  [Fatal Error] DataMod.pas(9): F1026 File not found: 'VarUtils.dcuil'

이 에러는 VarUtils 유닛이 VCL.NET에는 존재하지 않기 때문에 발생한 것입니다(Variants 유닛에 통합되었습니다). 따라서 우리는 VarUtils 유닛을 uses 절에서 삭제할 수 있습니다.

- DataMod.pas의 interface 섹션의 uses 절에서 VarUtils를 삭제합니다.

*여러분의 프로젝트가 Win32에서도 그대로 컴파일 가능하도록 유지하고 싶다면, uses 절에서 VarUtils 유닛을 그냥 삭제하는 대신 {$IFDEF WIN32} .... {$ENDIF} 블럭 안에 둘 수 있습니다.

- 만약 IFDEF를 쓰기로 결정했다면 uses 절을 다음과 같이 수정하십시오.

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  DB, IBQuery, IBCustomDataSet, IBTable, IBDatabase, IB, Variants
  {$IFDEF WIN32}, VarUtils {$ENDIF};

- Shift+F2 키를 눌러 프로젝트의 모든 파일들을 저장하고 다음으로 Shift+F9 키를 눌러 프로젝트를 리빌드합니다.

이제 3개의 힌트와 2개의 에러가 나올 것입니다.

[Error] EDCUST.PAS(54): E2010 Incompatible types: 'Variant' and 'Double'
[Fatal Error] BrCstOrd.pas(48): F2063 Could not compile used unit 'EDCUST.PAS'

'incompatible type' 워닝의 원인이 되는 코드는 다음과 같습니다.

procedure TEdCustForm.Edit(CustNo: Double);
begin
  MastData.Cust.Open;
  MastData.Cust.Locate('CustNo', CustNo, []);
  ShowModal;
end;

이 에러 메시지는 MastData.Cust.Locate 메소드의 CustNo 인자와 관련된 것입니다. 이 변수는 Double 타입인데, 해당 메소드에서 요구되는 타입은 Variant 타입입니다. 그 자체로는 문제가 없지만, 컴파일하기 위해서는 Variants 유닛이 uses 절에 추가되어야 합니다.

- Edcust.pas 유닛의 implementation 섹션의 uses 절에 Variants 유닛을 추가합니다.

- Shift+F2 키를 눌러 프로젝트의 모든 파일들을 저장하고 다음으로 Shift+F9 키를 눌러 프로젝트를 리빌드합니다.

이제 3개의 힌트와 1개의 에러가 남았습니다.

[Fatal Error] EDORDERS.PAS(10): F1026 File not found: 'DBLookup.dcuil'

DBLookup 유닛도 VCL.NET에 존재하지 않는 거 같군요. 안심하고 지워도 됩니다.

- Edorders.pas 유닛의 interface 섹션의 uses 절에서 DBLookup 유닛을 제거합니다.

*여러분의 프로젝트가 Win32에서도 그대로 컴파일 가능하도록 유지하고 싶다면, uses 절에서 DBLookup 유닛을 그냥 삭제하는 대신 {$IFDEF WIN32} .... {$ENDIF} 블럭 안에 둘 수 있습니다.

- 만약 IFDEF를 쓰기로 결정했다면 uses 절을 다음과 같이 수정하십시오.

uses
  SysUtils, Windows, Messages, Classes, Graphics, Controls,
  Dialogs, Forms, StdCtrls, DBGrids, DBCtrls, DB,
  Buttons, Grids, {$IFDEF WIN32} DBLookup, {$ENDIF} ExtCtrls, Mask;

- Shift+F2 키를 눌러 프로젝트의 모든 파일들을 저장하고 다음으로 Shift+F9 키를 눌러 프로젝트를 리빌드합니다.

이제 3개의 힌트와 4개의 에러가 나올 것입니다.

[Error] SrchDlg.pas(54): E2010 Incompatible types: 'Variant' and 'Double'
[Error] SrchDlg.pas(64): E2010 Incompatible types: 'Variant' and 'Double'
[Error] SrchDlg.pas(98): E2010 Incompatible types: 'Variant' and 'TCaption'
[Fatal Error] EDORDERS.PAS(76): F2063 Could not compile used unit 'SrchDlg.pas'

앞의 세가지 문제는 이전에 봤던 에러와 매우 비슷합니다. uses 절에 Variants 유닛을 추가함으로써 해결되었었죠.

- SrchDlg.pas 유닛의 implementation 섹션의 uses 절에 Variants 유닛을 추가합니다.

- Shift+F2 키를 눌러 프로젝트의 모든 파일들을 저장하고 다음으로 Shift+F9 키를 눌러 프로젝트를 리빌드합니다.

이제 3개의 힌트와 1개의 워닝, 그리고 2개의 에러가 나올 것입니다.

[Error] EDORDERS.PAS(105): E2010 Incompatible types: 'Variant' and 'Double'
[Warning] EDORDERS.PAS(229): W1050 WideChar reduced to byte char in set expressions
[Fatal Error] BrCstOrd.pas(48): F2063 Could not compile used unit 'EDORDERS.PAS'

위의 에러는 이제 금방 알아볼 것입니다. 워닝은 나중에 해결하겠습니다. 지금은 컴파일러 에러를 해결하는 데만 집중합시다.

- Edorders.pas 유닛의 implementation 섹션의 uses 절에 Variants 유닛을 추가합니다.

- Shift+F2 키를 눌러 프로젝트의 모든 파일들을 저장하고 다음으로 Shift+F9 키를 눌러 프로젝트를 리빌드합니다.

이제 3개의 힌트, 1개의 워닝, 3개의 에러가 나올 것입니다.

- BrCstOrd.pas 유닛의 implementation 섹션의 uses 절에 Variants 유닛을 추가합니다.

- Shift+F2 키를 눌러 프로젝트의 모든 파일들을 저장하고 다음으로 Shift+F9 키를 눌러 프로젝트를 리빌드합니다.

이제 3개의 힌트, 1개의 워닝, 1개의 에러가 나올 것입니다.

- Edparts.pas 유닛의 interface 섹션 uses 절에서 DBLookup을 제거하거나, 다음과 같이 DBLookup을 {$IFDEF WIN32} 블럭으로 감쌉니다.

uses
  SysUtils, Windows, Messages, Classes, Graphics, Controls,
  Forms, Dialogs, DB, StdCtrls, ExtCtrls, Mask, DBCtrls,
  {$IFDEF WIN32} DBLookup, {$ENDIF} Buttons;

- Shift+F2 키를 눌러 프로젝트의 모든 파일들을 저장하고 다음으로 Shift+F9 키를 눌러 프로젝트를 리빌드합니다.

이제 3개의 힌트, 1개의 워닝, 2개의 에러가 나올 것입니다.

- Edparts.pas 유닛의 implementation 섹션의 uses 절에 Variants 유닛을 추가합니다.

- Shift+F2 키를 눌러 프로젝트의 모든 파일들을 저장하고 다음으로 Shift+F9 키를 눌러 프로젝트를 리빌드합니다.

이제 3개의 힌트, 1개의 워닝, 2개의 에러가 나올 것입니다.

- Brparts.pas 유닛의 implementation 섹션의 uses 절에 Variants 유닛을 추가합니다.

- Shift+F2 키를 눌러 프로젝트의 모든 파일들을 저장하고 다음으로 Shift+F9 키를 눌러 프로젝트를 리빌드합니다.

이제 3개의 힌트, 1개의 워닝, 1개의 페이털 에러가 나올 것입니다.

  [Hint] DataMod.pas(244): H2443 Inline function 'ExpandFileName' has not been expanded
  because unit 'System.IO' is not specified in USES list
  [Hint] DataMod.pas(743): H2443 Inline function 'FileExists' has not been expanded because
  unit 'System.IO' is not specified in USES list
  [Hint] DataMod.pas(748): H2443 Inline function 'ExtractFileName' has not been expanded
  because unit 'System.IO' is not specified in USES list
  [Warning] EDORDERS.PAS(229): W1050 WideChar reduced to byte char in set expressions
  [Fatal Error] CustRpt.pas(6): F1026 File not found: 'Quickrpt.dcuil'

이 시점에서, 델파이 2005 VCL 디자이너가 CustRpt 유닛을 보여주려 할 때 몇몇 속성을 찾을 수 없다는 디자인타임 에러 다이얼로그도 나타날 것입니다.

QuickReport가 없다

문제는 CustRpt.pas 유닛에서 필요한 Quickrpt.dcuil 유닛을 찾을 수 없기 때문에 발생했습니다. QuickReport의 .NET 버전은 델파이 2005에 포함되어 있지 않습니다. 이 기능을 마이그레이션하기 위해 추천되는 방법들 중 한가지는 Rave Reports를 이용하는 것입니다. 혹은 QuickReports의 .NET 버전을 찾아보거나, 다른 레포팅 관련 프레임워크를 찾아볼 수도 있습니다.

Reporting is left as exercise for the reader, 하지만 우리는 레포팅 기능을 제외하고라도 일단 프로젝트를 컴파일해야 합니다.

- Project | View Source 메뉴를 클릭하여 프로젝트 소스(mastapp.dpr)를 열고, uses 절에서 QuickReports의 유닛들을 찾습니다(이들 유닛은 TQuickRep 타입입니다). 그리고 다음과 같이 주석으로 처리합니다.

uses
  Forms,
  Main in 'MAIN.PAS' {MainForm},
  Brparts in 'BRPARTS.PAS' {BrPartsForm},
  QryCust in 'QryCust.pas' {QueryCustDlg},
  Edparts in 'EDPARTS.PAS' {EdPartsForm},
  BrCstOrd in 'BrCstOrd.pas' {BrCustOrdForm},
  Edcust in 'EDCUST.PAS' {EdCustForm},
  Edorders in 'EDORDERS.PAS' {EdOrderForm},
  SrchDlg in 'SrchDlg.pas' {SearchDlg},
  Splash in 'SPLASH.PAS' {SplashForm},
  Pickdate in 'PICKDATE.PAS' {BrDateForm},
  About in 'ABOUT.PAS' {AboutBox},
  Pickrep in 'PICKREP.PAS' {PickRpt},
//CustRpt in 'CustRpt.pas' {CustomerByInvoiceReport: TQuickRep},
//OrderRpt in 'OrderRpt.pas' {OrdersByDateReport: TQuickRep},
//InvcRpt in 'InvcRpt.pas' {InvoiceByOrderNoReport: TQuickRep},
  PickInvc in 'PickInvc.pas' {PickOrderNoDlg},
  DataMod in 'DataMod.pas' {MastData: TDataModule};

소스 라인을 주석으로 처리하는 빠른 방법은 Ctrl+/ 키를 누르는 것입니다. 이 핫키는 주석되지 않은 코드를 주석으로 토글해주고 다음 라인으로 커서를 옮깁니다. 따라서 3 라인 전체를 빠르게 주석 처리할 수 있습니다.

*여러 라인을 블럭으로 선택한 후 Ctrl+/ 키를 누르면 전체 블럭이 한번에 주석 처리됩니다.

- 프로젝트 소스 파일의 가장 아래쪽으로 이동하여, QuickReports 폼을 생성하는 세개의 CreateForm 코드를 찾습니다. 블럭으로 선택한 다음 Ctrl+/ 키를 눌러 다음과 같이 주석 처리합니다.

begin
  Application.Initialize;
  SplashForm := TSplashForm.Create(Application);
  SplashForm.Show;
  SplashForm.Update;
  Application.Title := 'Marine Adventures Order Entry';
  Application.HelpFile := 'MASTAPP.HLP';
  Application.CreateForm(TMainForm, MainForm);
  Application.CreateForm(TBrPartsForm, BrPartsForm);
  Application.CreateForm(TQueryCustDlg, QueryCustDlg);
  Application.CreateForm(TEdPartsForm, EdPartsForm);
  Application.CreateForm(TBrCustOrdForm, BrCustOrdForm);
  Application.CreateForm(TEdCustForm, EdCustForm);
  Application.CreateForm(TEdOrderForm, EdOrderForm);
  Application.CreateForm(TSearchDlg, SearchDlg);
  Application.CreateForm(TBrDateForm, BrDateForm);
  Application.CreateForm(TAboutBox, AboutBox);
  Application.CreateForm(TPickRpt, PickRpt);
//  Application.CreateForm(TCustomerByInvoiceReport, CustomerByInvoiceReport);
//  Application.CreateForm(TOrdersByDateReport, OrdersByDateReport);
//  Application.CreateForm(TInvoiceByOrderNoReport, InvoiceByOrderNoReport);
  Application.CreateForm(TPickOrderNoDlg, PickOrderNoDlg);
  Application.CreateForm(TMastData, MastData);
  SplashForm.Hide;
  SplashForm.Free;
  Application.Run;
end.

이것으로 끝난 것은 아닙니다. QuickReports를 이용하는 유닛들은 이 프로젝트의 다른 곳에서도 이용되고 있기 때문입니다. 이런 코드들을 모두 찾아서 주석으로 처리해야 합니다.

- Search | Find 메뉴를 클릭하고 CustRpt를 검색합니다(이 유닛은 다른 유닛들의 uses 절에도 있으므로 제거해야 합니다).

델파이 2005 Find in Files

*검색 결과가 파일별로 그룹되어 트리뷰에 나타나는 것을 주목하십시오. 검색 결과로 Main.pas 유닛이 나타납니다.

- Main.pas 파일을 열고 implementation 섹션의 uses 절을 찾아가십시오. CustRpt 유닛이 포함되어 있을 것입니다.

*에러 인사이트(Error Insight)가 자동으로 이 유닛과 OrderRpt, InvcRpt 유닛을 잘못된 것으로 표시해주는 것을 주목하십시오. (컴파일러가 해당 유닛 이름들을 해결하지 못했다는 뜻입니다)

Click to see full-sized image

Cannot resolve unit names- plus other uncompilable code

- Ctrl+/ 키를 눌러 CustRpt, OrderRpt, InvcRpt 유닛을 주석 처리합니다.

- Shift+F2 키를 눌러 프로젝트의 모든 파일들을 저장하고 다음으로 Shift+F9 키를 눌러 프로젝트를 리빌드합니다.

다음 에러는 PrintCustomerReport 메소드에서 나타납니다.

- PrintCustomerReport 메소드 안의 코드를 선택하고 주석 처리합니다. (더 많이 주석으로 처리하거나 더 적게 하거나 관계없습니다)

procedure TMainForm.PrintCustomerReport(Preview: Boolean);
begin

  with MastData.CustByLastInvQuery do
  begin
    Open;
//    if Preview then
//       CustomerByInvoiceReport.Preview
//    else
//       CustomerByInvoiceReport.Print;
    Close;
  end;
end;

다음 문제는 PrintOrderReport 메소드에서 나타납니다. 역시 주석으로 처리합니다.

- PrintOrderReport 메소드 안의 코드들을 선택하고 Ctrl+/ 키를 눌러 주석으로 처리합니다.

Click to see full-sized image

PrintOrderReport in comments

이제 PrintInvoiceReport 한 군데만 남았습니다.

- PrintInvoiceReport 메소드 안의 코드들을 선택하고 주석으로 처리합니다. (더 많이 주석으로 처리하거나 더 적게 하거나 관계없습니다)

procedure TMainForm.PrintInvoiceReport(Preview: Boolean);
begin
  if PickOrderNoDlg.ShowModal = mrOk then
//     if Preview then
//        InvoiceByOrderNoReport.Preview
//     else
//        InvoiceByOrderNoReport.Print;
end;

- Shift+F2 키를 눌러 프로젝트의 모든 파일들을 저장하고 다음으로 Shift+F9 키를 눌러 프로젝트를 리빌드합니다.

이제, 프로젝트의 컴파일과 링크가 아무런 문제 없이 완료됩니다.

데이터베이스의 경로

약간 주의를 해야 할 문제가 하나 더 있습니다. 지금 애플리케이션을 실행시키면, 제대로 동작할 수도 있지만 데이터베이스를 찾을 수 없다는 메시지를 받을 수도 있습니다.

이 마지막 문제는 애플리케이션의 코드 자체 때문에 발생하는 것입니다. 데이터모듈 안에 DataDirectory라는 함수가 있는데, 다음과 같이 정의되어 있습니다.

function TMastData.DataDirectory: string;
begin
  { Assume data is in ..\..\..\..\..\Common Files\Borland Shared\DATA\data relative to where we are }
  Result := ExtractFilePath(ParamStr(0));
  //Result := ExpandFileName(Result + '..\..\DATA\');
  Result := ExpandFileName(Result + '..\..\..\..\..\Common Files\Borland Shared\DATA\');
end;

주석의 내용대로, 데이터가 애플리케이션의 경로로부터 상대 경로로 ..\..\..\..\..\Common Files\Borland Shared\DATA\data 디렉토리에 있다고 가정하는 것입니다. 이것은 Demo 디렉토리 구조에서는 동작할 수 있겠지만, 애플리케이션을 배포했을 때 이용할 위치와는 관계가 없습니다.

사실, 이 프로젝트를 마이그레이션하기 시작할 때 데이터베이스가 디자인타임에 연결된다는 것을 확인했습니다. 따라서 Database.DatabaseName은 이미 정확한 위치를 가리키고 있습니다.

DataDirectory 함수는 단 한 군데에서만 이용되는데, 그것은 MastDataCreate 함수입니다. 우리는 거기서 하는 작업을 되돌리면 됩니다.

- datamod.pas 유닛을 열고 MastDataCreate 메소드를 찾습니다. DataFile 변수에 Database.DatabaseName의 값을 대입하여 DataDirectory 값을 덮어쓰도록 합니다.

procedure TMastData.MastDataCreate(Sender: TObject);
var
  DataFile: string;
begin
  DataFile := DataDirectory + 'MASTSQL.GDB';
  DataFile := Database.DatabaseName; // already working at design-time!
  if not FileExists(DataFile) then
    if MessageDlg('Could not locate MASTSQL.GDB.  Would you like to locate the file?',
    mtError, [mbYes, mbNo], 0) = mrYes then
      if OpenDialog.Execute then
      begin
        if UpperCase(ExtractFileName(OpenDialog.FileName)) = 'MASTSQL.GDB' then
          DataFile := OpenDialog.FileName
        else
          raise Exception.Create('Invalid File: ' + OpenDialog.FileName);
      end
      else
        raise Exception.Create('Cannot locate Interbase data file: MASTSQL.GDB');
  Database.DatabaseName := DataFile;
  Database.Open;
  Transaction.StartTransaction;
end;

*DataDirectory 호출을 없애버릴 수도 있습니다만, 어쨌든 DataFile에 새 값을 대입해야 합니다.

- Shift+F2 키를 눌러 프로젝트의 모든 파일들을 저장하고 다음으로 Shift+F9 키를 눌러 프로젝트를 리빌드합니다.

프로젝트는 다시 컴파일되고 실행되어 다음과 같이 Marine Adventures Order Entry 애플리케이션을 보여줄 것입니다.

Marine Adventures Order Entry 메인 애플리케이션

- Order 폼을 보이기 위해 New Order 버튼을 클릭합니다.

Order 폼

- Order 폼을 닫고 Orders by Customer 폼을 보이기 위해 Browse 버튼을 클릭합니다.

Orders by Customer 폼

- Orders by Customer 폼을 닫고 Browse Parts 폼을 보이기 위해 Parts 버튼을 클릭합니다.

Browse Parts 폼

- Browse Parts 폼을 닫고 Report Selection 폼을 보이기 위해 Reports 버튼을 클릭합니다.

Report Selection 폼

*세개의 레포트 모두 사용할 수 없으며 버튼들도 동작하지 않습니다. 이것은 우리가 모든 QuickReports를 이용하는 코드를 주석으로 처리했기 때문입니다. 원한다면 여러분이 직접 레포트를 추가할 수 있을 것입니다.

결론

이 강좌에서는, 기존의 Win32 VCL 애플리케이션을 델파이 2005와 VCL.NET을 이용하여 .NET으로 마이그레이션하는 방법을 알아보았습니다. 우리는 threading 예제부터 시작했는데, 먼저 unsafe한 .NET 애플리케이션으로 마이그레이션하고 나서 다음으로 100% safe한 네이티브 .NET 애플리케이션으로 바꾸어보았습니다.

다음으로 데이터베이스를 이용하는 좀 더 복잡한 예제를 연습해봤습니다.

VCL 애플리케이션을 Win32에서 .NET으로 마이그레이션하는 노력의 양은 애플리케이션을 처음부터 다시 만드는 노력에 비해서는 훨씬 적습니다. 델파이 2005는 .NET으로의 마이그레이션에 놀라운 지원을 하고 있으며, 그로 인해 기존의 Win32 애플리케이션에 투자했던 노력을 그대로 .NET으로 가져갈 수 있게 해줍니다.

박지훈.임프 [cbuilder]   2007-01-13 08:50 X
같은 번역 아티클을 코드기어 개발자 사이트에도 올렸습니다.

+ -

관련 글 리스트
113 델파이 VCL 애플리케이션의 VCL.NET 마이그레이션 박지훈.임프 9168 2007/01/13
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.