최근에 문의받은 내용인데... 스캐너에서 스캔받은 이미지를 델파이 프로그램에서 직접 받으려면 어떻게 할까요, 하는 내용이었습니다. 검색해보니 스캐너 연동을 위한 금방 쓸만한 무료 서드파티 컴포넌트가 있었는데요. Delphi Twain이라는 컴포넌트입니다. (여기서 TWAIN이란 스캐너를 연동하기 위한 표준 인터페이스 및 그 드라이버를 말합니다)

사용자 삽입 이미지

실제로 테스트해보니, 간단한 하나의 컴포넌트만으로 현재 PC에 연결된 스캐너를 동작시키고 그 이미지를 TPicture 객체로 받아와 폼 위의 TImage 컴포넌트에 표시할 수 있었습니다. 고급 설정 기능들도 있는데, 그것까지는 다 테스트해보지 못했구요.

다만, 이 컴포넌트가 2004년에 마지막으로 업데이트된 관계로, 델파이 2010이나 2009등에서는 제대로 컴파일이 되지 않습니다. 그래서, 델파이 2010에서도 컴파일 및 설치가 되도록 코드를 조금 수정했습니다. 아울러 원래 소스는 C++빌더에서 지원하지 않는 델파이 문법을 일부 사용하여 C++빌더에서 컴파일이 안되었는데, 그 부분도 수정했으므로 C++빌더에서도 설치가 가능합니다.

아래 첨부 파일을 다운로드하시면 됩니다.

2010/02/08 22:23 2010/02/08 22:23

trackback :: http://blog.devgear.co.kr/imp/trackback/136

지난 밤 사이에 Delphi/C++Builder 2009에 대한 핫픽스 3가 올라왔는데...
http://edn.embarcadero.com/article/40331

이건 사실 제가 이미 올렸던 인트라웹 관련 글 두개의 내용과 반복된 내용입니다.
핫픽스 자체는 아래 주소에서 다운로드 받을 수 있습니다.
http://cc.embarcadero.com/item/27563

위 핫픽스를 다운로드 해보시면 아시겠지만, 인트라웹의 한글 문제에 대해 처음 썼던 글(아래 주소)에서 첨부했던 UTF8ContentParser.pas 파일 하나만 달랑 들어있습니다. 이 파일 자체가 핫픽스인 거죠.
http://blog.devgear.co.kr/imp/entry/VCL-for-the-Web에서-한글-깨짐-문제

이 UTF8ContentParser 유닛은 2010 버전에는 dcu, hpp, pas 모두 기본으로 들어있기 때문에 2010에는 필요가 없는 핫픽스이구요. 어쨌든, 이 UTF8ContentParser를 적용하기 위해서는 인트라웹의 최신 업데이트를 설치해야 합니다. 아래 링크의 글을 참고하세요.

http://blog.devgear.co.kr/imp/entry/VCL-for-the-Web-업데이트-한글-문제-해결
2010/01/19 10:38 2010/01/19 10:38

trackback :: http://blog.devgear.co.kr/imp/trackback/130

델파이의 최근 버전에 추가되었지만 개발자들이 잘 모르고 있는 기능들이 꽤 많은데요. 숙련된 델파이 개발자들까지도 델파이 7 이하까지의 문법에만 익숙한 경향이 있습니다. 하지만 구버전 문법으로 구버전처럼 사용한다면 최신 버전을 사용하는 장점이 반감되지 않겠습니까. 그래서, 델파이 개발자들이 잘 모르고 있는 아주 유용한 기능들을 시간이 되는 대로 하나씩 소개해볼까 합니다.

이번에 소개하는 클래스 헬퍼는 델파이 2006에서 추가된 언어 기능으로, 기존의 클래스를 수정하지도 상속하지도 않고 클래스의 기능을 확장할 수 있게 해줍니다. 클래스를 많이 다루는 경력 개발자분들은 이 말만 듣고도 우와~ 할 것 같습니다. 이런 필요가 있는 경우가 꽤 흔하거든요.

클래스 헬퍼 자체도 하나의 클래스입니다. 클래스 헬퍼 클래스(말이 좀 헷갈리네요)에서 선언한 멤버들은 마치 원래의 클래스의 멤버인 것처럼 액세스할 수 있게 됩니다.

실제로도 아주 유용한 아래의 샘플 코드를 살펴봅시다. (delphi.about.com에서 소개된 코드입니다)

interface

uses Classes;

type
  TStringsHelper = class helper for TStrings
  public
    function Add(const V: Variant): Integer; overload;
    function Add(const Args: array of Variant): Integer; overload;
  end;

implementation

uses Variants;

function TStringsHelper.Add(const Args: array of variant): Integer;
var
  tmp: string;
  cnt: Integer;
begin
  tmp := '';
  for cnt := Low(Args) to High(Args) do
    tmp := tmp + VarToStr(Args[cnt]) ;
  result := Add(tmp) ;
end;

function TStringsHelper.Add(const V: Variant): Integer;
begin
  Result := Add([V]) ;
end;

end.

