Form Style - fsStayOnTop 효과

 SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE)

<-> SetWindowPos(Handle, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE);

 

출처 :  http://www.delmadang.com/community/bbs_view.asp?bbsNo=17&bbsCat=41&indx=405581&keyword1=fsStayOnTop&keyword2=

이 글은 스프링노트에서 작성되었습니다.

 폼 소스 부분은 생략하고 처리부분만 기술한다.

  • Form Style : fsStayOnTop
  • 해당 폼을 TObject 형태로 구현 함수로 넘긴다
    (경우에 따라서 TForm으로 넘기던지 상속클래스 만들어서 넘기던지...그건 알아서...단, 구현부분 파라메터 타입과 구현부분도 거기에 맞추어서 ^^)

 

 

 구현 부분

  1. procedure ShowSaveDialogBox(Sender : TObject = nil)
  2. var
  3. saveDlg : TSaveDialog;
  4. SenderFormStyle : TFormStyle;
  5. isSenderFormStyleChange : Boolean;
  6. begin
  7. isSenderFormStyleChange := False;

    if (Sender <> nil) and Assigned(Sender) and (Sender is TForm) then

    saveDlg := TSaveDialog.Create(TForm(Sender))

    else

    saveDlg := TSaveDialog.Create(nil);

  8. saveDlg.Title := '파일 저장';
  9. saveDlg.Filter := 'TEXT 파일|*.txt';
  10. saveDlg.DefaultExt := 'txt';
  11. saveDlg.Options := saveDlg.Options + [ofOverwritePrompt];
  12. saveDlg.FileName := 'ExportText' + '.xls';
  13. if (Sender <> nil) and Assigned(Sender) and (Sender is TForm) and (TForm(Sender).FormStyle = fsStayOnTop) then
  14. begin
  15. //BEGIN 1안. 폼을 아래로 위치 시킨다(사라지는 효과 나타남)
  16. TForm(Sender).SendToBack;
  17. isSenderFormStyleChange = True;
  18. //END 1안.
  19. //BEGIN 2안. 폼을 일반 폼으로 변경함(화면이 심하게 깜빡거리는 단점)
    SenderFormStyle := TForm(Sender).FormStyle;
  20. isSenderFormStyleChange := True;
  21. TForm(Sender).FormStyle := fsNormal;
  22. Application.ProcessMessages; //(생략가능 혹시나 해서.....^^;;)
  23. //END 2안.
  24.  end;
  25. if saveDlg.Execute then
  26. begin
  27.  {처리 코드}
  28. end;
  29. if isSenderFormStyleChange = True then

    begin

  30. //1안.
  31. TForm(Sender).BringToFront;
  32. //2안.
  33. TForm(Sender).FormStyle := SenderFormStyle;
  34. Application.ProcessMessages; //(생략가능 혹시나 해서.....^^;;)
  35. end;
  36. end;

 

출처 : 자작(userpark)

이 글은 스프링노트에서 작성되었습니다.

 Showmessage 박스 Owner가 Application으로 되어져 있는 현상 때문에 Form이 StayOnTop일 경우 아래에 숨어버리는 현상 발생

해결 방법은 아래 소스.... Screen.ActiveForm을 이용한 방법

 

  1. TForm1 = class(TForm)
  2. {...생략...}
  3. procedure OnScreenActiveFormChange(Sender: TObject);
  4. private
  5. {...생략...}
  6. protected
  7. {...생략...}
  8. public
  9. {...생략...}
  10. end;
  11. procedure TForm1.FormCreate(Sender: TObject);
    begin
  12. Screen.OnActiveControlChange := OnScreenActiveFormChange;
  13. end;
  14. procedure TfrmUbBase_S.OnScreenActiveFormChange(Sender: TObject);
  15. begin
  16. if Assigned(Screen.ActiveForm) and ( (UpperCase(Screen.ActiveForm.ClassName) = UpperCase('TMessageForm')) ) then
  17. begin
  18. SetWindowPos(Screen.ActiveForm.Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE);
  19. end;
  20. end;

 

출처 : 델마당 for Modify By Userpark

이 글은 스프링노트에서 작성되었습니다.

 Showmessage 박스 Owner가 Application으로 되어져 있는 현상 때문에 Form이 StayOnTop일 경우 아래에 숨어버리는 현상 발생

