'IT/Delphi'에 해당되는 글 14건

  1. 2009.08.17 주석에 대해서(2)
  2. 2009.08.17 [펌]주석에 대해
  3. 2009.06.10 [펌] [번역]델파이에서의 메모리할당과 DLL
  4. 2009.06.01 FormStyle의 StayOnTop 문제점
IT/Delphi2009. 8. 17. 09:08

델파이를 써온지도 어언 10년이 되어 갑니다. 델파이2, 5 를 거쳐서 지금은 2007로 작업을 하는 중이지요.

저는 주석을 달때 가능하면 다음의 룰을 지킵니다.

1. 단순 설명(블럭단위가 아닌 경우)에는 표시선에 합니다.

editor를 보면 가운데 상하로 줄이 하나 죽~ 가있지요. 특별히 손대지 않으면 대부분 80컬럼정도에서 그어집니다. (이거 고치려면 Tool - Option - Editor Options - Display에 보면 Margin and gutter에 Right-margin 의 값을 수정해 주면 됩니다.)

대부분의 주석선은 여기에 맞춰서 합니다.

물론, 하다보면 소스가 길어지면서 넘어가는 경우가 생기죠. 그런데.. 이거 소스가 길어지면 화면이 좌우로 스크롤 되는 경우가 생깁니다. 그러면 가독성이 떨어지죠. 그래서 저 같은 경우는 소스가 길어지면 Right margin근처에서 개행을 하는 편입니다. 그리고 그뒤에 주석을 달죠.

물론.. 하다보면 길어질 수도 있습니다. 연속적으로 동일한 소슥가 있다보니 복사 및 수정, 또는 변경내역을 한눈에 확인 하기 위해 일부러 한줄로 쭉~ 붙여쓰기도 합니다.

if ... then begin A1 end else begin A2 end;
if ... then begin B1 end else begin B2 end;
if ... then begin C1 end else begin C2 end;

원래의 제 코딩 스타일대로라면 then, begin, end, else 등 다음에는 반드시 엔터가 들어가서 개행을 해야 합니다만, 그렇게 하면 위아래의 변화(?)를 한번에 파악하기 어려울 수도 있습니다.

if ... then
begin 
    A1
end
else
begin
    A2
end;
...
...
이렇게 되면 줄이 좀.. 길어지죠. 물론 전제조건은 A1,2 B1,2등이 그렇게 길지 않다라는 전제로 갑니다.
2. 블럭단위로 필요한 경우에는 해당소스의 들여쓰기와 같은 들여쓰기로 기재한다.

한무더기(?)로 싸잡아서 주석을 달고 싶을 때가 있죠.  이때 저는 주석의 시작, 끝을 달아서 범위를 표시합니다.

/////////////////////////////////////////////////
// 어쩌구저쩌구 시작.

어쩌구 저쩌구...

// 어쩌구저쩌구 끝.
/////////////////////////////////////////////////

이러면 일종의 주석이 블럭을 형성하죠.

이 블럭단위 주석을 쓰는 경우가 unit상단에 선언부인 경우가 많습니다. 작업을 하다보면 일정작업에 관련되는 함수들이 죽.. 발생할때가 있죠. 예를 들면 화면 조정관련 이라든가.. 시작제어라든가..

물론, 저는 함수를 기록할때 다음의 룰을 따릅니다.

1. procedure와 function끼리 모은다.

2. 펑션을 모을때는 리턴값의 종류에 따라 모은다. 예를 들면 리턴이 string인것 끼리, TAdoQuery인거끼리, Integer인거 끼리.. 등이다.

다만, 함수량이 너무 많아지고, 전문화 되기 시작하면 이 함수들을 위의 조건에 맞춰서 주석으로 나누게 됩니다.

/////////////////////////////////////////////////
// 화면제어 시작.

function 화면제어 함수들 : Return

procedure 화면제어 함수들
// 화면제어 끝.
/////////////////////////////////////////////////
//저장관련 함수 시작