이 클래스 헬퍼를 이용하면, 이제 TStrings (그리고 TStringList 등 상속받은 모든 클래스들)에서 TStrings에 원래 존재하는 기본 Add() 함수 외에 오버로드된 Variant 및 Variant 배열 버전의 Add() 함수들을 호출할 수 있게 됩니다. Variant가 되니까 당연히 정수나 실수 등 대부분의 델파이 기본 타입들을 직접 TStrings 객체의 문자열 아이템으로 추가할 수 있게 됩니다.

with ListBox1.Items do
begin
  Add('delphi.about.com') ;
  Add(2008) ;
  Add(true) ;
  Add(['Only ', 1, true, ' line']) ;
end;

이와 같이, 클래스 헬퍼를 이용하면 기존의 클래스에 기능을 추가할 수 있습니다. 하지만 자신이 직접 만드는 클래스에 클래스 헬퍼를 사용할 필요는 거의 없을 거고, 주로 위의 TStrings처럼 개발자가 수정하기 곤란한 프레임워크/라이브러리의 클래스들에 기능을 추가해서 사용할 때 많이 활용할 수 있습니다.

클래스 헬퍼로 기존 클래스의 private이나 protected 멤버를 액세스할 수는 없고 오직 public/published 멤버만 액세스할 수 있습니다. 따라서 클래스 헬퍼를 쓴다고 해서 기존에 할 수 없었던 작업을 할 수 있게 되는 것은 아닙니다. 하지만 위의 예제에서 보듯이, 단순 코딩 작업을 많이 줄여주고 코드를 더 간략하게 만들 수 있게 됩니다.

2010/01/13 10:39 2010/01/13 10:39

trackback :: http://blog.devgear.co.kr/imp/trackback/128

지난 11월에, 델파이 및 C++빌더의 2010, 2009 버전의 VCL for the Web에서 한글이 깨지는 문제의 긴급 해결책에 대해 안내해드렸었는데요.
http://blog.devgear.co.kr/imp/entry/VCL-for-the-Web에서-한글-깨짐-문제

바로 며칠 전에 VCL for the Web의 벤더인 Atozed에서 이 문제를 해결한 IntraWeb 10.0.21 버전을 내놓았습니다. 아래의 링크에서 다운로드를 받으실 수 있구요.
http://www.atozed.com/Intraweb/Download/Download.EN.aspx

사용자 삽입 이미지

설치 프로그램을 다운받아 설치하려고 하면 라이선스 키를 입력하라고 나오는데요. 아래의 링크를 참고해서, 메일로 요청해야 합니다. (키를 안넣고도 설치를 할 수 있지만, 그러면 평가판 모드로 설치가 됩니다)
http://www.atozed.com/Intraweb/Download/FreeKeyRequest.EN.aspx

요청하는 데에 특별한 조건이 있는 것은 아니고, 사용중인 델파이/C++빌더의 버전, 회사 이름, 개발자 이름 정도만 써서 키를 요청하면 됩니다. 예를 들면 저는 아래와 같이 무성의하게 메일을 보냈습니다.

제목: IntraWeb 10.0.21 Free Key Request
내용:
Hello,

Would you please send me IntraWeb 10.0.21 key?

Version : RAD Studio 2010 Architect
Developer Name: 개발자이름
Company Name: 회사이름


한가지 주의할 점은, 이렇게 요청해서 받은 키는 모든 델파이/C++빌더 버전에 대한 키가 아니라 요청한 한가지 버전만 적용되는 키라는것입니다. 설치 프로그램에서는 델파이/C++빌더의 모든 버전이 선택되어 있는데, 요청했던 버전 하나만 선택해야 키를 입력했을 때 다음으로 넘어갈 수 있습니다.

그냥 이 업데이트를 설치한 상태로는 그대로 한글이 깨지구요. 지난번에 알려드렸던 대로 UTF8ContentParser 유닛을 uses 해줘야합니다. 다만 이번에는 UTF8ContentParser.pas 유닛이 기본으로 포함되어 있어서 별도로 다운받아 복사해줘야 하는 불편은 덜었네요.

이 업데이트를 설치하고 나면 파일 업로드에 필요한 TIWDBFile 컴포넌트를 사용할 수 없습니다. 아마도 벤더인 Atozed에서 아직 파악을 못하고 있는 듯 한데, 레포트하도록 하겠습니다.

2010/01/12 08:11 2010/01/12 08:11

trackback :: http://blog.devgear.co.kr/imp/trackback/126

일반적으로, DLL에 포함된 루틴을 호출하는 방법은 정적 로딩(Static Loading)과 동적 로딩(Dynamic Loading)이 있습니다.

정적 로딩이란 DLL 내의 루틴을 호출하기 위해 해당 루틴의 임포트 선언을 하고 사용하는 방법이죠.

procedure ProcInDll; external 'DLL입니다용.dll';