해결 방법은 아래 소스.... Screen.ActiveForm을 이용한 방법

 

  1. TForm1 = class(TForm)
  2. {...생략...}
  3. procedure OnScreenActiveFormChange(Sender: TObject);
  4. private
  5. {...생략...}
  6. protected
  7. {...생략...}
  8. public
  9. {...생략...}
  10. end;
  11. procedure TForm1.FormCreate(Sender: TObject);
    begin
  12. Screen.OnActiveControlChange := OnScreenActiveFormChange;
  13. end;
  14. procedure TfrmUbBase_S.OnScreenActiveFormChange(Sender: TObject);
  15. begin
  16. if Assigned(Screen.ActiveForm) and ( (UpperCase(Screen.ActiveForm.ClassName) = UpperCase('TMessageForm')) ) then
  17. begin
  18. SetWindowPos(Screen.ActiveForm.Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE);
  19. end;
  20. end;

 

출처 : 델마당 for Modify By Userpark

이 글은 스프링노트에서 작성되었습니다.

다음은 동적(Static) DLL로 구현 되어져 있다.

  • 정적(Static) DLL 이란? 본래의 DLL이라기 보다는 코드의 큰 함수들을 따로 모듈별로 분리 했다가 실행 시 함께 처리한다.
  • 동적(Dynamic) DLL(런타임 로딩) 이란 ? DLL은 GetProcAddress라는 API를 사용하여 필요에 따라 첨가하고 필요에 따라 해제시킬 수 있다.

DLL 소스 및 정적 DLL 호출 방법은 다음 글을 참고 하기 바란다.

2010/04/27 - [Language/Delphi] - [Delphi] DLL 호출 규칙(Calling Convention) 테스트용 DLL 및 Source

다음 소스는 Delphi 2010에서 제작 되었으나 기본 사용법은 동일하다.


  1: unit UB_Main_DynDLL;
  2: 
  3: interface
  4: 
  5: uses
  6:   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  7:   Dialogs, StdCtrls;
  8: 
  9: type
 10:   TfrmUBMainDynDLL = class(TForm)
 11:     btnPascal: TButton;
 12:     edtPascal: TEdit;
 13:     btnCdecl: TButton;
 14:     edtCdecl: TEdit;
 15:     btnStdcall: TButton;
 16:     edtStdcall: TEdit;
 17:     procedure btnPascalClick(Sender: TObject);
 18:     procedure btnCdeclClick(Sender: TObject);
 19:     procedure btnStdcallClick(Sender: TObject);
 20:   private
 21:     { Private declarations }
 22:   public
 23:     { Public declarations }
 24:   end;
 25: 
 26: var
 27:   frmUBMainDynDLL: TfrmUBMainDynDLL;
 28: 
 29: implementation
 30: 
 31: const
 32:   ImportDLLFile = 'UPCallTypeDLLTest.dll';
 33:   Msg = '안녕! 세계 (Hellow World!)';   // Hellow World! 국산화 버전 ㅎㅎ
 34: 
 35: var
 36:   DLLCallTypePascal : function (AStr : string)  : PChar;  pascal;
 37:   DLLCallTypeCdecl  : function (AStr : string)  : PChar;  cdecl;
 38:   DLLCallTypeStdcall: function (AStr : string)  : PChar;  stdcall;
 39: 
 40: {$R *.dfm}
 41: 
 42: procedure TfrmUBMainDynDLL.btnCdeclClick(Sender: TObject);
 43: var
 44:   H : HINST;
 45:   S : PChar;
 46: begin
 47:   H := LoadLibrary(PChar(ImportDLLFile));
 48:   if H <= 0 then
 49:   begin
 50:     ShowMessage('로딩 에러 : ' + IntToStr(GetLastError));
 51:   end else begin
 52:     try
 53:       @DLLCallTypeCdecl := GetProcAddress(H, Pchar('DLLCallTypeCdecl'));
 54:       S := DLLCallTypeCdecl(Msg);
 55:       if H <> 0 then
 56:         edtCdecl.Text := S
 57:       else
 58:         edtCdecl.Text := 'ERROR!!';
 59:     finally
 60:       FreeLibrary(H);
 61:     end;
 62:   end;
 63: end;
 64: 
 65: procedure TfrmUBMainDynDLL.btnPascalClick(Sender: TObject);
 66: var
 67:   H : HINST;
 68:   S : PChar;
 69: begin
 70:   H := LoadLibrary(PChar(ImportDLLFile));
 71:   if H <= 0 then
 72:   begin
 73:     ShowMessage('로딩 에러 : ' + IntToStr(GetLastError));
 74:   end else begin
 75:     try
 76:       @DLLCallTypePascal := GetProcAddress(H, Pchar('DLLCallTypePascal'));
 77:       S := DLLCallTypePascal(Msg);
 78:       if H <> 0 then
 79:         edtPascal.Text := S
 80:       else
 81:         edtPascal.Text := 'ERROR!!';
 82:     finally
 83:       FreeLibrary(H);
 84:     end;
 85:   end;
 86: end;
 87: 
 88: procedure TfrmUBMainDynDLL.btnStdcallClick(Sender: TObject);
 89: var
 90:   H : HINST;
 91:   S : PChar;
 92: begin
 93:   H := LoadLibrary(PChar(ImportDLLFile));
 94:   if H <= 0 then
 95:   begin
 96:     ShowMessage('로딩 에러 : ' + IntToStr(GetLastError));
 97:   end else begin
 98:     try
 99:       @DLLCallTypeStdcall := GetProcAddress(H, Pchar('DLLCallTypeStdcall'));