....

//저장관련 함수 끝
/////////////////////////////////////////////////
이런식으로 일일히 나눕니다. 그러면 이동이나 정리에 나름 편하더군요...
Posted by 비와바람
IT/Delphi2009. 8. 17. 08:42

- 변수/함수/클래스등의 이름은 누구나 알수 있게 충분한 가독성이 있도록 만듭니다.
NameRule처럼 대문자로 구분해도 되고 Name_Rule 처럼 '_'밑줄로 처럼 해도 됩니다.
만드는 사람 맘이지만 대부분 Naming Rule이 있으므로 거기에 따라 만들되 가독성이 중요합니다.

- 주석은 간결하고 내용을 한눈에 알아 볼수 있도록 만듭니다.
주석은 짧고 간결해야 합니다. 뭘 하는지와 뭘 해야 하는지만 적으면 됩니다.
주석이 길면 소스를 분석하는데 오히려 방해가 됩니다.
주석은 구구절절 모든 내용을 담는것이 아닙니다.
단지 내가 볼경우는 나의 기억을 떠올리게 하는 역활을 하고 타인이 볼경우에는 로직의 이해를 돕는것입니다.

왜 해야 하는지가 필요하다면, 간결하게 내용이 길어진다면 소스가 중간이 아니라 Unit의 선두에 기술하거나 따로 문서로 만들어 주세요.
소스명_Readme.txt처럼...

- 소스의 들여쓰기를 반드시 지켜줘야 합니다.
들여쓰기에는 누구도 이의를 제기하지 않지만, 잘 지켜지지 않습니다.
begin~end문의 위치는 만드는 사람 맘이지요? 전 아래처럼 만들고 end문 뒤에 이넘이 어떤넘의 end인지를 알려 줍니다.

예>
01.  while 어쩌구 do
02.  begin
03.     for i := 0 to iCount -1 do
04.     begin
05.  
06.       if 저쩌구 then
07.       begin
08.       end; // <-- if 저쩌구
09.     end; // <-- for i := 0 to iCount -1
10.  end; // <-- while 어쩌구

-  procedure나 Function 선두에는 이넘의 하는일과 사용법을 적습니다.
뭘 하는지는 Naming Rule만 봐도 알수 있지만 친절히 적어 줍니다. 사용법(파라미터 하나 하나까지)은 필수 입니다.
저는 개인적으로 예제도 적습니다. 예제에 대한 설명은 적지 않습니다. 단지 예제만...

- Unit에 주석을 달아 주세요.
class, procedure와 function 그리고 하다못해 변수에도 주석을 달면서 왜 Unit에는 주석을 달지 않을까요?
unit에도 반드시 주석을 달아야 합니다. 변경이력등 가장 많은 정보를 담을수 있는곳이 unit입니다.
전 개인적으로 타인에게 소스를 양도해야 하는경우 소스명_Readme.txt에 따로 담아 두기도 합니다.

- 변경 이력 사항은 반드시 소스에 적어 주세요.
중요 로직의 시작점에 반드시 변경 이력사항을 적습니다.
일반 개발자는 변경 이력사항이 뭐 필요하지 라고 할지 모르지만, SM등의 관리자나 패키지 개발 또는 Component를 개발하는 경우 혼자만 사용할것이 아니므로 누구누구의 요청에 의한 개발/필요 없음 등등을 한줄 주석으로 달아 둡니다.
상단히 유용할뿐아니라 대고객서비스에  효과가 최고 입니다.

- To Do List를 활용해야 합니다.
To-Do List를 잘 활용하면 원하는 내용을 검색하기도 좋고 추가/수정/삭제/업데이트에 유용합니다.
또한 주석의 의미를 가지므로 관리에도 후처리 작업에도 효율성이 좋습니다.

어떤 방법이던 개발자가 얼마나 부지런하게 움직이느냐에 달려 있습니다.
저처럼 게으른 사람들은 반드시 주석을 꼭꼭 달아 놔야 낭패를 면합니다.