이렇게 임포트 선언을 하게 되면, 해당 DLL은 현재 프로그램이 실행되는 즉시 프로세스로 로딩됩니다. 이 방법의 좋은 점은, 코드가 아주 간단하고, 이렇게 dll의 루틴들을 모두 모아 라이브러리 목적의 유닛으로 만들어두면, 해당 유닛을 uses하기만 하면 마치 메인 프로그램 소스 내의 함수인 것처럼 편하게 호출할 수 있다는 거죠. 실제로 VCL의 Windows.pas나 ShellAPI.pas처럼 Win32를 그대로 번역한 유닛들이 이런 파일이어서, 우리는 델파이에서 Win32 API를 껌씹듯이 쉽게 호출해댈 수 있습니다.

하지만 이 정적 로딩 방법에는 중요한 단점이 하나 있는데... 프로그램이 시작될 때 해당 DLL을 로드하기 때문에, 만약 해당 DLL이 없거나 DLL 안에 해당 루틴이 없을 경우 프로그램이 아예 시작되지를 못한다는 것입니다. (이런 경우를 많이 접해보셨을 겁니다) 또, 프로그램이 시작될 때 DLL을 몽땅 다 로드해버리기 때문에 당장 쓰지도 않을(경우에 따라서는 아예 호출하지도 않을 수도 있는) 루틴들을 위해 무시할 수는 없을 정도의 메모리가 소요된다는 거죠.

DLL의 동적 로딩이란, 프로그램이 시작되는 동안이 아닌, 프로그램의 코드 내에서 LoadLibrary/FreeLibrary와 GetProcAddress 등의 함수를 이용해서 코드로 일일이 DLL을 로드하고, 그 DLL에서 해당 함수의 주소를 찾고, 그 주소를 함수 포인터로 해서 해당 함수를 호출하는 절차입니다.

TProcInDll = procedure;

var
  Handle: THandle;
  AProcInDll: TProcInDll;
begin
  Handle := LoadLibrary('DLL입니다용.dll');
  if Handle<>0 then
  begin
    @AProcInDll := GetProcAddress(Handle, 'ProcInDll');
    if @AProcInDll<>nil then
      AProcInDll;
  end;
  FreeLibrary(Handle);
end;


정적 로딩 방법에 비해 동적 로딩 방법의 단점은, 위 코드에서 바로 눈에 보이시죠. 코드가 복잡하고 까다롭다는 겁니다. 대신, 해당 DLL이 없거나 DLL 안의 루틴이 없더라도 당장 프로그램이 아예 뜨지도 않는 경우는 발생하지 않는다는 거죠. 물론 기대했던 DLL이 없다면 난감하겠지만, 위의 코드에서처럼 에러 체크를 통해 적어도 뭔가 대책을 세울 수 있는 가능성이 생깁니다. 또, 필요한 경우에만 DLL을 로드하기 때문에 메모리도 적게 먹습니다.

정적 로딩과 동적 로딩 사이에 장단점이 너무나 명확하죠. 그러면... 동적 로딩과 정적 로딩 사이에서 장점만 취할 수 있는 방법은 없을까요? 정적 로딩에서처럼 간단하게 임포트 선언만 하면서도, 프로그램 실행시에 무조건 바로 DLL을 로드하지는 않고 실제로 필요할 때 DLL을 불러들이면 되겠죠.

별로 알려지지 않았지만, 델파이 2010에서 바로 이 기능이 추가되었습니다. 지연 로딩(Delayed Loading)이라는 것으로, delayed라는 지시어가 추가되어 가능해졌습니다. 위의 정적 로딩에서 임포트 선언의 뒤에 delayed만 추가하면 된다는 거죠.

procedure ProcInDll; external 'DLL입니다용.dll' delayed;

정적 로딩 방식과 똑같은 임포트 선언에 delayed 지시어가 추가되었을 뿐입니다. 이렇게 delayed를 추가해주면, 프로그램 시작시에 바로 로딩되지 않고 실제로 해당 프로시저/함수가 호출될 때 비로소 DLL을 로드하고 루틴을 임포트합니다. 그래서 지연 로딩, delayed인 거죠.

당장 델파이 2010의 Windows.pas나 ShellAPI.pas 등등에는 2009 버전까지는 보이지 않았던 수없이 많은 함수들이 이 delayed 지시어와 함께 임포트 선언으로 추가되어 있는데요. 이 함수들은 윈도우 7, 윈도우 비스타, 윈도우 XP 등 특정 버전 이상에서 추가된 함수들로서, 그보다 낮은 윈도우 버전에서는 존재하지 않았던 함수들입니다. 그래서 API 지원이 훨씬 풍부해졌죠.

그러면, 해당 DLL이나 함수가 존재하지 않을 경우, 어떻게 대응을 해야 할까요? 해당 DLL이나 함수가 존재하지 않아 불러들일 수 없는 경우 EExternalException 예외가 발생합니다. 따라서, 동적 로딩에서 리턴 값을 체크해서 함수의 존재 여부에 따라 처리하는 것과 마찬가지로 try except 블럭으로 EExternalException 예외를 처리하면 깔끔하게 되겠죠.