100:       S := DLLCallTypeStdcall(Msg);
101:       if H <> 0 then
102:         edtStdcall.Text := S
103:       else
104:         edtStdcall.Text := 'ERROR!!';
105:     finally
106:       FreeLibrary(H);
107:     end;
108:   end;
109: end;
110: 
111: end.
112: 





출처 : 자작(http://userpark.net)

DLL호출 규칙에 대하여 먼저 언급하고자 한다.

Delphi는 다른 랭귀지에서 사용된 함수들을 쉽게 호출 할 수 있도록 여러 가지 호출 규칙을 가진다.

아래와 같이 5가지 방법이 있다.

  1. Register(__fastcall) : 레지스터에 등록하여 호출하는 방식
  2. stdcall(__stdcall) : 가장 일반적으로 활용하는 방식으로 윈도우 표준
  3. cdecl(__cdecl) : 가변인자가 있는 경우
  4. pascal(__pascal) : Delphi 최적화 코드를 생성하고자 할 때 스택으로 인자를 저장하는 방식보다는 레지스터를 경유하여 속도 향상
  5. safecall : OLE 방식에서 이용

참고 : http://www.delmadang.com/community/bbs_view.asp?bbsNo=3&bbsCat=42&indx=195902&keyword1=dll&keyword2=호출규칙

※pascal 경우 속도 향상이 된다고 책에는 나와있으나 실제 테스트는 하지 않음.

본 글에서는 stdcall,cdecl,pascal 3가지에 대해서만 샘플을 제공하여 드리겠습니다.

아래 소스를 콜타입들을 바꿔가면서 DLL과 App에서 서로 테스트 해보기시기 바랍니다.

그런데 이상하게도 테스트 하면서 stdcall과 pascal은 서로 상호 호환이 완벽하게 이루어졌습니다. 이 해당 소스만이 그런건지 정확히는 현재 알 수 없습니다.

지금까지 저는 DLL을 안 쓰다가 이번에 새로운 일이 생겼는데 DLL을 호출해서 사용해야 할 일이 생겨서 이것 저것 테스트 하다가 이런 문서도 만들게 되었습니다.

(기존 Delphi만 이용시에는 dcu파일로 배포등을 하여 DLL의 필요성을 알지 못했습니다. ^^;;)

정확한 개념이 잡힌 소스인지… 저도 장담을 못하지만 여러가지로 도움이 되었으면 좋겠습니다.

또한 DLL 생성 및 Delphi 기초에 대하여서는 기타 유용한 사이트 및 책을 이용하시기 바랍니다.


아래 방법으로 공부하시기 바랍니다.(저도 이걸로 공부 중)

  1. UPCallTypeDLLTest.dll 을 만든다
  2. UPCallTypeDLLTestApp.exe에서 상기 DLL을 호출한다.
  3. DLL과 APP를 서로 콜방식을 변경하여 가면서 오류 사항 및 반영내용을 스스로 공부한다.

아래 소스는 Delphi 2010으로 만들었습니다.(Delphi 7로 하려다가 그냥~)


Import 해 올 DLL 파일을 반드시 아래 경로에 존재 하여야 한다.
  • [%SystemRoot%] (Windows 디렉토리)
  • [%SystemRoot%]\system32\ 경로 (Microsoft Windows XP 일 경우)
  • 실행파일(현재 작업) 디렉토리에 같이 위치
  • 환경변수 PATH 상의 경로(비추천)

  • UPCallTypeDLLTest.dll
  1: library UPCallTypeDLLTest;
  2: 
  3: uses
  4:   SysUtils,
  5:   Classes,
  6:   Dialogs;
  7: 
  8: {$R *.res}
  9: 
 10: function DLLCallTypePascal(AStr : string) : PChar; pascal;
 11: var
 12:   S : string;
 13: begin
 14:   S := AStr;
 15:   S := 'DLL 함수 테스트 : ' + S + ' - pascal';
 16:   ShowMessage(S);
 17:   Result := PChar(S);
 18: end;
 19: 
 20: function DLLCallTypeCdecl(AStr : string) : PChar; cdecl;
 21: var
 22:   S : string;
 23: begin
 24:   S := AStr;
 25:   S := 'DLL 함수 테스트 : ' + S + ' - cdecl';
 26:   ShowMessage(S);
 27:   Result := PChar(S);
 28: end;
 29: 
 30: function DLLCallTypeStdcall(AStr : string) : PChar; stdcall;
 31: var
 32:   S : string;
 33: begin
 34:   S := AStr;
 35:   S := 'DLL 함수 테스트 : ' + S + ' - stdcall';
 36:   ShowMessage(S);
 37:   Result := PChar(S);
 38: end;
 39: 
 40: exports
 41:   DLLCallTypePascal
 42:   ,DLLCallTypeCdecl
 43:   ,DLLCallTypeStdcall
 44:   ;
 45: 
 46: begin
 47: end.

다음은 정적(Static) DLL로 구현 되어져 있다.

  • 정적(Static) DLL 이란? 본래의 DLL이라기 보다는 코드의 큰 함수들을 따로 모듈별로 분리 했다가 실행 시 함께 처리한다.
  • 동적(Dynamic) DLL(런타임 로딩) 이란 ? DLL은 GetProcAddress라는 API를 사용하여 필요에 따라 첨가하고 필요에 따라 해제시킬 수 있다.
  • UPCallTypeDLLTestApp.exe
      - UB_Main.pas
  1: unit UB_Main;
  2: 
  3: interface
  4: 
  5: uses
  6:   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  7:   Dialogs, StdCtrls;
  8: 
  9: type
 10:   TfrmUBMain = class(TForm)
 11:     btnPascal: TButton;
 12:     edtPascal: TEdit;
 13:     btnCdecl: TButton;
 14:     edtCdecl: TEdit;
 15:     btnStdcall: TButton;
 16:     edtStdcall: TEdit;
 17:     procedure btnPascalClick(Sender: TObject);
 18:     procedure btnCdeclClick(Sender: TObject);
 19:     procedure btnStdcallClick(Sender: TObject);
 20:   private
 21:     { Private declarations }
 22:   public
 23:     { Public declarations }
 24:   end;
 25: 
 26: var
 27:   frmUBMain: TfrmUBMain;
 28: 
 29: const
 30:   ImportDLLFile = 'UPCallTypeDLLTest.dll';
 31:   Msg = '안녕! 세계 (Hellow World!)';   // Hellow World! 국산화 버전 ㅎㅎ
 32: 
 33: function DLLCallTypePascal(AStr : string)   : PChar;  pascal;   external ImportDLLFile;
 34: function DLLCallTypeCdecl(AStr : string)    : PChar;  cdecl;    external ImportDLLFile;
 35: function DLLCallTypeStdcall(AStr : string)  : PChar;  stdcall;  external ImportDLLFile;
 36: function DLLCallTypeStdcallNickName(AStr : string)  : PChar;  stdcall;  external ImportDLLFile name 'DLLCallTypeStdcall';
 37: 
 38: implementation
 39: 
 40: {$R *.dfm}
 41: 
 42: procedure TfrmUBMain.btnCdeclClick(Sender: TObject);
 43: var
 44:   S : PChar;
 45: begin
 46:   S := DLLCallTypeCdecl(Msg);
 47:   edtCdecl.Text := S;
 48: end;
 49: 
 50: procedure TfrmUBMain.btnPascalClick(Sender: TObject);
 51: var
 52:   S : PChar;
 53: begin
 54:   S := DLLCallTypePascal(Msg);
 55:   edtPascal.Text := S;
 56: end;
 57: 
 58: procedure TfrmUBMain.btnStdcallClick(Sender: TObject);
 59: var
 60:   S : PChar;
 61: begin
 62:   S := DLLCallTypeStdcall(Msg);
 63:   edtStdcall.Text := S;
 64: end;
 65: 
 66: end.

 출처 : 자작(http://userpark.net)


PS) 본 소스를 바탕으로 .NET C#과 Visual Basic에서 호출하여 사용하는 방법을 추후 올리겠습니다.

      (대부분 C++에서 DLL을 만드는데 전 C++이 약한 관계로 ^^;;)

UPCallTypeDLLTestForDelphi2010.7z

UPCallTypeDLLTestAppForDelphi2010.7z


UPCallTypeDLLTestGroupForDelphi2010(All).7z


+ Recent posts