즐거운 하루 되시기 바랍니다

---------------------------------------------------------

델마당에서 허락없이 퍼왔습니다.. -.-;;;

http://www.delmadang.com/community/bbs_view.asp?bbsNo=19&bbsCat=0&st=&keyword=&indx=415255&keyword1=&keyword2=&page=1
Posted by 비와바람
IT/Delphi2009. 6. 10. 15:00
http://www.delmadang.com/community/bbs_view.asp?bbsNo=3&bbsCat=0&st=&keyword=&indx=413800&keyword1=&keyword2=&page=1

---------------------------------------------------------------------------------


//http://www.codexterity.com/memmgr.htm
//위 글을 날림 번역한 것입니다. 나은 번역 있으시면은 덧글로 부탁합니다.


< 델파이에서의 메모리할당과 DLL >

마법사로 DLL을 만들면 이런 주석이 달립니다.

    {중요: ShareMem을 uses절 맨 처음에 달아라. unit이랑 Project-View Sorce 모두에 그렇게 해야 한다.
    strings를 파라미터로 전달하거나 결과값으로 리턴하는 경우에 말이다.
    record나 class안의 어디에 처박혀 있든, strings가 있다면 효과를 볼 것이다.
    SharMem은 공유메모리 관리자인 BORLNDMM.DLL의 interface unit이다. 이 DLL은 당신의 DLL과 같이 배포돼야 한다.
    이런 방식이 싫다면, string 정보를 PChar이나 ShortString으로 전달해라.}

왜 이런 주의사항이 필요할까요? 그 이유는 델파이가 메모리를 할당하는 방식에 뿌리를 두고 있습니다.
Windows에는 메모리를 할당할 때 쓰로록 네이티브 루틴들이 준비돼 있습니다. VirtualAlloc, HeapAlloc, GlobalAlloc, LocalAlloc 등이죠.
델파이는 나름의 할당원칙을 지키는데요. 뭐, 더 정확히 말하자면 보조할당기를 쓴다고 할 수 있습니다.
델파이에서는 이런 식입니다. 일단 heap을 부르고요(priority heap아닙니다. 혼동하지 마시길). C/C++에서는 free store라고 것입니다.

보조할당기가 하는 일은 모든 동적 메모리를 할당하는 겁니다.
  프로그래머가 명시적으로 잡아주었던 raw memory에서부터,
  컴파일러에 의해 암시적으로 할당된 메모리로의
  할당이죠.

strings, 동적배열, 객체 등을 생성할 때 말입니다.

사실 개발자들 중에 아래 문장을 적으면서, 메모리가 암시적으로 할당되고 있다고 느끼는 사람은 적습니다.
  var
    s:string;
  ...
  s:=s+'abc';

델파이 유저들에게 친숙한 동적 메모리할당 함수들은 GetMem, FreeMem, New, Dispose 이런 것들입니다.
하지만, 사실은 단순해 보이는 동작들에서도 델파이는 heap 메모리를 할당해 쓰고 있습니다.
    * Object creation using a constructor
    * Long string variables, and operations on them
    * Operations on short string variables
    * Creation and resizing of dynamic arrays
    * String/array values in variants
    * Explicit allocation using GetMem()/FreeMem(), New() and Dispose()
이런 데서 말입니다.