그렇다고 동적 로딩을 사용하는 모든 경우를 지연 로딩으로 커버할 수는 물론 없습니다. 지연 로딩에서 프로그램 시작 이후 DLL 함수가 호출될 때까지는 DLL이 메모리에 로드되지 않지만, 일단 호출된 후에는 해당 DLL이 언로드되지 않고 계속 메모리에 머무르게 됩니다. 극단적으로 효율적인 메모리 운영이 필요하다면 언제든 DLL을 언로드할 수 있는 동적 로딩을 따라갈 수는 없죠.

또, 동적 로딩의 경우에는 DLL 이름과 함수 이름을 문자열로 취급하므로 메인 프로그램이 사전에 알지 못하는 DLL이나 함수도 호출이 가능하지만 정적 로딩과 지연 로딩에서는 컴파일 시점에 고정되는 이름만 지원할 수 있으므로, 업무 개발 프로젝트에서처럼 사전에 프로그램에서 알 수 없는 많은 DLL들을 쓰는 경우를 지원할 수 없게 됩니다.

성능 면에서는 어떨까요. delayed를 불필요하게 너무 남발하면 정적 로딩에 비해 프로그램의 성능을 떨어뜨릴 수도 있습니다. 반면 한번 호출되어 로딩된 DLL은 메모리에 계속 상주하게 되므로 이런 면에서는 매번 LoadLibrary, GetProcAddress를 호출해야 하는 동적 로딩보다는 속도가 빠르게 되죠. 결국 개발자가 정적 로딩, 지연 로딩, 동적 로딩을 적절히 잘 배합해서 사용하는 것이 좋습니다. 실제 VCL 코드에서도 이 세가지가 잘 배합되어 사용되고 있죠.

지연 로딩에 대한 좀 더 자세한 내용은, 엠바카데로의 앨런 바우어의 블로그에서 보실 수 있습니다.
http://blogs.embarcadero.com/abauer/2009/08/25/38894
http://blogs.embarcadero.com/abauer/2009/08/29/38896
http://blogs.embarcadero.com/chrishesik/2009/11/02/35056

아래 JEDI 블로그에서는 조금 더 테크니컬한 내용들을 보실 수 있습니다.
http://blog.delphi-jedi.net/2009/08/29/version-checking-for-delphi/

2010/01/10 02:17 2010/01/10 02:17

trackback :: http://blog.devgear.co.kr/imp/trackback/127

제 업무 특성상 하루에도 아주 많은 도움 요청을 받습니다. 가급적 답변에 하루를 넘기지 않으려고 노력하지만, 요즘은 일주일에 두차례씩 외부 개발 컨설팅을 나가고 있어서 보통은 하루나 이틀 정도가 흐른 다음에야 답변을 하고 있습니다. 양해를 부탁드립니다.

오늘 질문받은 건 중에, 현재 데이터베이스 연결에 BDE를 사용중인 프로젝트가 있는데 BDE를 마이그레이션하는 데 대한 조언을 요청한 건이 있어서, 이에 대한 내용을 써볼까 합니다.

왜 BDE를 제거해야 하는가

먼저, 왜 BDE를 들어내야 하는지에 대해 써보죠. 아시다시피 BDE는 2002년 델파이 7이 출시되면서 RDBMS에 대한 연결 지원이 중단되었습니다. 쉽게 말해서 오라클, MS SQL, 사이베이스, DB2 등의 데이터베이스로 연결할 수 없게 되었다는 것입니다. BDE의 SQLLinks가 바로 이런 RDBMS로의 연결을 담당하는 부분인데, 델파이 7 버전부터는 이 SQLLinks가 제거되었습니다.

이에 대해서는 2002년에 볼랜드포럼의 주요 뉴스로 올린 적이 있으니 자세한 내용은 링크를 참고하실 수 있습니다.
http://www.borlandforum.com/impboard/impboard.dll?action=read&db=news&no=93

물론 굳이 사용하려면 편법은 있습니다. 델파이 6까지의 BDE에는 여전히 SQLLinks가 포함되어 있으므로, 구버전 라이선스가 있다면 구버전을 먼저 설치하고 그 이후에 신버전을 설치하면 구버전의 SQLLinks를 그대로 사용하여 BDE로 RDBMS를 그대로 연결할 수 있습니다.

구버전 라이선스가 없을 경우에 BDE의 SQLLinks를 따로 복사하여 쓰는 것이 기술적으로는 가능하지만 라이선스 위반이 됩니다. 이런 경우에는 반드시 제게 연락하여 사전 양해를 받아야 하며 그렇지 않은 경우 불법이 됩니다.

그러면, 이런 방식으로 BDE를 계속 사용할 수 있는 것일까요? 그래도 여전히 문제들이 남습니다.

1. 데이터베이스 버전 문제
BDE는 1999년에 마지막으로 버전업이 되었고, 2001년 델파이 6 버전에서 마지막으로 지원되었던 만큼, 당연히 각 데이터베이스들의 지원 버전도 1999년 당시로 그대로 머물러 있습니다. 오라클의 경우를 보자면 오라클 8 버전까지만 지원하고, SQL 서버도 2000 버전까지만 지원합니다. 당연히 사이베이스나 DB2의 경우도 당시 버전까지만 지원하죠.

새로운 데이터베이스 버전에는 새로운 데이터 타입이 많이 추가됩니다. 오라클에서도 MS SQL에서도 각 버전마다 중요한 새로운 타입들이 많이 추가되어 있습니다. 만약 오라클 데이터베이스에 오라클 9 이후로 추가된 필드 타입이 있다면, BDE에는 그 타입에 대응하는 내부 처리가 되어 있지 않으므로 BDE에서 처리할 수 없게 됩니다. (아마 친숙한 Access Violation이 뜨게 될 겁니다)
그러면, 이런 새로운 타입을 가진 필드들을 아예 사용하지 않으면 되지 않겠느냐, 물론 그렇습니다만, 그렇게 새로운 필드 타입들을 피해간다면 새로운 버전의 데이터베이스를 사용하는 효과도 반감될 것입니다. 또 델파이나 C++빌더로 개발된 이외의 웹 같은 다른 시스템들도 있어서 그쪽에서도 데이터베이스를 다루어야 하는 경우, 그쪽 시스템 담당자들은 왜 구닥다리 버전의 델파이나 C++빌더 시스템 때문에 우리 시스템이 피해를 봐야 하느냐고 불평하거나 반발할 것입니다.

2. 윈도우 버전 문제
BDE는 그 마지막 버전 조차도 윈도우 XP 이상의 버전에 대해서는 아무런 동작 보장을 하지 않습니다. 볼랜드/엠바카데로에서 BDE의 마지막 버전을 내놓은 것이 2001년이므로 당연히 윈도우 비스타와 윈도우 7, 윈도우 2003 서버 등에 대해서는 테스트 자체가 안되었습니다. 따라서 윈도우 비스타와 윈도우 7에 대해서는 아직 알려지지 않은 문제가 발생할 수도 있습니다.

예를 들면 BDE에서는 비스타 이상의 보안 구조를 전혀 고려하지 않고 개발되어 있는데, 그런 이유로 BDE를 사용하기 위해 프로그램을 구버전 델파이로 개발한 개발자가 사용자에게 UAC를 끄라고 조언하는 경우가 종종 있습니다. 이건 아주 위험한 시도인데요, 심각한 문제로 비화될 수 있습니다. 개발자가 사용자에게 UAC를 끄라고 조언한 경우, 그로 인해 비전문가인 사용자가 바이러스나 해킹에 노출되어 피해를 입었다면, 개발자를 대상으로 법적으로 고소하는 것이 충분히 가능합니다. 이게 한두 명의 개인 사용자가 아니라 수십, 수백, 수천명의 기업 사용자가 사용하는 업무 시스템이라면 어마어마한 손해배상을 해야 할 수도 있겠지요.

3. 64비트 문제
특히 BDE는 64비트에서는 전혀 사용이 불가능합니다. BDE는 최초 버전이 16비트로 개발되었고, 32비트로 포팅된 후에도 마지막 버전까지도 16비트 코드가 상당히 남아있습니다. 16비트 코드는 64비트 OS에서 전혀 운영이 안됩니다. 따라서 윈도우 7 64비트 버전에서는 운영이 전혀 불가능합니다. 이런 경우라면 BDE를 무조건 다른 기술로 마이그레이션해야 합니다.

개발자 여러분이 BDE를 사용하여 개발해서 내놓은 소프트웨어를 사용자가 64비트 윈도우에서 사용하려 한다면 당연히 제대로 동작하지 않습니다. 패키지/솔루션 소프트웨어이든 혹은 SI 성격의 업무개발 시스템이든 그 사용자는 강하게 반발할 것입니다. 현재 버전의 델파이는 32비트 개발툴이기는 하지만 개발된 소프트웨어는 64비트 윈도우에서 아무 문제 없이 실행되는데, BDE를 사용하게 되면 문제가 생기게 되는 거죠.

그럼 대안은?

볼랜드에서도 그랬고, 지금 엠바카데로에서도 BDE의 공식적인 대안으로 dbExpress를 강력하게 추천하고 있습니다. 그리고, 그 외에 또다른 범용 데이터베이스 연결 방법으로 ADO가 있죠.

아무래도 ADO를 조금이라도 써본 분이 적지 않을 것이기 때문에, BDE를 들어내려면 ADO가 먼저 대안으로 떠오르는 것이 당연할 것입니다. 그런데 ADO나 dbExpress나 BDE로부터 마이그레이션하는 데 드는 노력은 별 차이가 없습니다. 그리고 지원하는 데이터베이스 면에서는 둘다 약간 차이는 있지만 메이저 데이터베이스는 두루 다 지원한다는 면에서는 별 차이가 없습니다.

그럼, 아무래도 더 친숙한 ADO를 선택해도 되지 않을까요? 하지만 여기에는 몇가지 고려해야 할 점들이 있습니다.