델파이에서, 모두 객체는 heap에 !삽!니!다!(//"live"로 강조하고 있습니다.)
이는 Java나 C#(Java/Delphi의 영향을 부정하고 있죠)과 비슷합니다.

하지만, C++다릅니다. C++에서 객체들은 stack에도 heap에도 심지어는 data segment에도 삽니다.
16bit windows programming에 친숙한 개발자들은 궁금해 할지도 모르겠군요.
어째서 델파이는 Windows의 heap을 사용하지 않는지 말입니다.
HeapCreat(), HeapAlloc(), HeapFree() 같은 것을 쓰면 되는데 말입니다.
이도저도 아니면 VirtualAlloc(), VirtualFree()를 쓰면 되지 않을까요.

델파이가 이러는 단순한 이유는 speed입니다.

Windows heap functions, 이것들은 Delphi의 native allocation에 비하면 매우 느립니다.// 앞서 말한 Heap...()들
virtual memory allocations, 이것들도 느리기는 마찬가지 입니다. //앞서 말한 Virtual...()들

앞의 것들이 느린 이유는 그저 '아주 많은 조그만 조각들'에 맞도록 디자인한 것이 아니라서 그런 겁니다.
애초에 heap이라는 것이 비교적 큰 덩어리를 위한 공간이니까요. 
//Stack은 미리 자리를 차지하기 때문에 비교적 작고 분명한 것을 쌓는데 쓰고, Heap은 상대적으로 큰 것들을 쌓는데 쓴다고 배운듯...

어쨌거나,
하위에 하위를 이어 할당해야하는 상황이어서 커다란 영역이 필요하면,
suballocator는 virtaul memory function들을 최대한 호출합니다.

memory manager code는 System.pas, GetMem.inc에 들어 있습니다. 당연히 모든 어플리케이션에 statically linked됩니다.
이렇게 해도 보통 때에는 아무런 문제가 되지 않습니다.
델파이로 제작한 DLL을 쓰고 있는 어플리케이션에서는 다음과 같이 예측할 수 있습니다.
사실 DLL은 별개로 컴파일된 어플리케이션이라는 점, 그러니까 자체적으로 memory manager의 사본을 받는다는 점,
그러니까 별개의 heap이 만들어 진다는 점(//원문은 'heap이 분리된다'입니다).
이 점이 가장 중요한 점입니다.
각각 별개의 어플리케이션이(exe와 exe뿐만 아니라 exe와 dll 사이라도),
각자 자기의 heap을 관리하게 됩니다.

이 두 heap의 존재를 인식하지 못하고 실수로 메모리를 관리하게 되면, 연달아 문제가 됩니다.


    heap이 뭐야? 
        heap이 낯설고 델파이에서 어떤 식으로 쓰이는 지 모르는 분들을 위해서,
        heap은 메모리의 한 영역입니다. 여기에 동적 할당된 메모리(내용)가 저장됩니다.
        C든, C++든, Delphi든, C#이든, 모든 structured language에서 프로그래머는 두가지의 메모리를 씁니다.
        static, dynamic //정적, 동적
        기본 데이터형은 static입니다. 컴파일 할 때 부터 요구사항이 정해져 있습니다. //크기를 압니다.
        integer, 열거형, record, 정적 배열, 이런 것들 정적으로 할당됩니다.(staticall allocated)

        C에서 모든 자료형은 정적입니다.
        그러니까 동적으로 메모리를 할당하고 싶다면, 프로그래머는 명시적으로 malloc()같은 메모리 할당 루틴을 써야 합니다.
       
        한편, 동적 메모리는 run-time에 그 크기가 재조정됩니다.
        예를 들자면, Delphi의 long strings, 클래스, 동적배열 등이 있습니다.
        VisualBasic에서는, 많은 자료형이 동적으로 할당됩니다. 그중에 대표적인 것이 variant와 동적 배열입니다.
        요약하자면, 어떤 데이터 형이든 run-time에 크기가 변할 가능성을 열어두려면, 동적으로 할당되어야 합니다.

        컴파일러의 입장에서 보자면, 이 두가지 형태의 메모리는 굉장히 다릅니다.
        이 두 친구는 어플리케이션의 메모리 영역중에서도 엄격하게 분리된 다른 구역에 삽니다.
        메모리라는 것을 이렇게 둘로 나누어 생각하는 것은 현대 프로그래밍에 깊이 배어 있습니다.//색이 든 천으로 비유
        깊게는 OS까지, 아래로는 하드웨어 자체에까지 말입니다.
        이래서 x86 family같은 많은 chip들이 explicit data와 stack segments를 분리하여 지원합니다.

자동생성되는 주석문으로 이야기를 시작했는데요.
  문자열 정보를 넘기려거든 PChar나 ShortString을 쓰라고 했잖아요
그건 아마도 PChar나 ShortString을 쓰면 문제가 없겠거니 생각하게 만듭니다.
하지만, 매우 잘못된 방향으로 이끄는 것이라고 봅니다.
애 사탕주듯 해서, 개발자들에게 잘못된 보안 감각에 빠져들게 한다고 봅니다.//안정성을 걱정하는 듯
(더 자세한 정보를 보시려면 ShortStrings and Chars라는 글을 보세요.)//원문에 링크 걸려 있음.


자 생각해 봅시다:

    In DLL:

            function GetStringList: TStringList;
            begin
                Result := TStringList.Create;
                Result.Add( 'foo' );
            end;

    In EXE:
            var obj: TStringList;
                ...
            obj := GetStringList;
            // do something
            obj.Free; // may corrupt DLL heap; may free >1 blocks
              // DLL의 heap을 더럽히고 있습니다. 아마도 한개 이상의 block을 free합니다.
              ////이부분을 잘 이해하고 번역해야 하는데 그렇지 못한 점 죄송합니다. 아래는 추측입니다.   
              ////EXE의 heap에 메모리를 할당하고, free한다고 생각하겠지만,
              ////할당하지도 않았던, DLL의 heap에서도 free시도   
       

EXE가 객체에 뭘 하느냐에 달렸지만, 아마도 양쪽 heap을 모두 더럽힐 겁입니다.
자, 봅시다. 델파이6같은 경우에, a모듈의 heap에서부터 b모듈의 메모리를 해제하려고 하는 경우에,
자체로는 heap을 더럽히는 걸로 보이지 않습니다.
heap manager는 free memory block을 linked-list에 보관합니다.
그리고, 삭제가 일어나면 가까운 두 free block을 병합하려고 합니다.
"Invalid pointer operation" exception은
  a모듈이 b모듈의 free list에서 마지막으로 할당됐던 block을 해제하려고 할 때에만 일어납니다.
  // aModul Free -> bModule.Items[theLast].Free
invalid element이므로 인식하는데 실패하고는,
그 free block을
marker element라고 생각되는 것(혹은 그저 garbage일 수도 있는 것)과 병합하려고 합니다.
이게 에러를 일으킵니다.
에러는 이 경우에만 일어나지만, heap manager의 실행에 있어서는 이런식으로 그치지 않습니다.
나중 버전에서는 heap이 더럽혀지는 일이 아무 곳에서나 일어날 수도 있습니다.

//번역하고도 무슨 소린지 원????? 그래도 하던 것이므로 계속합니다.

위의 코드를 고쳐봅시다.

In DLL:

        function GetPChar: PChar;
        begin
            Result := StrAlloc( 13 );
            StrCopy( Result, 'Hello World!' );
        end;

        procedure FreePChar( p: PChar );
        begin
            StrDispose( p );
        end;

In EXE:

        var p: PChar;
            ...
        p := GetPChar;
        // do something
        FreePChar( p ); // heap-friendly free

TStringList버전은 교정할 수가 없습니다.
EXE의 heap에 생성되었던 strings는 TStringList의 destructor에 의해 free 되어야 하기 때문입니다.
EXE의 heap이 더럽혀집니다.

그럼 해결책은 무엇일까요?  몇가지 방법이 있습니다:

- Sharemem.pas/Borlndmm.dll을 쓰고, 보통처럼 한다:
    가장 간단한 방법으로 보입니다. 특별히 주의할 일도 없습니다.
    하지만 치러야할 댓가는 있습니다:
        모든 할당은 Borlndmm.dll을 경유합니다. 통상적인 할당보다 2~8배 느리겠군요.
        이 속도저하는 모든 할당에 적용됩니다.
        DLL안에서의 연산에만이 아니라, 문자열연산 객체연산 등등 모두 속도저하됩니다.
        어플리케이션 배포할 때 Borlndmm.dll도 같이 배포해야 합니다.

- 모듈간에는 동적 데이터를 절대로 주고 받지 않는다:
    어려운 일입니다. 델파이 타입 시스템에 대한 깊은 이해를 요구합니다.
    여러 개발자와 함께라면 강요하기가 특히 힘들겁니다.

- DLL이 다른 언어로 쓰인 것처럼 취급하고 API-style로 관리한다:
    이것은 다소 그럴듯합니다.
    이 경우에, 만약 프로젝트에 다양한 언어가 쓰였다면,
        DLL을 교차하는델파이만의 construct를 쓰지않기로 한 것만으로도 더이상 복잡해지지는 않겠습니다.
    단점은 많은 Delphi-contruct를 쓰지 못합니다.(객체, 문자열, 동적배열 등등)

- 자신만의 API를 운영한다:
    DLL간 클래스나 문자열을 던질 때에는 자신만의 API 만들어 사용합니다.
    예를 들자면, 자신의 객체를 생성하고 해제할 GetMyObejct/FreeMyObject같은 것을 만들어 씁니다.
    한쪽의 heap만을 쓰도록 만들어야 합니다. 이 의제된 객체에 heap operation을 수행해선 안된다는 것을 기억해야 합니다.
    당연한 얘기지만, 이것은 의존적인 프로세스입니다. 원칙이 있어야 합니다.
    복잡해지다가 심해진다 싶으면 세 번째 방법으로 하는 것이 낫습니다.
    똑같이 복잡하지만, 세번째 방법은 다른 언어에서도 쓰일 수 있다는 장점이 하나 더 있습니다.

- DLL 내부적으로 COM objects를 씁니다:
    극단적인 방법입니다. 그저 DLL간의 통신을 위해서만 COM을 씁니다.
    퍼포먼스가 떨어지고, 많은 노력을 해야 합니다.

하지만 더 간단한 방법이 있습니다. FastSharemem unit을 사용하는 것입니다.
차선책이기는 합니다만, unit 하나만 추가하면 되므로  사용하기 쉽고, 무엇보다 퍼포먼스가 떨어지지 않습니다.
DLL을 같이 배포해야 할 일도 없습니다.

//번역은 여기까지입니다. heap에 대한 내용전달에 힘썼습니다만, 실력부족입니다.
//Unit하나를 추천하면서 글이 끝나는데, 이 유닛에 대해 모릅니다. 저는 그저 heap에 관심이 있었습니다. ;)


---------------------------------------------------------------------------------

감사합니다...
Posted by 비와바람
IT/Delphi2009. 6. 1. 09:05
http://cbuilder.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_tip&no=883

장성호님의 글입니다.


Design-time때  Form의 FormStyle을 fsStayOnTop으로 설정하고
해당Form을 Show또는 ShowModal해보면

실제로 StayOnTop이 적용이 안된다는 질문이 커뮤니티에 심심찮게 올라옵니다.

비슷한 팁들이 여러가지 있던데... 정확한 원인과 증상에 대한 설명은 잘 없더군요
제가 올린 답변글에서도 마찬가지구...


오늘 일때문에 간단히 테스트 해보았는데...
정확한 이유에 대해서는 설명을 못하겠지만.
증상과 해결방안에 대해서 좀 기술해 보겠습니다.


Form의 FormStyle을    fsStayOnTop으로 설정하면

Form이 생성될때 TCustomForm의 CreateWnd함수에서 다음과 같은 코드가 실행됩니다.

       
  1. procedure TCustomForm.CreateWnd;   
  2. var  
  3.   ClientCreateStruct: TClientCreateStruct;   
  4. begin  
  5.   inherited CreateWnd;   
  6.   if NewStyleControls then  
  7.     if BorderStyle <> bsDialog then  
  8.       SendMessage(Handle, WM_SETICON, 1, GetIconHandle) else  
  9.       SendMessage(Handle, WM_SETICON, 10);   
  10.   if not (csDesigning in ComponentState) then  
  11.     case FormStyle of  
  12.       fsMDIForm:   
  13.          ...   
  14.       fsStayOnTop:   
  15.         SetWindowPos(Handle, HWND_TOPMOST, 0000, SWP_NOMOVE or  
  16.           SWP_NOSIZE or SWP_NOACTIVATE); // 팁과 똑같은 방식으로 설정함    
  17.     end;   
  18. end;  



stayontop관련 팁들을  보면 대게
SetWindowPos( Handle , HWND_TOPMOST, ...) 를 하라고 되어있죠

그런데 이렇게 한후에 Form을 Show 하면
Application(프로그램)내에서는 해당폼이 top으로 뜹니다.

그런데 전체 desktop에는 적용이 안되죠

제가 이해한 것은 Form이 Visible=true일때랑 false일때
SetWindowPos(Handle, HWND_TOPMOST ... 이 다르게 먹는다는것입니다.


그럼
Form을 데스크탑 전체에 topmost로 항상띄우려면 어떻게 해야할까요?

Form의 OnShow이벤트에서
SetWindowPos(Handle, HWND_TOPMOST...해주면 됩니다.
       
  1. procedure TForm2.FormShow(Sender: TObject);   
  2. begin  
  3.     SetWindowPos(Handle, HWND_TOPMOST, 0000, SWP_NOMOVE or  
  4.             SWP_NOSIZE or SWP_NOACTIVATE);   
  5. end;  


FormStyle을 그냥 fsNormal로 둬도 상관없구요

Form이 만약 hide되었다가 다시 Show할때 topmost가 해제 되기때문에
매번 Form이 show될때마다 SetWindowPos(Handle, HWND_TOPMOST...를 해줘야 합니다.


그런데...
Form을 Show했을때랑 ShowModal했을때 TopMost가 다르게 동작하는 부분도 있더군요

ShowModal로 했을경우엔 위와같이 Form의 OnShow에서
한번 SetWindowPos(..HWND_TOPMOST...)해주면 되는데..

그냥 Show로 할경우 현재프로그램의 다른 Form으로 포커스를  이동할경우엔 문제없지만
다른프로그램으로 이동하면 topmost가 풀려버립니다.

이경우 현재프로그램이 Deactivate 될때 TopMost폼을 다시  ToopMost로 Set해주면 되더군요
다음과 같이...

       
  1. procedure TForm1.FormCreate(Sender: TObject);   
  2. begin  
  3.   Application.OnDeactivate:=AppDeactivate;   
  4. end;   
  5.   
  6. procedure TForm1.AppDeactivate(Sender: TObject);   
  7. begin  
  8.   if Form2.Visible then  
  9.   begin  
  10.     SetWindowPos(Form2.Handle, HWND_TOPMOST, 0000, SWP_NOMOVE or  
  11.       SWP_NOSIZE or SWP_NOACTIVATE );   
  12.   end;   
  13. end;  



참 그리고 만약 top속성을 변경하고 싶다고
그리고 run-time에 FormStyle을 변경하는 경우가 있는데...
이것도 별로 바람직하지는 않습니다.
임프님이 작성한 팁에  나와있듯이 Form이 한번 껌벅거릴것입니다.
http://cbuilder.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_tip&no=32
FormStyle을 변경할때 CreateWindow를 다시 하기때문이죠

윈도우 핸들을 따로 저장해뒀다 .. 뭐시기 하는경우 문제가 발생할수 있겠죠
그리고 Form위의 다른 window-control도 모두 CreateWindow를 다시 하기때문에 매우 좋지 않습니다.

간만에 팁을 올렸네요
요즘 회사일이 바쁘기도 하구...
개인적으로 운영하는 카페도 신경쓴다구... 볼포에는 Q&A만 주로 하네요..

그럼..
Posted by 비와바람