1. 멀티티어로의 전환 문제
최근 버전인 델파이 2009와 델파이 2010에서, 델파이와 C++빌더의 멀티티어 기술인 DataSnap이 전면 재개발되면서, 이전의 COM 의존의 무겁고 기능성이 부족하던 방식에서 가볍고 강력한 멀티티어로 탈바꿈되었습니다. 당장 저 자신부터, 이전에는 MIDAS/DataSnap이 너무 무겁고 기능도 떨어져서 대안으로 서드파티 멀티티어 기술을 사용했었지만, 이제는 새로운 DataSnap 2010을 사용하고 있는데, 아주 만족스럽습니다.

그런데 이 새로운 DataSnap 2010이 강력하기만 할 뿐 아니라, dbExpress를 너무나 멋지게 활용해서, 기존에 dbExpress를 사용하던 프로젝트라면 DataSnap 2010 기반의 멀티티어 방식으로의 전환이 아주 쉬워졌습니다. 어디까지가 dbExpress이고 어디부터가 DataSnap 2010인지 잘 구별조차 안될 정도로 빈틈없이 잘 통합되었답니다.

2. ADO 자체에 대한 의존성의 문제
ADO를 사용하게 되면 당연히 MS 기술에 대한 의존성이 생깁니다. ADO 자체적으로는 SQL 서버나 액세스 외에 다른 데이터베이스도 지원을 하기는 합니다만, 아무래도 ADO로 오라클이나 DB2 등 다른 DB로 연결하면 특정 경향을 타거나 오작동할 우려가 있습니다. ADO 자체가 MS의 DB만을 고려하여 최적화된 엔진이기 때문입니다.

예를 들면, 지난 6월에 MS는 오라클에 대한 ADO.NET 드라이버 지원을 아예 끊겠다고 일방적으로 발표한 바 있습니다.
http://blogs.msdn.com/adonet/archive/2009/06/15/system-data-oracleclient-update.aspx

3. 윈도우에 대한 의존성의 문제
당연하지만 ADO는 플랫폼 의존성이 있습니다. (물론 BDE도 그랬습니다) 윈도우 이외의 OS는 전혀 꿈도 꿀 수 없게 됩니다. 반면 dbExpress는 플랫폼 독립적으로 만들어졌습니다. 지금은 단종되었지만 리눅스용 델파이인 카일릭스가 dbExpress로 델파이와 거의 완벽하게 호환되었었습니다. 물론 카일릭스는 지금 단종되었지만...
 
아시다시피 내년이면 델파이가 크로스플랫폼으로 갑니다. 리눅스 버전이 다시 나오고, MacOSX, 아이폰까지 지원합니다. 그 이후로 줄줄이 다른 OS 버전들이 계속 개발될 것입니다.
http://blog.devgear.co.kr/imp/entry/MacOSX와-Linux를-위한-Delphi와-CBuilder

당연하게도, dbExpress로 마이그레이션 하면 지금까지 개발한 소스들을 이런 플랫폼으로 쉽게 옮길 수 있지만, ADO로 작업하면 다시 또 dbExpress로 마이그레이션해야 합니다. 또, 당장 델파이의 형제 툴로서 닷넷용 개발툴인 델파이 프리즘에서도 dbExpress를 이용하고 있습니다.
 
개발자 여러분이 일하고 있는 업계에 따라 당장 리눅스와 MacOSX, 아이폰에 대해 큰 수요가 없을 거라고 생각하실 수도 있지만, 최근 3~4년 사이에 리눅스도 약진했고 Mac의 점유율은 더욱 크게 급등했습니다. 아직 우리나라에서는 크게 느끼기 힘든 수준이지만, 글로벌 시장에서는 MS의 윈도우 점유율이 상당히 크게 떨어지고 있습니다. 이미 일본 등 해외쪽으로 소프트웨어를 수출하는 업체들에서는 윈도우 버전밖에 없다는 이유로 거절당하는 사례도 종종 나오고 있습니다.
 
이런 여러가지 면들을 고려하면...
굳이 dbExpresss 대신 ADO를 사용해서 크로스플랫폼으로 쉽게 갈 수 있는 기회를 스스로 차단할 필요가 있을까요...?

2009/12/18 14:42 2009/12/18 14:42

trackback :: http://blog.devgear.co.kr/imp/trackback/118

TEdit나 TMemo 등의 컴포넌트에서 현재 한글이 조합중인지 확인하려고 하니 마땅한 함수가 없더군요. 그래서 Win32 SDK의 IME 관련 함수들을 뒤져서 이 목적으로 적당히 쓸만한 함수를 하나 만들어봤습니다. (윈도우 IME의 버그를 추적하면서 이것저것 테스트해보느라 만들었습니다)

아래 IsInComposition 함수를 호출하면서 인자로 해당 에디트나 메모의 핸들을 넘겨주면 됩니다. 조합중일 경우 true, 조합중이 아닌 경우 false를 리턴합니다.

아래 함수의 핵심은 IME 관련 Win32 함수인 Imm32GetCompositionString 함수인데, 이 함수는 원래는 조합중인 글자를 알아내는 함수이구요. 이 함수의 리턴 값이 조합중인 글자의 길이입니다. 따라서 조합중인 글자가 없을 경우 당연히 0이 리턴되겠죠.

uses imm;

function IsInComposition(hWnd: HWND): boolean;
var
  H: HIMC;
  buff: array[0..1] of char;
  len: integer;
begin
  result := false;
  H := Imm32GetContext(hWnd);
  if H <> 0 then
  begin
    len := Imm32GetCompositionString(H, GCS_COMPSTR, @buff, 2);
    result := len > 0;
    Imm32ReleaseContext(hWnd, H);
  end;
end;

델파이 2010과 2009에서만 테스트해봤는데, 뭐 코드로 봐서는 그 이전 버전이라도 제대로 동작하지 않을 이유는 없을 거 같네요.

저처럼 IME 기능을 추적하는 용도 이외에 이런 함수를 쓸 일이 있을지는 잘 모르겠지만... ^^;;;;

2009/12/15 03:26 2009/12/15 03:26

trackback :: http://blog.devgear.co.kr/imp/trackback/113

델파이나 C++빌더의 IDE 안에서 프로젝트를 Run으로 실행시킨 경우인지 여부를 코드에서 확인해야 할 경우가 있습니다. 물론, 컴파일된 모드가 디버그 모드인지 릴리즈 모드인지를 확인하기 위해서는 컴파일러 디렉티브 _DEBUG를 쓰면 되는데요.

디버그 모드로 컴파일되어있는지가 아니라 IDE 안에서 Run으로 실행된 경우, 즉 현재 디버깅 진행중인지를 알아내려면 전역변수 DebugHook의 값을 검사하면 됩니다. 이 DebugHook의 값이 0보다 크면 디버깅 중인 것입니다.

델파이라면...
procedure TForm1.Button1Click(Sender: TObject);
begin
  if DebugHook>0 then
    ShowMessage('디버깅 중입니다.');
end;

C++빌더라면...
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  if(DebugHook>0)
    ShowMessage("디버깅 중입니다.");
}

참고로 이 DebugHook 전역변수는 System.pas에 정의되어 있습니다. 델파이3와 C++빌더3 이상의 모든 버전에서 사용하실 수 있습니다.

2009/12/11 13:33 2009/12/11 13:33

trackback :: http://blog.devgear.co.kr/imp/trackback/111

델파이로 서드파티 컴포넌트의 패키지 프로젝트(.dpk)를 사용자인 개발자가 직접 컴파일할 때, DesignIntf 유닛에서 컴파일러 에러가 나는 경우가 있습니다. 이런 경우에는 흔히 ToolIntf, DesignEditors, Proxies 등의 유닛들도 같이 걸리는 경우가 많습니다.

많은 초중급 델파이 개발자들이, 이런 에러를 만나면 일단 이들 유닛들의 pas 혹은 dcu 파일을 찾아서 해결하려고 접근합니다. 게다가, 열심히 찾는 개발자들의 경우, 그 노력에 부응하듯이, 델파이가 설치된 디렉토리 아래에서 이들 파일들의 pas 소스를 찾아내게 됩니다. 그러면 너무나 당연한 공식처럼, 이 파일들을 찾아낸 개발자들은 패키지 프로젝트에 이들 파일을 추가하거나 혹은 이 파일들을 컴파일한 dcu 파일들을 같은 디렉토리에 두든지 하여 패키지 컴파일시에 링크되도록 합니다.

물론 일반적인 델파이 애플리케이션 개발에서는 대부분 그렇게 시도하는 것이 맞습니다만, 여기서는 아닙니다. 이 유닛들이 사용되는 곳은 컴포넌트 개발 혹은 델파이 IDE 위저드 개발이라고 불리는 특수한 영역입니다.

결론부터 말씀드리자면, 절대로 해당 유닛들의 pas나 dcu를 직접 링크시켜서는 안됩니다. 그리고 그 대신 DesignIde.dcp를 requires 섹션에 추가하여 해결해야 합니다.

사용자 삽입 이미지

그 이유를 설명하자면...

uses에 지정된 파일이 없다고 에러가 났으니 공식처럼 당연히 해당 파일을 찾아야겠다는 시도부터가 시작을 잘못한 것입니다. 델파이에서 uses라는 문법은 반드시 실제 dcu 파일(혹은 pas 파일)을 직접 참조해야만 하는 것이 아닙니다.

DesignIntf를 비롯한 이 파일들은 델파이를 사용하는 개발자들에게는 실질적인 어떤 용도로도 전혀 필요하지 않습니다. 다만 컴포넌트 개발자들이 고급 컴포넌트 개발을 할 수 있도록 볼랜드/엠바카데로에서 참고용으로 소스를 넣어둔 것일 뿐입니다.

DesignIntf, ToolIntf, DesignEditors, Proxies 등의 유닛들은 모두 DesignIde.bpl이라는 패키지에 포함되어 있습니다. 이 bpl을 동적으로 링크하기 위한 일종의 임포트 라이브러리 역할을 하는 것이 바로 DesignIde.dcp 파일입니다. 쉽게 말하면, bpl을 사용하려면 같은 이름의 dcp 파일이 있어야 연동될 수 있습니다. (물론 DLL에 대해 LoadLibrary와 마찬가지로 LoadPackage를 사용하면 bpl을 dcp 없이 직접 링크할 수 있지만 여기서는 논외.)

다시 말하면, 패키지 프로젝트의 requires 섹션에서 DesignIde.dcp를 지정하는 것은 DesignIde.bpl을 동적으로 불러다쓰기 위한 기본적인 준비입니다. 거꾸로 말하면, 해당 루틴을 정적 링크를 할 때에는 dcu 파일을 직접 링크해야 하고, 해당 dcu의 기능을 bpl 패키지의 기능으로 호출하려면 dcp를 requires에 추가하는 것입니다.

그럼, dcu를 링크하나 dcp를 통해 bpl을 동적으로 링크하나 동작은 같을 거라는 얘긴데, 그럼 dcu를 직접 링크해도 되지 않나, 하는 생각을 할 수 있습니다. 하지만 이건 안됩니다.

델파이 IDE 자체를 포함해서, 델파이로 만들어진 애플리케이션의 메모리 공간에서 유닛 이름(네임스페이스 이름)과 클래스 이름은 유일해야 합니다. 따라서 한 유닛이 여러번 로딩되려 할 때는 이름 충돌로 에러가 나게 됩니다. 만약 A.dpk 패키지에서 DesignIntf.dcu를 정적으로 링크해버리면 B.dpk 패키지에서는 DesignIntf.dcu를 링크할 수 없게 됩니다.

델파이 IDE 자체에서는 좀 더 심각한데요. DesignIde.bpl 자체가 이미 델파이 IDE의 메모리에 로딩되어 있으므로, DesignIntf, ToolIntf, DesignEditors, Proxies 등의 유닛 이름들은 이미 로딩된 네임스페이스 이름입니다. 따라서 이들 중 하나의 dcu를 포함한(정적으로 링크한) 다른 bpl 패키지가 로딩되려고 하면 바로 이름 충돌이 일어나므로 해당 bpl은 델파이 IDE에 등록이 불가능합니다.

결국, 다시 말해 패키지 형태로 델파이 IDE에 등록하려는 모든 유닛은 단 하나의 패키지에만 포함되어야 합니다(유일해야 한다는 얘기죠). 컴포넌트 이름도 마찬가지입니다. 그렇지 않으면 해당 유닛을 포함한 두번째 이후의 bpl 패키지는 모두 로딩이 실패하게 됩니다. 로딩이 안되니까 당연히 사용도 불가죠.

이런 이유로, DesignIntf, ToolIntf, DesignEditors 등의 유닛들은 절대로 직접 pas 혹은 dcu를 링크하면 안되고 DesignIde.dcp를 requires 섹션에 추가하는 방법으로만 참조할 수 있는 것입니다.

참고로 말씀드리면...
DesignIde에 포함된 이 유닛들은 모두 컴포넌트 개발시에 델파이 IDE에서 디자인타임 전용 기능을 개발하기 위해 필요한 기능들을 가지고 있습니다. 컴포넌트 에디터, 프로퍼티 에디터, IDE 확장 기능의 위저드 개발 기능 등등이죠.
2009/12/09 23:36 2009/12/09 23:36

trackback :: http://blog.devgear.co.kr/imp/trackback/110

몇년 전에 본사에서 나왔던 "Delphi 7 이후 ... 부분에서 좋아진 점들" 문서 시리즈를 업데이트해서, Delphi 7 이후로 Delphi 2010까지 개선되고 강화된 여러 부분들을 각 영역별(IDE / VCL / 언어)로 정리하여 PDF 문서들을 만들었습니다.

아울러 C++Builder에 대해서도, C++Builder 6 이후에 개선된 점들을 역시 IDE와 VCL의 두가지 영역에서 정리해서 문서를 만들었습니다. 언어 영역에 대해서는 문서를 만들지 않았는데요. 사실 C++Builder 2010까지의 언어 부분에서의 가장 큰 개선점들은 C++0x와 TR1, Boost 지원 등이 가장 큰 것인데요. 이런 점들은 독자적인 언어인 Delphi와는 달리 C++ 전반에 대한 표준의 차원이기도 하고, 또 이 내용들은 별도의 고려가 필요할 거 같아서 일단은 제외했습니다)

Delphi 7 ~ Delphi 2010 IDE의 새로운 기능들
Delphi 7 ~ Delphi 2010 VCL의 새로운 기능들
Delphi 7 ~ Delphi 2010 언어의 새로운 기능들

C++Builder 6 ~ C++Builder 2010 IDE의 새로운 기능들
C++Builder 6 ~ C++Builder 2010 VCL의 새로운 기능들
2009/11/19 10:14 2009/11/19 10:14

trackback :: http://blog.devgear.co.kr/imp/trackback/101

  1. 김성동의 생각

    Tracked from acroedit's me2DAY 2009/11/28 16:46  delete

    Delphi 7, C++Builder 6에서 2010까지의 주요 개선점 문서들