2014. 2. 13. 16:21

델파이 API

■윈도우API
●System Modal 폼을 만들려면?
 윈도우 API 함수인 SetSysModalWindow를 사용하면 가능하다.
 다은 System Modal 창을 보여주는 간단한 예제이다.


procedure TMainForm1.Create(Application) do
begin
 SetSysModalWindow(Handle);
end;


●.RES 파일에서 비트맵을 불러 오려면?
 다음과 같이 선언한다.


implementation
{$R C:DelphiMydirMyRes.Res} <- .RES 파일이 있는 경로명과 파일명


 위와 같이 선언한 후에 사용시에는 다음과 같이 윈도우 API 함수를 이용한다.


Image1.Picture.Bitmap.Handle := LoadBitmap(HInstance, 'BITMAP1');


●Win95와 W3.X를 구별하는 법은?
 윈도우 API 함수인 GetVersion을 쓰면 가능하다.
 다음은 버튼을 누르면 윈도우의 버전을 보여준다.


procedure TForm1.Button1Click(Sender : TObject);
var
 x : Lonhint;
 y,z : integer;
begin
 x := GetVersion;
 y := integer(x and $ff);
 z := integer(x shr 8) and $ff);
 Edit1.Text := IntToStr(y);
 Edit2.Text := IntToStr(z);
end;


●마우스 커서를 보이지 않게 하려면?
 윈도우 API 함수인 ShowCursor에서 값을 False 로 준다.


●정의된 Message Handler에 다른 작업을 추가하려면?
 예를 들어, CM_DIALOGKEY Message가 발생되었을 때 원하는 작업을 추가하려고 한다면 Public Section에 다음과 같이 선언한다.


procedure CMDialogKey(var Message : TCMDialogKey);message DM_DIALOGKEY;


procedure 이름을 Message 이름에서 _(밑줄) 표시를 뺀다. Procedure 의 정의는 다음과 같다.


procedure TForm1.CMDialogKey(var Message : TCMDialogKey);
begin
 if CharCode = VK_TAB then begin
   {Process the Alt+Tab key here}
   result := 1;
   exit;
 end;
 inherited;
end;


Result를 1로 Setting하면 더 이상 실행시키지 않고 중단시키겠다는 뜻이고, inherited 문은 Parent Handler 로 제어를 보냄을 의미한다.
 모든 작업을 일일이 처리하지 않으려면 inherited 문을 사용하기 바란다.


●런타임시에 DLL을 Load하고 Free시키는 방법은?
 if H<32 then begin
   ShowMessage('No DLL');
   exit;
 end;
 DicProc := TDisProc(GetProcAddress(H, 'displayTable'));
 edit1.Text := DisProc;
 FreeLibrary(H);
end;


●비정상적으로 종료된 DLL 프로그램을 강제적으로 Unload하는 방법은?
 윈도우 API 함수인 GetModuleHandle 은 DLL의 Handle을 돌려주므로 ModuleHandle 이 0을 리턴할 때까지 Freelibrary를 Call한다.
 만약 DLL이 다른 DLL을 Load했다면 Child DLL을 먼저 Free 시킨다.


●DLL의 Data Segment를 Fixed에서 Movable로 바꾸는 방법은?
 DLL 외부에서 GlobalPageUnlock(DESG)를 부르면 된다. 이 함수는 DLL 소스에서 Pointer 등을 이용하지 않는다면 정상적으로 실행될 것이다.


●Title Bar가 없는 Form을 움직이게 하려면?
 폼 위에서 마우스 커서가 움직이면, 윈도우는 폼에 WM_NCHitTest 메시지를 보낸다. 이때 폼은 마우스가 폼의 어느 위치에 있는지를 메시지로 주게 된다. 마우스의 버튼을 누르는 것과 같은 Event가 발생하면 윈도우는 이 정보를 써서 특정 행동을 수행하게 되는 것이다.
 다음은 WM_NCHitTest 메시지가 특정한 값을 주는 예제 코드이다.


procedure TNoCapForm.WMNCHitTest(var Msg : TMessage);
begin
 if GetAsynKeyState(VK_LBUTTON) < 0 then
   Msg.Result := HTCAPTION
 else
   Msg.Result := HTCLIENT;
end;


●Resource를 동적으로 Load/Free하는 방법은?
 윈도우가 제공하는 LoadResource(), FreeResource() API 함수를 사용한다.


●Visual Basic의 doEvent 와 같은 기능을 사용하려면?
 다음과 같이 함수를 만들 수 잇다.


function doEvents : Boolean;
var
 msg : TMsg;
begin
 while PeekMessage(msg, 0, 0, 0, PM_REMOVE) do
 begin
   if msg.message = WM_QUIT then
   begin
    PostQuitMessage(msg.wParam);
    doEvents := true;
    exit;
   end
   else
   begin
    TranslateMessage(msg);
    DispatchMessage(msg);
   end;
 end;
 doEvents := false;
end;


●프로그램의 실행이 끝나기를 기다리는 법은?
 윈도우 함수는 핸들을 돌려주므로 이것을 이용한다.


procedure SomeProc;
var
 ProgramHandle : THandle;
begin
 ProgramHandle := WinExec('C:Program.exe', SW_SHOWNORMAL);


 {프로그램이 종료될 때까지 반복}
 while GetMoudleusage(ProgramHandle) <> 0 do Application.ProcessMessages;
end;


●프로그램 실행중에 잠시 멈추고 다른 프로세스를 실행하려면?
 다음과 같은 코드를 작성할 수 있다.


procedure TForm1.Delay(msecs : integer);
var
 FirstTickCount : longint;
begin
 FirstTickCount := GetTickCount;
 repeat
   {실행을 잠시 중단하고 다른 프로세스를 실행한다.}
   Application.ProcessMessages;
 until ((GetTickCount-FirstTickCount) >= LongInt(msecs));
end;


 참고로 Application.ProcessMessages는 메시지 큐에 쌓여 있는 메시지 중 하나를 처리하고 메시지가 큐에 없으면 False를 리턴한다.


●Control의 Handle 이나 ID를 얻는 방법은?
 Control Object의 Pointer를 알고 있다면 PointerToMyControl^.HWindow가 바로 윈도우 핸들이다.


 만약, Control 의 Handle을 알고 있다면 GetDlgCtrlID() API 함수는 ID를 돌려준다.


ControlID := GetDlgCtrlID(ControlHandle);


 만약 Control의 Pointer를 모르고 ID만 알고 있다면, GetDlgItem() API 함수는 Handle을 돌려준다.


ControlHandle := GetDlgItem(DialogHandle, COntrolID);


●프로그램이 실행된 디렉토리를 알 수 있는 방법은?
 다음의 함수는 Application 이라는 개체의 ExeName 속성으로부터 디렉토리 경로를 추출해낸다.


function GetExePath : String;
var
 LastBackSlashPos, Index : Integer;
begin
 Result := Application.ExeName;
 for Index := 1 to length(Result) do
   if REsult[Index] = '' then LastBackSlashPos := Index;


 {'' 기호가 붙지 않도록 하려면 LastBackSlashPos에서 1을 빼야 한다}
 Result[0] := chr(LastBackSlashPos - 1);
end;


●Directory를 만드는 방법은?
 MKDIR Procedure를 이용하면 된다.


MkDir('C:DelphiMyDir');


●MediaPlayer를 이용하지 않고 Sound를 발생할 수 있는 방법은?
 mmSystem에 있는 SndPlaySound Function을 이용하면 된다.


SndPlaySound('C:Windowsding.WAV', snd_Async);


●윈도우의 Message를 처리하는 방법은?
 다음 윈도우 메시지를 처리하는 Procedure를 참고하기 바란다.


procedure YieldToOthers;
var
 MSG : TMSG;
begin
 while PeekMessage(MSG, 0, 0, 0, PM_REMOVE) do begin
   if Msg.Message = WM_QUIT then exit;
   TranslateMessage(Msg);
   DispatchMessage(Msg);
 end;
end;


●윈도우의 Main Message Procedure를 만드는 방법은?
 다음 예제 Procedure를 참고하기 바란다.


procedure TForm1.ClientWndProc(var Message : TMessage);
begin
 with Message do
   case Msg of
    WM_MOUSEMOVE : Memo1.Lines.Add('Mouse Move');
    WM_LBUTTONDOWN : Memo1.Lines.Add('LeftButton down');
   else
    Result := CallWindowProc(FPrevClientProc, Handle, Msg, wParam, lParam);
   end;
end;


●다른 응용프로그램의 메뉴 기능을 실행하려면?
 다음 예제 Procedure를 참고하기 바란다.


CurrWnd := GetWindow(Application.Handle, gw_hwndfirst);
length := GetWindowText(Currwnd, tmpstr, 255);


if length > 0 then
begin
 if(pos('훈민정음‘, strpas(tmpstr)) > 0) and (strpas(pAttach^.filepath.tmpstr) <> nil) then
   CurrWnd := 0;
end;


tmpname := ExtractFilename(strpas(pAttach^.filepath));


while CurrWnd <> 0 do
begin
 length := GetWindowText(CurrWnd, tmpstr, 255);


 if (length > 0) and (pos('훈민정음‘, strpas(tmpstr) > 0) and (pos(tmpname,
                                                       StrPas(tmpstr)) > 0) then
   break;


 CurrWnd := GetWindow(CurrWnd, GW_HWNDNEXT);
 Application.ProcessMessages;
end;


Handle := CurrWnd;


if Handle <> 0 then
begin
 SendMessage(Handle, WM_COMMAND, 4005, 0);
 SendMessage(Handle, WM_SYSCOMMAND, SC_CLOSE, 0);
end;


●폼이 최소화되지 못하게 하려면?
 다음과 같이 WM_SYSCOMMAND 메시지를 처리하면 된다.


type
 TForm1 = class(TForm)
   public :
       procedure WMSysCommand(var Msg : TWMSysCommand);message
                                                       WM_SYSCOMMAND;
   end;


procedure TForm1.WMSysCommand(var Msg : TWMSysCommand);
begin
 {최소화/최대화 버튼을 누를 때 아무 작용을 하지 않게 한다}
 if (Msg.CmdType = SC_MINIMIZE) or (Msg.CmdType = SC_MAXMIZE) then
   Msg.CmdType := SC_RESTORE;
 DefaultHandler(Msg);
end;


●DPR 파일의 Application.Run이 실행되기 전에 Window 메시지를 가로채는 방법은?
 다음과 같이 새로운 Windows Message Procedure를 정의하고, 그것을 Main Windows Procedure 로 설정한다.
 다음 예제 Procedure를 참고하기 바란다.


program Project1;
uses
 Forms, messages, wintypes, winprocs,
 Unit1 in 'UNIT1.PAS';


{$R *.RES}


var
 OldWndProc : TFarProc;


function NewWndProc(hWndAppl : HWnd; Msg, wParam : Word; lParam : Longint):
                       Longint; export;
begin
 result := 0; {Default WndProc return value}
 {message 처리 루틴이 들어갈 곳}
 result := CallWindowProc(OldWndProc, hWndAppl, Msg, wParam, lParam);
end;


begin
 Application.CreateForm(TForm1, Form1);
 OldWndProc := TFarProc(GetWindowLong(Application.Handle, GWL_WNDPROC));
 SetWindowLong(Application.Handle, GWL_WNDPROC, longint(@NewWndProc));
 Application.Run;
end.


●Task Handling 방법은?
 ToolHelp unit 에 저으이되어 있는 함수들을 이용하면 된다.
 다음은 TaskFirst, TaskNext 등을 이용한 예제이다.


function isTaskInstance(HInst : Longint) : Boolean;
var
 CurrentTask : TTaskEntry;
 Success : boolean;
begin
 Result := false;
 Yield;
 CurrentTask.dwSize := SizeOf(CurrentTask);
 Success := TaskFirst(@CurrentTask);
 while success do begin
   if CurrentTask.HInst = HInst then begin
     Result := true;
     exit;
   end;
   Success := TaskNext(@CurrentTask);
 end;
end;


●Virtual Key Code List는 어디서 찾나?
 Windows.pas에 있다.


●현재 원하는 프로그램이 실행중인지를 찾는 방법은?
 Findwindow를 사용하기 바란다.


procedure TForm1.Button1Click(Sender : TObject);
var
 Apppath : string;
 Fhandle : HWND;
begin
 Apppath := ExtractFilepath(Application.exename);
 WinExec(Pchar(Apppath+'project1.exe'),SW_SHOW)
 Application.ProcessMessage;
 while FHandle = 0 do
   Fhandle := FindWindow('Tapplication', 'project1');
end;


●DLL 사용법
 1.C에서 작성한 DLL을 델파이에서 사용시


C에서 DLL 만들 때
_declspec(dllexport) int fixtags(char *filename, short level, char* tag_prfix)
{
}
Delphi에서 사용.
Interface
 function fixtags(filename : PChar; level : Smallint; tagprefix : Pchar): integer;FAR
                                                                       ;CDECL;
implementation
 function fixtags(filename : PChar; level : Smallint; tagprefix : Pchar): integer; external
               'dllfix.dll' name 'fixtags';


2.델파이에서 작성한 DLL을 델파이에서 사용시


implementation
 function GetPassword(Apassword : Pchar): WordBool; far; external PASSWORD.dll';


●윈도우 메시지로 Edit의 Text Handling 하려면?
procedure TForm1.Button1Click(Sender : TObject);
var
 p : pChar;
 I : integer;
begin
 I := edit1.perform(wm_GetTextLength, 0, 0) + 1;
 p := AllocMem(i);
 edit1.perform(wm_GetText, I, longint(p));
 edit2.perform(wm_SetText, 0, longint(p));
 FreeMem(p, I);
end;


●Cursor를 Load하려면?
delphiimagescursors 안에 있는 CURSOR를 사용한다.
Image Editor를 상ㅇ하여 Res File로 Load 한다.


{$R programsdelphiMyFile.res}


const Cursorx = 1; {임시 숫자}


procedure stuff;
begin
 Screen.cursors[Cursorx] := LoadCursor(hInstance, pchar('cursor_1'));
 Screen.cursors := PutitHere;
end;


●Mouse 위치를 제조정하려면?
procedure PlaceMouse(x,y : word);
var
 tp : TPoint;
begin
 tp := ClientToScreen(point(x, y));
 SetCursorPos(tp.x, tp.y);
end;


●Application을 Program Manager/Start Menu에 추가하려면?
1.TDDEClientConv Component를 Form 에 추가한다.
2.다음의 코드를 추가한다.


var
 Macro : String;
 Command : Array[0..255] of Char;
begin
 {link를 연다.}
 DDEClient.OpenLink;


 {group을 생성}
 Macro := Format('[CreateGroup(%s)]', ['<your group name>']) + #13#10;
 StrPcopy(Command, Macro);
 if not DDEClient.ExecuteMacro(Command, False) then
   MessageDlg('<your error message>', mtError, [mbok], 0);
 {application을 추가}
 Macro := '[AddItem('+<your application>+', '+<your description>+')]' + #13#10;
 StrPcopy(Command, Macro);
 if not DDEClient.ExecuteMacro(Command, False) then
   MessageDlg('your error message>', mtError, [mbok], 0);


 {새로운 group를 보여줌}
 StrPCopy(Command, '[ShowGroup(NonExist, 1)]');
 DDEClient.ExecuteMacro(Command, False);


 {link를 닫음}
 DDEClient.OpenLink;
end;


●Text를 Rotate 하려면?
procedure TextRotate(LocalCanvas : TCanvas; Text : String; X : Integer; Y : Integer;
                       RotateAngle : Integer);
var
 Logfont : TLogFont;
begin
 {font 정보를 구함}
 GetObject(LocalCanvas.Handle, Sizeof(TLogFont), LogFont);


 LogFont.lfEscapement := RotateAngle * 10;


 {새로운 rotated font handle을 할당}
 LocalCanvas.Font.Handle := CreateFontIndirect(LogFont);


 {print text}
 LocalCanvas.TextOut(X, Y, Text);
end;


●on_click Event를 발생하지 않고 ComboBox를 체크하려면?
procedure CheckNoClick(CB : TCheckBox; CheckIt : Boolean);
begin
 CB.Perform(BM_SETCHECK, Ord(CheckIt), 0);
end;


<CheckNoClick 프로시저 호출하는 방법>
CheckNoClick(ComboBox1, True);


●프로그램상에서 Network Drive를 연결하려면?
procedure TForm1.Button1Click(Sender : TObject);
var
 NRW : TNetResource;
begin
 with NRW do
   begin
    dwType := RESOURCETYPE_ANY;
    lpLocalName := 'X:';         //map to this driver letter
    lpRemoteName := '\ MyServerMyDirectory';
    // Must be filled in. if an empty string is used,
    // it will use the lpRemoteName.
    lpProvider := '';
   end;
 WNetAddConnection2(NRW, 'MyPassword', 'MyUserName',
                               CONNECT_UPDATE_PROFILE);
end;


●PORT를 인식하려면?
<읽기>
function GetPort() : Byte;
var
 InValue : Byte;
 Address : Word;
begin
 asm
   mov DX, Address
   in AL,DX
   mov InValue, AL
 end;


 GetPort := InValue;
end;


<쓰기>
procedure SetPort(OutValue : Byte);
var
 Address : Word;
begin
 Address : Word;
begin
 asm
   mov DX,Address
   mov AL, OutValue
   out DX, AL
 end;
end;


●그래픽으로 프린트하는 대신에 TPrinter에게 프린터에 내장된 기본 글꼴을 사용하도록 하려면?
 윈도우 API 함수인 GetStockObject() 함수를 사용해서 디바이스 디폴트 글꼴 핸들을 얻고, Printer.Font.Handle 에 대입하면 된다.


uses Printers;


procedure TForm1.Button1Click(Sender : TObject);
var
 tm : TTextMetric;
 I : integer;
begin
 if PrintDialog1.Execute then begin
   Printer.BeginDoc;
   Printer.Canvas.Font.Handle := GetStockObject(DEVICE_DEFAULT_FONT);
   GetTextMetrics(Printer.Canvas.Handle, tm);
   for I := 1 to 10 do begin
    Printer.Canvas.TextOut(100, i*tmHeight + tm.tmExternalLeading, 'Test');
   end;
   Printer.EndDoc;
 end;
end;


●윈도우 95의 시작 버튼의 문서 메뉴에 문서를 추가하려면?
 Shell 함수인 SHAddToRecentDocs를 사용한다.


uses ShlOBJ;


procedure TForm1.Button1Click(Sender : TObject);
var
 s : string;
begin
 s := 'C:DownLoadntkfaq.html';
 SHAddToRecentDocs(SHARD_PATH, pChar(s));
end;


●응용프로그램에 할당된 CPU 시간을 변경하려면?
 다음 예제는 응용프로그램에 주어지는 CPU 우선순위를 변경하는 것이다. 이 우선 순위를 변경할 때에는 너무 높은 값을 주지 않도록 한다.
 추가 정보는 Win32 도움말 중에서 SetThreadPriority() 함수를 참조하기 바란다.


procedure TForm1.Button1Click(Sender : TObject);
var
 ProcessID : DWORD;
 ProcessHandle : THandle;
 ThreadHandle : THandle;
begin
 ProcessID := GetCurrentProcessID;
 ProcessHandle := OpenProcess(PROCESS_SET_INFORMATION, false, ProcessID);
 SetPriorityClass(ProcessHandle, REALTIME_PRIORITY_CLASS);
 ThreadHandle := GetCurrentThread;
 SetThreadPriority(ThreadHandle, THREAD_PRIORITY_TIME_CRITICAL);
end;


●문자열의 배경색을 변경하려면?
 API 함수인 SetBkColor() 과 TextOut()을 사용한다.


procedure TForm1.Button1Click(Sender : TObject);
var
 OldTextColor : TColorRef;
 OldBkColor : TColorRef;
 OldBkMode : Integer;
begin
 OldTextColor := SetTextColor(Form1.Canvas.Handle, RGB(0,0,255));
 OldBkColor := SetBkColor(Form1.Canvas.Handle, RGB(255,0,0));
 OldBkMode := SetBkMode(Form1.Canvas.Handle, OPAQUE);
 TextOut(Form1.Canvas.Handle, 100, 100, 'Blue text on red Background', 27);
 SetBkMode(Form1.Canvas.Handle, OldBkMode);
 SetBkColor(Form1.Canvas.Handle, OldBkColor);
 SetTextColor(Form1.Canvas.Handle, OldTextColor);
end;


●코드에서 Display 모드 설정을 변경하려면?
 윈도우 API 함수인 EnumDisplaySettings()을 사용하여 설정되어 있는 모드 설정에 대한 리스트를 얻을 수 있고, ChangeDisplaySettings()는 디스플레리 설정을 변경 하기 위해서 사용될 수 있다. 그러나 많은 드라이버들은 변경사항이 가능하도록 설정했어도, 컴퓨터를 재부팅하지 않고 재설정을 수행할 수 없다.


unit Unit1;


interface


uses
 Windows, Messages, Sysutils, Classes, Graphics, Control, Forms,
 Dialogs, StdCtrls, Spin;


type
 PdmArray = ^TDmArray;
 TDmArray = array[0..] of TDeviceMode;


type
 TForm1 = class(TForm)
   Memo1 : TMemo;
   SpinEdit1 : TSpinEdit;
   Button1 : TButton;
   procedure FormCreate(Sender : TObject);
   procedure FormDestroy(Sender : TObject);
   procedure Button1Click(Sender : TObject);
 private
   lpDmArray : PDmArray;
   NumModes : integer;
   {            }
 public
   {            }
end;


var
 Form1 : TForm1;


implementation
{$R *.DFM}


procedure TForm1.FormCreate(Sender : TObject);
var
 I : integer; //auto-initialized to zero
 MoreModes : bool;
 dm : TDeviceMode;
begin
 Memo1.Lines.Clear;
 MoreModes := True;


 while MoreModes do begin
   MoreModes := EumDisplaySettings(nil, I, Dm);
   Memo1.Lines.Add('Mode '+
    IntToStr(i) + ': '+
    IntToStr(Dm.DmBitsPerPel) + ' Bits Per Pixel ' +
    IntToStr(Dm.DmPelsWidth) + ' X ' +
    IntToStr(Dm.DmPelsHeight));
   Inc(i);
 end;


 NumModes := I;
 SpinEdit1.MinValue := 0;
 SpinEdit1.MaxValue := NumModes;


 GetMem(lpDmArray, sizeof(TDeviceMode) * NumModes);
 FillChar(lpDmArray^, sizeof(TDeviceMode) * NumModes, #0);


{$IFOPT R+}
 {$DEFINE CKRANGE}
 {$R-}
{$ENDIF}
 for I := 0 to (NumModes - 1) do
   EnumDiaplaySettings(nil, I, lpDmarray[i]);
{$IFDEF CKRANGE}
 {$UNDEF CKRANGE}
 {$R+}
{$ENDIF}
end;


procedure TForm1.Button1Click(Sender : TObject);
var
 ReturnVal : Longint;
begin
{$IFOPT R+}
 {$DEFINE CKRANGE}
 {$R-}
{$ENDIF}
 ReturnVal := ChangeDisplaySettings(lpDmArray[SpinEdit1.Value],
                                       CDS_UPDATEREGISTRY);
{$IFDEF CJRANGE}
 {$UNDEF CKRANGE}
 {$R+}
{$ENDIF}
 with Memo1.Lines do begin
   case ReturnVal of
    DISP_CHANGE_SUCCESSFUL : Add('DISP_CHANGE_SUCCESSFUL');
    DISP_CHANGE_RESTART : Add('DISP_CHANGE_RESTART');
    DISP_CHANGE_BADFLAGS : Add('DISP_CHANGE_BADFLAGS');
    DISP_CHANGE_FAILED : Add('DISP_CHANGE_FAILED');
    DISP_CHANGE_BADMODE : Add('DISP_CHANGE_BADMODE');
    DISP_CHANGE_NOTUPDATED : Add('DISP_CHANGE_NOTUPDATED');
   end;
 end;
end;


procedure TForm1.FormDestroy(Sender : TObject);
begin
 FreeMem(lpDmArray, sizeof(TDeviceMode) * NumModes);
end;


end.


●인쇄시 용지 크기를 바꾸려면?
 인쇄 작업의 시작에서 프린터의 설정을 변경하기 위해서는 프린터의 디바이스 모드 구조를 변경해야 한다.


※참고
 델파이의 DEVMODE 도움말 파일.


다음 예는 사용되는 용지 설정과 용지 크기를 변경하는 코드이다.


procedure TForm1.Button1Click(Sender : TObject);
var
 Device : array[0..255] of char;
 Driver : array[0..255] of char;
 Port : array[0..255] of char;
 hDMode : THandle;
 PDMode : PDEVMODE;
begin
 Printer.PrinterIndex := Printer.PrinetrIndex;
 Printer.GetPrinter(Device, Driver, Port, hDMode);
 if hDMode <> 0 then begin
   pDMode := GlobalLock(hDMode);
   if pDMode <> nil then begin
    {Set to legal}
    pDMode^.DmFields := pDMode^.DmFields or Dm_PaperSize;
    pDMode^.DmPaperSize := DMPAPER_LEGAL;


    {Set to custom size}
    pDMode^.DmFields := pDMode^.DmFieldS or
                       DM_PAPERSIZE or
                       DM_PAPERWIDTH or
                       DM_PAPERLENGTH;
    pDMode^.DmPaperSize := DMPAPER_USER;
    pDMode^.DmPaperWidth := 100 {SomeValueInTenthsOfAMillimeter};
    pDMode^.DmPaperLength := 100 {SomeValueInTenthsOfAMillimeter};


    {Set the bin to use}
    pDMode^.DmFields := pDMode^.DmFields or DMBIN_MANUAL;
    pDMode^.DmDefaultSource := DMBIN_MANUAL;


    GlobalUnlock(hDMode);
   end;
 end;
 Printer.PrinterIndex := Printer.PrinterIndex;
 Printer.BeginDoc;
 Printer.Canvas.TextOut(100, 100, 'Test 1');
 Printer.EndDoc;
end;


●코드에서 주어진 프린터의 포트를 변경하려면?
 포트를 변경하기 위해서는 TPrinter의 SetPrinter 메소드를 사용할 수 있다.
다음 예는 파일로 인쇄할 포트를 변경하는 것이다.


uses Printers;


{$IFNDEF WIN32}
 const MAX_PATH = 144;
{$ENDIF}


procedure TForm1.Button1Click(Sender : TObject);
var
 pDevice : pChar;
 pDriver : pChar;
 pPort : pChar;
 hDMode : THandle;
 PDMode : PDEVMODE;
begin
 if PrintDialog1.Execute then begin
   GetMem(pDevice, cchDeviceName);
   GetMem(pDriver, MAX_PATH);
   GetMem(pPort, MAX_PATH);
   Printer.GetPrinter(pDevice, pDriver, pPort, hDMode);
   Printer.SetPrinter(pDevice, PDriver, 'FILE:', hDMode);
   FreeMem(pDevice, cchDeviceName);
   FreeMem(pDriver, MAX_PATH);
   FreeMem(pPort, MAX_PATH);
   Printer.BeginDoc;
   Printer.Canvas.TextOut(100, 100, 'Delphi is RAD!');
   Printer.EndDoc;
 end;
end;


●기본 윈도우 프린터를 변경하려면?
 Win.ini 파일에서 Windows 섹션의 Device 키에 Device 키에 목록화된 프린터, 드라이버, 포트를 변경하기 위해서 WM_WININICHANGE 메시지를 보내야 한다.


uses
 IniFiles;


procedure TForm1.Button1Click(Sender : TObject);
var
 WinIni : TIniFile;
 WinFileName : array[0..MAX_PATH] of char;
 s : array[0..64] of char;
begin
 GetWindowDirectory(WinIniFileName, sizeof(WinIniFileName));
 StrCat(WinIniFileName, 'win.ini');
 WinIni := TIniFile.Create(WinIniFileName);
 try
   WinIni.WriteString('windows','device', 'HP LaserJet Series II, HPPCL, LPT1 :');
 finnaly
   WinIni.Free;
 end;


 StrCopy(S, 'windows');
 SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, LongInt(@S));
end;


●윈도우의 시작 메뉴에 현재의 문서들의 목록들을 제거하려면?
 윈도우의 API 함수인 SHAddToRecentDocs()에 파일 이름 매개변수에 nil을 넘겨 호출한다.


uses
 ShlOBJ;


procedure TForm1.Button1Click(Sender : TObject);
begin
 SHAddToRecentDocs(SHARD_PATH, nil);
end;


●Tray 응용프로그램에서 팝업 메뉴가 포커스를 잃을 때 종료되지 않는 경우가 있는데, 종료하려면?
 메뉴를 팝업 처리하기 위해서 매시지를 처리할 때, 즉 foreground 윈도우로 설정되었을 때, 팝업 메뉴 후에 WM_NULL 메시지를 보내면 된다.


procedure TForm1.WndProc(var Msg : TMessage);
var
 p : TPoint;
begin
 case Msg.Msg of
   WM_USER + 1:
   case Msg.lParam of
    WM_RBUTTONDOWN : begin
       SetForegroundWindow(Handle);
       GetCursorPos(p);
       PopupMenu1.Popup(p.x, p.y);
       PostMessage(Handle, WM_NULL, 0, 0);
    end;
   end;
 end;
 inherited;
end;


●real only 로 설정된 String Grid가 있다. 만약 String Grid에 키 입력을 하려 하고 &Exit 라는 Caption을 가진 버튼이 있을 때, Stringgrid에서 사용자가 x 키를 누를 때마다(Alt 키를 누르지 않았어도), 버튼 클릭이 실행된다. 이를 방지하려면?
 다음 예는 폼 레벨에서 DM_DIALOGCHAR 메시지를 가죠 오는 예이다. 이것은 Alt 키를 누른다면 다이얼로그 문자에 응답할 기회를 주는 것으로 문자 단축키의 기본 핸들링을 막는 것이다.


type
 TForm1 = class(TForm)
   Button1 : TButton;
   StringGrid1 : TStringGrid;
   procedure FormCreate(Sender : TObject);
   procedure Button1Click(Sender : TObject);
   procedure StringGrid1KeyDown(Sender : TObject; var Key : Word; Shift :
                                       TShiftState);
 private
   {            }
   procedure CMDialogChar(var Message : TCMDialogChar);
               message CM_DIALOGCHAR;
 public
   {            }
end;


var
 Form1 : TForm1;


implementation
{$R *.DFM}


procedure TForm1.FormCreate(Sender : TObject);
begin
 Button1.Caption := '&Exit';
end;


procedure TForm1.Button1Click(Sender : TObject);
begin
 Application.Terminate;
end;


procedure TForm1.StringGrid1KeyDown(Sender : TObject; var Key : Word;
                                       Shift : TshiftState);
begin
 ShowMessage('Grid keypress = ' + Char(Key));
 Key := 0;
end;


procedure TForm1.CMDialogChar(var Message : TCMDialogChar);
begin
 if ssAlt in KeyDataToShiftState(Message.KeyData) then
   inherited;
end;


●주어진 파일의 이름 또는 경로명을 알려면?
 윈도우 API 함수인 GetShortPathName을 사용하면 된다.


procedure TForm1.Button1Click(Sender : TObject);
var
 Buffer : array[0..255] of char;
begin
 GetShortPathName('C:Program FilesBorlandCommon FilesBdeBde32.hlp', @buffer,
                       sizeof(Buffer));
 Memo1.Lines.Add(Buffer);
end;


●그룹 지어진 파일이나, 파일을 복사할 때 윈도우 탐색기에서 사용하는 복사 애니메이션 다이얼로그 화면을 사용하려면?
 다음 예는 그룹지어진 파일을 복사하는 함수인 SHFileOperation을 사용하고, 처리 과정 다이얼로그를 보여주는 예이다. 삭제, 이동, 이름 변경에 대해서는 다음의 플래그를 사용할 수 있다.


TO_COPY
FO_DELETE
FO_MOVE
FO_RENAME


uses ShellAPI;


procedure TForm1.Button1Click(Sender : TObject);
var
 Fo : TSHFileOpStruct;
 buffer : array[0..4096] of char;
 p : pchar;
begin
 FillChar(Buffer, sizeof(Buffer), #0);
 p := @buffer;
 p := StrECopy(p, 'C:Download1.ZIP') + 1;
 p := StrECopy(p, 'C:Download2.ZIP') + 1;
 p := StrECopy(p, 'C:Download3.ZIP') + 1;
 StrECopy(p, 'C:Download4.ZIP');


 FillChar(Fo, sizeof(Fo), #0);
 Fo.Wnd := Handle;
 Fo.wFunc := FO_COPY;
 Fo.pForm := @Buffer;
 Fo.pTo := 'D:';
 Fo.fFlags := 0;
 if ((SHFileOperation(Fo) <> 0) or (Fo.fAnyOperationsAborted <> false)) then
   ShowMessage('Cancelled');
end;


●픽셀 배열로부터 Bitmap을 빠르게 생성하려면?
 픽셀 배열로부터 Bitmap을 생성하는 방법은 윈도우 API 함수인 CreateDiBitmap()을 사용한다. 이것은 윈도우가 픽셀 데이터를 저장하기 위해서 사용하는 Bitmap 형식에 독립적인 많은 디바이스들 중 하나를 사용하는 것이다. 이것은 윈도우 시스템에서 작동하는 이점을 가진다.
 다음의 예는 픽셀 배열로부터 256 Color Bitmap을 생성한다. 이 Bitmap은 256 회색 그림자를 사용하여 흰색에서 검은 색으로 점점 색이 변한다. 윈도우는 시스템 색상들을 사용하기 위해서 첫 번째와 마지막의 10가지 색상들을 따로 보관한다. 그래서 256 회색 그림자들 중 Maximum을 가져올 수 잇다.


{$IFNDEF WIN32}
type
 {Used for pointer math under Win16}
 PPtrRec = ^TPtrRec;
 TPtrRec = record
   Lo : Word;
   Hi : Word;
 end;
{$ENDIF}


{Used for huge pointer math}
function GetBigPointer(lp : pointer; Offset : Longint) : Pointer;
begin
 {$IFDEF WIN32}
 GetBigPointer := @PByteArray(lp)^[Offset];
 {$ELSE}
 Offset := Offset + TPtrRec(lp).Lo;
 GetBigPointer := Ptr(TPtrRec(lp).Hi + TPtrRec(Offset).Hi * SelectorInc,
                       TPtrRec(Offset).Lo);
 {$EBDIF}
end;


procdure TForm1.Button1Click(Sender : TObject);
var
 hPixelBuffer : THandle; {Handle to the pixel buffer}
 lpPixelBuffer : pointer; {pointer to the pixel buffer}
 lpPalBuffer : PLogPalette; {the palette buffer}
 lpBitmapInfo : PBitmapInfo; {The bitmap info header}
 BitmapInfoSize : longint; {Size of the bitmap info header}
 BitmapSize : longint; {Size of the pixel array}
 PaletteSize : integer; {Size of the palette buffer}
 I : longint; {loop variable}
 j : longint; {loop variable}
 OldPal : hPalette; {temp palette}
 hPal : hPalette; {handle to our palette}
 hBm : hBitmap; {handle to our bitmap}
 Bm : TBitmap; {temporary Tbitmap}
 Dc : hdc; {used to convert the doB to a DDB}
 IsPaletteDevice : bool;
begin
 Application.ProcessMessages;
 {if range checking is on - turn it off for now}
 {we will remember if range checking was on by defining}
 {a define called CKRANGE if range checking is on.}
 {We do this to access array members past the arrays}
 {defined index range without causing a range check}
 {error at runtime. To satisfy the compiler, we must}
 {also access the indexes with a variable. ie : if we}
 {have an array defined as a: array[0..0] of byte,}
 {and an integer I, we can now access a[3] by setting}
 {i := 3; and then accessing a[i] without error}
 {$IFOPT R+}
  {$DEFINE CKRANGE}
  {$R-}
 {$ENDIF}


 {Lets check to see if this is a palette device - if so, then}
 {We must do palette handling for a successful operation.}
 {Get the screen's dc to use since memory dc's are not reliable}
 dc := GetDc(0);
 IsPaletteDevice := GetDeviceCaps(dc, RASTERCAPS) and RC_PALETTE =
                                                               RCPALETTE;
 {give back the screen dc}
 dc := ReleaseDc(0, dc);


 {The bitmap info size must be the size of the BitmapInfo}
 {plus the size of the color table - one color table entry}
 {is already defined in TBitmapInfo}
 BitmapInfoSize := sizeof(TBitmapInfo) + (sizeof(TRGBQUAD) * 255);


 {The Bitmap size must be the width of the bitmap rounded}
 {up to the nearest 32 bit boundary}
 BitmapSize := (sizeof(byte) * 256) * 256;


 {The size of the palette must be the size of the bitmap rounded}
 {up to the nearest 32 bit boundary}
 BitmapSize := (sizeof(byte) * 256) * 256;


 {The size of the palette must be the size of a TLogPalette}
 {plus the number of color palette entries - 1, since there}
 {is already one palette entry defined in TLogPalette}
 if IsPaletteDevice then
   PaletteSize := sizeof(TLogPalette) + (sizeof(TPaletteEntry) * 255);


 {Get the memory for the BitmapInfo, the PixelBuffer, and the Palette}
 GetMem(lpBitmapInfo, BitmapInfoSize);
 hPixelBuffer := GlobalAlloc(GHND, BitmapSize);
 lpPixelBuffer := GlobalLock(hPixelBuffer);


 if IsPaletteDevice then
   GetMem(lpPalBuffer, PaletteSize);


 {Zero out the BitmapInfo, the PixelBuffer, and the Palette}
 FillChar(lpBitmapInfo^, BitmapInfoSize, #0);
 FillChar(lpPixelBuffer^, Bitmapsize, #0);


 if IsPaletteDevice then
   FillChar(lpPalBuffer^, PaletteSize, #0);


 {Fill in the BitmapInfo structure}
 lpBitmapInfo^.bmiHeader.biSize := sizeof(TBitmapInfoHeader);
 lpBitmapInfo^.bmiHeader.biWidth := 256;
 lpBitmapInfo^.bmiHeader.biHeight := 256;
 lpBitmapInfo^.bmiHeader.biPlanes := 1;
 lpBitmapInfo^.bmiHeader.biBitCount := 8;
 lpBitmapInfo^.bmiHeader.biCompression := BI_RGB;
 lpBitmapInfo^.bmiHeader.biSizeImage := BitmapSize;
 lpBitmapInfo^.bmiHeader.biXPelsPerMeter := 0;
 lpBitmapInfo^.bmiHeader.biYPelsPerMeter := 0;
 lpBitmapInfo^.bmiHeader.biClrUsed := 256;
 lpBitmapInfo^.bmiHeader.biClrImportant := 256;


 {Fill in the BitmapInfo color table with gray shades : black to white}
 for I := 0 to 255 do begin
   lpBitmapInfo^.bmiColors[i].rgbRed := I;
   lpBitmapInfo^.bmiColors[i].rgbGreen := I;
   lpBitmapInfo^.bmiColors[i].rgbBlue := I;
 end;


 {Fill in the pixel buffer array with shades : black to white}
 {In a 256 color bitmap the color is an index into the color table}
 for I := 0 to 255 do
   for j := 0 to 255 do
     Byte(GetBigPointer(lpPixelBuffer, i+(j*256))^) := j;


 {Fill in the palette structure}
 if IsPaletteDevice then begin
   lpPalBuffer^.palVersion := $300;
   lpPalBuffer^.palNumEntries := 256;
 {Fill in the palette structure color table}
 for I := 0 to 255 do begin
   lpPalBuffer^.PalPalEntry[i].peRed := I;
   lpPalBuffer^.PalPalEntry[i].peGreen := I;
   lpPalBuffer^.PalPalEntry[i].peBlue := I;
 end;


 {Create a palette}
 hPal := CreatePalette(lpPalBuffer^);
end;


{Get the screen's dc to use for the sonversion since}
{memory dc's are not reliable to ues for conversions}
dc := GetDc(0);


if IsPaletteDevice then begin
   {If we are using a palette, it must be}
   {selected into the dc during the conversion}
   OldPal := SelectPalette(dc, hPal, True);
   {Realize the palette}
   RealizePalette(dc);
end;


{Do the conversion}
hBm := CreateDiBitmap(dc, lpBitmapInfo^.bmiHeader, CBM_INIT, pChar(lpPixelBuffer),
                       lpBitmapInfo^, DIB_RGB_COLORS);


if IsPaletteDevice then begin
   {Select the Old palette back in}
   SelectPalette(dc, OldPal, true);
   {Realize the old palette}
   RealizePalette(dc);
end;


{Give back the screen dc}
dc := ReleaseDc(0, dc);


{Create a temporory TBitmap}
bm := Tbitmap.Create;


{Free up the memory we used}
if IsPaletteDevice then
   FreeMem(lpPalBuffer, PaletteSize);
GlobalUnlock(hPixelBuffer);
GlobalFree(hPixelBuffer);
FreeMem(lpBitmapInfo, BitmapInfoSize);


{Assign the palette}
if IsPaletteDevice then
   bm.Palette := hPal;


{Assign the handle}
bm.Handle := hBm;


{Size Image1}
Image1.Width := 256;
Image1.Height := 256;


{Assign the bitmap}
Image1.Picture.Bitmap := bm;


SelectPalette(Image1.Picture.Bitmap.Canvas.Handle, Image1.Picture.Bitmap.Palette, false);


{Turn range checking back on if it was on when we started}
{$IFDEF CKRANGE}
 {$UNDEF CKRANGE}
 {$R+}
{$ENDIF}
end;


●TTimer 컴포넌트를 사용하지 않고, 시스템을 Lock하지 않고 지연시키려면?
 다음 예는 시간의 체크하는 루프를 사용하고, 루프가 실행되는 동안 처리된 윈도우 메시지들을 수행하도록 하는 Application.ProcessMessages를 호출한다.


procedure Delay(ms : longint);
var
 TheTime : LongInt;
begin
 TheTime := GetTickCount + ms;


 while GetTickCount < YheTime do
   Application.ProcessMessages;
end;


procedure TForm1.Button1Click(Sender : TObject);
begin
 ShowMessage('Start Test');
 Delay(2000);
 ShowMessage('End Test');
end;


●Flashing Icon을 생성하려면?
 윈도우 API 함수인 FlashWindow()을 호출한다.


var
 Flash : bool;


procedure TForm1.Timer1Timer(Sender : TObject);
begin
 FlashWindow(Form1.Handle, Flash);
 FlashWindow(Application.Handle, Flash);
 Flash := not Flash;
end;


procedure TForm1.FormCreate(Sender : TObject);
begin
 Flash := False;
end;


●RTL은 하나의 입력 Palette에만 TLogPallette를 정의한다. 그런데 하나 이상의 입력을 가진 Palette를 생성하려면?
 RTL은 원하는 팔레트 입력들의 수를 가진 Palette를 동적으로 생성하도록 하기 위해서, 오직 한 개의 입력을 가진 TLogPalette를 정의한다. 추가적인 입력들을 액세스 하기 위해서 범위 체크가 없애야 한다. 그리고 변수를 사용하여 Palette 입력 인덱스를 액세스해야만 한다.
 다음 예는 256 입력들을 가진 논리적 Palette 구조를 동적으로 생성하는 것이다. 범위 체크를 없애고, 회색 그림자로 그들을 채움으로써 Palette 입력들을 액세스한다. 그리고 Palette 에 핸들을 생성하고, 할당된 리소스들을 없앤다.


procedure TForm1.Button1Click(Sender : TObject);
var
 lpPalette : PLogPalette;
 hPal : hPalette;
 I : integer;
begin
 {palette에 사용된 메모리를 할당한다.}
 GetMem(lpPalette, sizeof(TLogPalette)+ (255*sizeof(TPaletteEntry)));


 {palette header를 채운다}
 lpPalette^.palVersion := $300;
 lpPalette^.palNumEntries := 256;


 {범위 체크를 없앤다.}
 {범위 체크 상태를 기억한다.}
 {$IFOPT R+}
  {$DEFINE CKRANGE}
  {$R-}
 {$ENDIF}


 {회색 그림자로 palette 구조 색상 테이블을 채운다.}
 for I := 0 to 255 do begin
   lpPalette^.PalPalEntry[i].peRed := I;
   lpPalette^.PalPalEntry[i].peGreen := I;
   lpPalette^.PalPalEntry[i].peBlue := I;
 end;


 {Turn range checking back on if it was on when we started}
 {$IFDEF CKRANGE}
  {$UNDEF CKRANGE}
  {$R+}
 {$ENDIF}


 {palette 핸들을 생성한다.}
 hPal := CreatePalette(lpPalette^);


 {palette 구조에 의해서 메모리 사용을 해제한다.}
 FreeMem(lpPalette, sizeof(TLogPalette) + (255*sizeof(TPaletteEntry)));


 {이 부분에 palette를 가지고 코딩을 한다.}


 {사용 후에 palette 핸들을 삭제한다.}
 DeleteObject(hPal);
end;


●회전되는 글자체를 생성하려면?
 TrueType 글씨체를 사용해야 한다.
 다음의 코드는 45도로 회전하는 글꼴을 생성하는 예이다.


procedure TForm1.Button1Click(Sender : TObject);
var
 lf : TLogFont;
 tf : TFont;
begin
 with Form1.Canvas do begin
   Font.Name := 'Arial';
   Font.Size := 24;
   tf := TFont.Create;
   tf.Assign(Font);
   GetObject(tf.Handle, sizeof(lf), @lf);
   lf.lfEscapement := 450;
   lf.lfOrientation := 450;
   tf.Handle := CreateFontIndirect(lf);
   Font.Assign(tf);
   tf.Free;
   TextOut(20, Height div 2, 'Rotated Text!');
 end;
end;


●Language 정의를 받아 들이는 윈도우 API 함수들을 가지고 사용된 PRIMARYLANGID() , SUBLANGID() and MAKELANGID() 매크로들을 정의하려면?
 다음 예는 PRIMARYLANGID(), SUBLANGID(), 그리고 MAKELANGID() 메크로에 대해 동등한 기능을 하는 예제이다.


function PRIMARYLANGID(lgid : Word) : LongInt;
begin
 result := lgid and $3FF;
end;


function SUBLANGID(lgid : Word) : LongInt;
begin
 result := lgid shr 10;
end;


function MAKELANGID(sPrimaryLanguage : Word; sSubLanguage : Word) : Word;
begin
 result := (sSubLanguage shl 10) or sPrimaryLanguage;
end;


●주어진 시간에 Windows 인쇄 스풀러에서 얼마나 많은 인쇄 작업이 있는지를 알아내는 방법은?
 Windows 인쇄 스풀러는 스풀러 큐로부터 추가되거나 삭제될 때마다 WM_SPOOLERSTATUS 메시지를 보낸다.
 다음 예는 이 메시지를 가져 오는 예이다.


type
 TForm1 = class(TForm)
   Label1 : TLabel;
 private
   {            }
   procedure WM_SpoolerStatus(var Msg : TMSPOOLERSTATUS);
               message WM_SPOOLERSTATUS;
 public
   {            }
end;


var
 Fomr1 : TForm1;


implementation
{$R *.DFM}


procedure TForm1.WM_SpoolerStatus(var Msg : TWMSPOOLERSTATUS);
begin
 Label1.Caption := InttoStr(msg.JobLeft) + ' Jobs currenly in spooler');
 msg.Result := 0;
end;


●PrintScreen 키를 눌렀는지 알 수 있는 방법은?
 PrintScreen 시스템 키는 TForm의 Keydown 이벤트에서 처리되지 않는ㄷ다.


 다음 예는 Application.OnIdle 이벤트에서 API 함수인 GetAsyncKeyState()를 호출함으로써 PrintScreen 키를 눌렀는지를 테스트하는 것이다.


type
 TForm1 = class(TForm)
   Button1 : TButton;
   procedure formCreate(Sender : TObject);
 private
   {            }
   procedure AppIdle(Sender : TObject; var done : Boolean);
 public
   {            }
end;


var
 Form1 : TForm1;


implementation
{$R &.DFM}


procedure TForm1.FormCreate(Sender : TObject);
begin
 Application.OnIdle := AppIdle;
end;


procedure TForm1.AppIdle(Sender : TObject; var done : Boolean);
begin
 if GetAsyncKeystate(VK_SNAPSHOT) <> 0 then
   Form1.Caption := 'SnapShot');
 done := true;
end;


●다른 응용프로그램에 의해서 시스템 시간이 변경되었는지를 알아내는 방법은?
 다은 예는 WM_TIMECHANGE 메시지를 가져 오는 예제이다.


 시스템 시간이 변경된 응용프로그램은 모든 상위 레벨 윈도우들에게 WM_TIMECHANGE 메시지를 보낸다.


type
 TForm1 = class(TForm1)
 private
   {            }
   procedure WMTIMECHANGE(var Message : TWMTIMECHANGE);
               message WM_TIMECHANGE;
 public
   {            }
end;


var
 Form1 : TForm1;


implementation
{$R *.DFM}


procedure TForm1.WMTIMECHANGE(var Message : TWMTIMECHANGE);
begin
 Form1.Caption := 'Time Changed';
end;


●DLL이 어디에서 실행되었는지 완전한 경로명과 파일 이름을 알아내려면?
 다음 예는 DLL이 로드된 곳은 경로명을 알아내는 DLL 함수에 대한 것이다.


uses Windows;


procedure ShowDllPath stdcall;
var
 TheFileName : array[0..MAX_PATH] of char;
begin
 Fillchar(TheFileName, sizeof(TheFileName), #0);
 GetModulefileName(hInstance, TheFileName, sizeof(TheFileName));
 MessageBox(0, TheFileName, 'The DLL file name is : ', mb_ok);
end;


●주어진 파일에 대한 최근 액세스 시간을 정의하려면?
 다음 예는 주어진 파일이 액세스된 날짜와 시간을 가져 오는 것이다. 모든 파일 시스템들이 최신 액세스 시간을 지원하는 것은 아니다.


procedure TForm1.Button1Click(Sender : TObject);
var
 SearchRec : TSearchRec;
 Success : integer;
 DT : TFileTime;
 ST : TSystemTime;
begin
 Success := SysUtils.FindFirst('C:autoexec.bat', faAnyfile, SearchRec);
 if ((Success = 0) and
   ((TLargeInteger(searchRec.FindData.ftLastAccessTime).LowPart <> 0) or
   ((TLargeInteger(searchRec.FindData.ftLastAccessTime).HighPart <> 0))) then
   begin
    FileTimeToLocalFileTime(SearchRec.FindData.ftLastAccessTime, DT);
    FileTimeToSystemTime(DT, ST);
    Memo1.Lines.Clear;
    Memo1.Lines.Add('AutoExec.bat was last accessed at : ');
    Memo1.Lines.Add('Year := ' + IntToStr(st.wYear));
    Memo1.Lines.Add('Month := ' + IntToStr(st.wMonth));
    Memo1.Lines.Add('DayofWeek := ' + IntToStr(st.wDayOfWeek));
    Memo1.Lines.Add('Day := ' + IntToStr(st.wDay));
    Memo1.Lines.Add('Hour := ' + IntTostr(st.wHour));
    Memo1.Lines.Add('Minute := ' + IntToStr(st.wMinute));
    Memo1.Lines.Add('Second := ' + InttoStr(st.wSecond));
    Memo1.Lines.Add('Milluseconds := ' + IntToStr(st.wMilliseconds));
   end;
   SysUtils.FindClose(SearchRec);
end;


●주어진 프린터가 PostScript 파일에 대해서 인쇄가 가능한지를 알려면?
 다음 예제 코드는 주어진 프린터가 Adobe PostScript 페이지에 대해서 지원하는지를 알아내는 예제이다.


uses Printers;


function IsPostScriptPrinter(dc : hdc) : bool;
var
 TestInt : integer;
 a : array[0..255] of char;
 err : integer;
 s : string;
begin
 Result := false;
 TestInt := GETTECHNOLOGY;
 {$IFEDF WIN32}
 if ExtEscape(Dc, QUERYESCSUPPORT, sizeof(TestInt), @TestInt, 0, Nil) > 0 then
   begin
    Err := ExtEscape(Dc, GETTECHNOLOGY, 0, nil, 256, @a);
 {$ELSE}
 if ExtEscape(Dc, QUERYESCSUPPORT, sizeof(TestInt), @TestInt, 0, Nil) > 0 then
   begin
    Err := ExtEscape(Dc, GetTechnology, 0, nil, @a);
 {$ENDIF}
   if Err > 0 then begin
     s := UpperCase(StrPas(a));
     if Pos('POSTSCRIPT', s) > 0 then
       result := true;
   end;
 end;
end;


procedure TForm1.Button1Click(Sender : TObject);
begin
 if PrintDialog1.Execute then
   if IsPosScriptPinter(Printer.Handle) then
       ShowMessage('This is a Postscript Printer') else
       ShowMessage('This is not a Postscript Printer');
end;


●주어진 윈도우의 종료 버튼을 사용하지 못하게 하려면?
 다음 예는 주어진 윈도우에서 종료 버튼을 사용하지 못하도록 하는 예이다.


peoceudre TForm1.Button1Click(Sender : TObject);
var
 hwndHandle : THANDLE;
 hMenuHandle : HMENU;
begin
 hwndHandle := FindWindow(nil, 'Untitled - notepad');
 if (hwndHandle <> 0) then begin
   hMenuHandle := GetSystemMenu(hwndHandle, False);
   if (hMenuHandle <> 0) then
     DeleteMenu(hMenuHandle, SC_CLOSE, MF_BYCOMMAND);
 end;
end;


●Win95의 시작 버튼을 숨기거나 사용하지 못하게 하려면?
 다음 예는 윈도우 시작 버튼을 숨기거나 나타나게 하고 또한 사용이 가능하거나 불가능하도록 하는 예이다.


procedure TForm1.Button1Click(Sender : TObject);
var
 Rgn : hRgn;
begin
 {Hide the start button}
 Rgn := CreateRectRgn(0, 0, 0, 0);
 SetwindowRgn(FindWindowEx(FindWindow('Shell_TrayWnd', nil), 0, 'Button', nil) ,Rgn
               , true);
end;


procedure TForm1.Button2Click(Sender : TObject);
begin
 {Turn the start button back on}
 SetwindowRgn(FindWindowEx(FindWindow('Shell_TrayWnd', nil), 0, 'Button', nil) ,0
               , true);
end;


procedure TForm1.Button3Click(Sender : TObject);
begin
 {Disable the start button}
 EnableWindow(FindWindowEx(FindWindow('Shell_TrayWnd'), nil), 0, 'Button', nil),
               false );
end;


procedure Tform1.Button4click(Sender : TObject);
begin
 {enable the start button}
 EnableWindow(FindWindowEx(FindWindow('Shell_TrayWnd'), nil), 0, 'Button', nil),
               true );
end;
end.


●VB 함수 중 doEvent 와 동등한 것으로 델파이에서 사용하는 것은?
 Application.ProcessMessages.


●RichEdit 컨트롤에서 Page Brake를 추가하려면?
 불가능하다. Page라는 명령은 RichEdit 컨트롤로부터 제거되는 것이다.


●윈도우 API CallBack 함수인 EnumFontFamilies()를 사용하는 방법은?
 다음 예는 TMemo 컴포넌트에 현재 프린터에 대한 글꼴과 사이즈의 목록들을 추가하는 것이다.


uses Printers;


function EnumFontFamilyProc(var lf : TLogFont;
                               var tm : TNewTextMetric;
                               FontType : integer;
                               var Memo : TMemo) : integer;
{$IFDEF WIN32} stdcall; {$ELSE} ; export; {$ENDIF}
begin
 Memo.Lines.Add(StrPas(@lf.lfFaceName) + #32 + IntToStr(lf.lfHeight));
 result := 1;
end;


function EnumFontFamiliesProc(var lf : TLogFont;
                               var tm : TNewTextMetric;
                               FontType : integer;
                               var Memo : TMemo) : integer;
{$IFDEF WIN32} stdcall; {$ELSE} ; export; {$ENDIF}
begin
 if FontType = TRUETYPE_FONTTYPE then begin
   Memo.Lines.Add(StrPas(@lf.lfFaceName) + #32 + 'All Sizes');
 end else
   EnumFontFamilies(Printer.Handle, @lf.lfFaceName, @EnumFontFamilyProc,
                       LongInt(@Memo));
 result := 1;
end;


procedure TForm1.Button1Click(Sender : TObject);
var
 tm : TTextMetric;
 I : integer;
begin
 if PrintDialog1.Execute then begin
   EnumFontFamilies(Printer.Handle, nil, @EnumFontFamiliesProc, LongInt(@Memo1));
 end;
end;


●'.LNK' 파일을 실행하려면?
 다음 예느 윈도우의 시작 메뉴에서 .lnk 파일을 실행하는 예제이다.


uses ShellApi;


procedure TForm1.Button1Click(Sender : TObject);
begin
 ShellExecute(0,
               nil,
               'C:WINDOWSSTART MEMUDELPHI|Delpgi5.lnk',
               nil,
               nil,
               SW_SHOWNORMAL);
end;


●응용프로그램으로부터 다른 프로그램들을 실행하려면?
 WinExec 함수는 응용프로그램에서 다른 응용프로그램을 실행시키는 가장 쉬운 방법이다. 또는 위의 ‘LNK 파일을 실행하는 방법’ 부분에서 설명한 ShellExecute API 함수를 사용할 수도 있다. 관련된 API 함수의 도움말은 ‘Borland SharedMSHELPWind32.hlp 도움말 파일’을 참고하기 바란다.
 WinExec를 이용하여 일반적인 프로그램을 실행하려면 다음과 같이 한다.


WinExec('C:WINDOWSNOTEPAD.EXE', SW_SHOWNORMAL);
WunExec('C:WINDOWSNOTEPAD.EXE C:WINDOWSWIN.INI',
                                               SW_SHOWNORMAL);


Dos 화면을 보이기 위해서는 ..


WinExec('COMMAND.COM', SW_SHOWNORMAL);


Dos 명령을 수행하기 위해서는 ..


WinExec('COMMAND.COM /C DIR *.*', SW_SHOWNORMAL);


●윈도우 탐색기의 파일 찾기의 다일얼로그 박스를 실행하려면?
 다음 예는 DDE를 사용하여 탐색기의 파일 찾기 다이얼로그를 수행하는 예이다.
이것은 “C:DownLoad" 디렉토리에서 다이얼로그를 연다.


procedure TForm1.Button1click(Sender : TObject);
begin
 with TDDEClientConv.Create(Self) do begin
   ConnectMode := ddeManual;
   ServiceApplication := 'explorer.exe';
   SetLink('Folders', 'AppProperties');
   OpenLink;
   ExecuteMacro('FindFolder(, C:DOWNLOAD)]', False);
   CloseLink;
   Free;
 end;
end;


●ShellAPI 함수인 ExtractIconEX()를 가지고 주어진 파일로부터의 작은 아이콘, 큰 아이콘을 추출하려면?
 ShellAPI 함수인 ExtracIconEx() 는 실행 파일, 동적 링크 라이브러리(DLL) 또는 아이콘 파일에 사용할 수 있다.
 다음은 함수에 대한 정의이다.


Function ExtractIconEx(lpszFile : PAnsiChar;
                       nIconIndex : Integer;
                       phiconLarge : PhIconArray;
                       phiconSmall : PhIconArray;
                       nIcons : UNIT) : UNIT ; stdcall;


다음은 매개변수를 설명할 것이다.


---------------------------------------------------------------------
매개변수        설명
---------------------------------------------------------------------
lpszFile         아이콘을 추출하려는 실행 파일, DLL, 또는 아이콘 파일의 이름을 Null
               종료 문자열로 정의하는 포인터.
nIconIndex      아이콘의 인덱스를 정의한다. 만약 값이 0이라면 함수는 정의된 파일에 대
               해서 첫 번째 아이콘의 핸들을 리턴한다. 값이 -1이라면, 그리고
               phiconLarge 과 phiconSmall 이 모든 nil 이라면 함수는 실행 파일, dll, 또
               는 아이콘 파일에 아이콘의 총 수를 리턴한다. 파일이 실행파일이거나
               DLL이라면 리턴 값은 RT_GROUP_ICON 리소스들의 수이다. 만약 .ICO
               라면 리턴 값은 1이다.
phiconLarge    큰 아이콘에 대한 아이콘 핸들들에 대한 배열 포인터로 이 매개변수는 오
               직 한 개의 아이콘이 추출되면 nil 값을 가질 수 있다.
nIcons          아이콘의 수를 정의한다.
Return Value   리턴 값은 오직 한 개의 아이콘이라면 아이콘에 대한 핸들이다. 그리고 파
               일에서 어떤 아이콘도 찾을 수 없다면 리턴 값은 0이다.
---------------------------------------------------------------------


 다음 예는 ExtractIconEx() 함수를 사용하느 예이다.
 함수의 완전한 사용을 허락하기 위해서 ShellAPI 유닛에 정의된 것과 다르게 함수가 정의된 것을 주의하라.


type ThIconArray = array[0..0] of hIcon;
type PhIconArray = ^ThIconArray;


function ExtracIconExA(lpszFile : PAnsiChar;
                       nIconIndex : Integer;
                       phiconLarge : PhIconArray;
                       phiconSmall : PhIconArray;
                       nIcons : UINT) : UNIT ; stdcall;
   external 'shell32.dll' name 'ExtracIconExA';


function ExtracIconExW(lpszFile : PWideChar;
                       nIconIndex : Integer;
                       phiconLarge : PhIconArray;
                       phiconSmall : PhIconArray;
                       nIcons : UINT) : UNIT ; stdcall;
   external 'shell32.dll' name 'ExtracIconExW';


function ExtractIconEx(lpszFile : PAnsiChar;
                       nIconIndex : integer;
                       phiconLarge : PhIconArray;
                       phiconSmall : PhIconArray;
                       nIcons : UNIT) : UNIT; stdcall;
   external 'shell32.dll' name 'ExtracIconExA';


procedure TForm1.Button1Click(Sender : TObject);
var
 NumIcons : Integer;
 pTheLargeIcons : phIconArray;
 pThrSmallIcons : phIconArray;
 LargeIconWidth : integer;
 SmallIconWidth : integer;
 SmallIconHeight : integer;
 I : integer;
 TheIcon : TIcon;
 TheBitmap : TBitmap;
begin
 NumIcons :=
 ExtractIconEx('C:Program FilesBorlandDelphi 5BINDelphi32.exe', -1, nil, nil, 0);
 if NumIcons > 0 then begin
   LargeIconWidth := GetsystemMetrics(SM_CXICON);
   SmallIconWidth := GetSystemMetrics(SM_CXSMICON);
   SmallIconHeight := GetsystemMetrics(SM_CYSMICON);
   GetMem(pTheLargeIcons, NumIcons * sizeof(hIcon));
   GetMem(pTheSmallIcons, NumIcons * sizeof(hIcon));
   FillChar(pTheLargeIcons^, NumIcons * sizeof(hIcon), #0);
   FillChar(pTheSmallIcons^, NumIcons * sizeof(hIcon), #0);
   ExtractIconEx('C:Program FilesBorlandDelphi 5BINdelphi32.exe',
               0,
               pTheLargeIcons,
               pTheSmallIcons,
               numIcons);
   {$IFOPT R+}
    {$DEFINE CKRANGE}
    {$R-}
   {$ENDIF}
   for I := 0 to (NumIcons - 1) do begin
       DrawIcon(Form1.Canvas.Handle, i*LargeIconWidth, 0, pTheLargeIcons^[i]);
       TheIcon := TIcon.Create;
       TheBitmap := TBitmap.Create;
       TheIcon.Handle := pTheSmallIcons^[i];
       TheBitmap.Width := TheIcon.Width;
       TheBitmap.Height := TheIcon.Height;
       TheBitmap.Canvas.Draw(0,0, TheIcon);
       TheIcon.Free;
       Form1.Canvas.StrectchDraw(Rect(i * SmallIconWidth,
                                       100,
                                       (i + 1) * SmallIconHeight),
                                       TheBitmap);
       TheBitmap.Free);
   end;
   {$IFDEF CKRANGE}
    {$UNDEF CKRANGE}
    {$R+}
   {$ENDIF}
   FreeMem(pTheLargeIcons, NumIcons * sizeof(hIcon));
   FreeMem(pTheSmallIcons, NumIcons * sizeof(hIcon));
 end;
end;


end.


●주어진 Canvas를 지우는 가장 빠른 방법은?
 윈도우 API 함수인 PatBlt()를 사용하면 된다.


procedure TForm1.Button1Click(Sender : TObject);
begin
 PatBlt(Form1.Canvas.Handle, 0 , 0, Form1.ClientWidth, Form1.ClientHeight,
       WHITENESS);
end;


●Win32 아래의 드라이브를 포맷하려면?
 ShellAPI 함수인 shFormatDrive()를 사용할 수 있다.


const SHFMT_DRV_A = 0;
const SHFMT_DRV_B = 1;


const SHFMT_ID_DEFAULT = $FFFF;


const SHFMT_OPT_QUICKFORMAT = 0;
const SHFMT_OPT_FULLFORMAT = 1;
const SHFMT_OPT_SYSONLY = 2;
const SHFMT_ERROR = -1;
const SHFMT_CANCEL = -2;
const SHFMT_NOFORMAT = -3;


function SHFormatDrive(hWnd : HWND;
                       Drive : Word;
                       fmtID : Word;
                       Option : Word) : Longint
   stdcall; external 'Shell32.dll' name 'SHFormatDrive');


procedure TForm1.Button1click(Sender : TObject);
var
 FmtRes : longint;
begin
 try
   FmtRes := ShformatDrive(Handle,
                               SHFMT_DRV_A,
                               SHFMT_ID_DEFAULT,
                               SHFMT_OPT_QUICKFORMAT);
   case FmtRes of
    SHFMT_ERROR : ShowMessage('Error formatting the drive');
    SHFMT_CANCEL :
       ShowMessage('User canceled formatting the drive');
    SHFMT_NOFORMAT : ShowMessage('No Format');
   else
    ShowMessage('Disk has been formatted');
 except
 end;
end;


●Windows Console 응용프로그램을 일반화하려면?
 새로운 응용프로그램을 시작하고, Project Manager를 시작하여 프로젝트의 모든 유닛을 제거한다. 그리고 Project Source 에 다음의 코드를 추가한다.


program Project1;


uses
 Windows;
{$R *.RES}


begin
 Write('A Console Application');
 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
                       FOREGROUND_RED OR BACKGROUND_BLUE);
 Writeln('Red text on a blue background');
 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
                       FOREGROUND_BLUE OR BACKGROUND_RED);
 writeln('Blue text on a red background');
 {write text on black background}
 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
                       FOREGROUND_RED OR
                       FOREGROUND_GREEN OR
                       FOREGROUND_BLUE);
 Writeln('Press Enter To End');
 Readln;
end.


●시스템에서 가능한 드라이브들의 목록을 가져 오는 가장 빠른 방법은?
 다음 예는 시스템에서 가능한 논리적 드라이브들의 리스트를 가져 오는 것이다.


procedure TForm1.Button1Click(Sender : TObject);
var
 ld : DWORD;
 I : integer;
begin
 il := GetLogicalDrives;
 for I := 0 to 25 do begin
   if (ld and (1 shl I)) <> 0 then
       Memo1.Lines.Add(Char(Ord('A') + I) + ':');
 end;
end;


●DeviceCapabilities 를 사용하여 특정 프린터에 대한 모든 빈들의 이름들을 가져 오려면?
 다음 코드를 참조하기 바란다. 델파이에서 새로운 프로젝트를 시작하여 TButton 과 TMemo를 가져다 놓는다. 버튼의 on_click 이벤트에 다음과 같이 코드를 작성한다.


uses
 WinSpool;


const
 pName = 'DELPHI III';
 pPort = '\CONANDELPHI_III';


procedure TForm1.Button1Click(Sender : TObject);
var
 I : Integer;
 p : pChar;
begin
 GetMem(p, 24*DeviceCabilities(pName, PPort, DC_BINNAMES, nil, nil));
 with Memo1.Lines do begin
   Clear;
   for I:= 1 to DeviceCapabilities(pName, PPort, DC_BINNAMES, p, nil) do
       Add(p+24*(i-1));
   end;
   FreeMem(p);
end;


●Win32 아래에서 모뎀의 상태를 가져 오려면?
 다음 예는 Win32 아래에서 모뎀 Control-Register 값들을 가져 오는 것이다.


peocedure TForm1.Button1Click(Sender : TObject);
var
 CommPort : string;
 hCommFile : THandle;
 ModemStart : DWord;
begin
 CommPort := 'COM2';


 {Open the comm port}
 hCommFile := CreateFile(PChar(CommPort),
                       GENERIC_READ,
                       0,
                       nil,
                       OPEN_EXISTING,
                       FILE_ATTRIBUTE_NORMAL,
                       0);
 if hCommFile = INVALID_HANDLE_VALUE then
 begin
   ShowMessage('Unable to open ' + CommPort);
   exit;
 end;


 {Get the Modem Status}
 if GetCommMedemStatus(hCommFile, ModemStart) <> false then begin
   if MedemStat and MS_CTS_ON <> 0 then
       ShowMessage('The CTS (clear-to-send) is on.');
   if ModemStat and MS_DSR_ON <> 0 then
       ShowMessage('The DSR (data-set-ready) is on.');
   if MedemStat and MS_RING_ON <> 0 then
       ShowMessage('The ring indicator is on.');
   if ModemStat and MS_RLSD_ON <> 0 then
       ShowMessage('The RLSD (receive-line-singnal-detect) is on.');
 end;


 {Close the comm port}
 CloseHandle(hCommFile);
end;


●TPrinter 의 GetPrinter() 메소드들로부터 Printer의 드라이버나 포트명을 가져 오려면?
 보통 이들 매개변수들은 빈 문자열을 리턴한다. Windows.ini 파일로부터 할당된 Driver 와 Port를 가져 오기 위해서 윈도우 API 함수인 GetProfileString()을 사용할 수 있다.


uses Printers;


{$IFNDEF WIN32}
 const MAX_PATH = 144;
{$ENDIF}


procedure TForm1.Button1Click(Sender : TObject);
var
 pDevice : pChar;
 pDriver : pChar;
 pPort : pChar;
 hDMode : THandle;
begin
 if PrintDialog1.Execute then begin
   GetMem(pDevice, cchDeviceName);
   GetMem(pDriver, MAX_PATH);
   GetMem(pPort, MAX_PATH);
   Printer.GetPrineter(pDevice, pDevice, '', pDriver, MAX_PATH);
   if lStrLen(pDriver) = 0 then begin
       GetProfileString('Devices', pDevice, '', pDriver, MAX_PATH);
       pDriver[pos(',', pDriver) - 1] := #0;
   end;
   if lStrLen(pPort) = 0 then begin
       GetProfileString('Device', pDevice, '', pPort, MAX_PATH);
       lsStrCpy(pPort, @pPort[lsStrLen(pPort)+2]);
   end;
   Memo1.Lines.Add('Device := ' + StrPas(pDevice));
   Memo1.Lines.Add('Driver := ' + StrPas(pDriver));
   Memo1.Lines.Add('Port := ' + StrPas(pPort));
   FreeMem(pDevice, cchDeviceName);
   FreeMem(pDriver, MAX_PATH);
   FreeMem(pPort, MAX_PATH);
 end;
end;


●Dos 화면이나 모든 Console 응용프로그램을 포함하는 윈도우의 핸들을 가져 오려면?
 다음 예는 Console 모드 응용프로그램의 핸들을 가져 오기 위해서 윈도우 API 함수인 FindWindow()을 사용하는 예이다.
 Console Window의 WndClass 는 윈도우95와 윈도우 NT를 사용하는 경우가 다르고 윈도우의 타이틀도 윈도우 NT에서는 완전한 경로명을 포함한다.


procedure TForm1.Button1Click(Sender : TObject);
var
 info : TOSVersionInfo;
 ClassName : string;
 Title : string;
begin
 {See if we're running on Win95 or NT.}
 info.dwOSVersionInfoSize := sizeof(info);
 GetVersionEx(info);
 if (info.dwPlatformId = VER_PLATFORM_WIN32_NT) then begin
   ClassName := 'ConsoleWindowClass';
   Title := 'MS-DOS Prompt';
 end;
 ShowMessage(IntToStr(FindWindow(PChar(ClassName), PChar(Title))));
end;


●페이지의 인쇄 여백을 얻어 오려면?
 PHYSICALOFFSETX 와 PHYSICALOFFSETY 상수를 전달하는 윈도우 API 함수인 GetDeviceCaps()를 호출한다.


uses Printers;


procedure TForm1.Button1Click(Sender : TObject);
var
 EscapeCode : integer;
 Margin : TPoint;
begin
 if PrintDialog1.Execute then begin
   {$IFDEF WIN32}
   Margin.x := GetDeviceCaps(Printer.Handle, PHYSICALOFFSETX);
   Margin.y := GetDeviceCaps(Printer.Handle, PHYSICALOFFSETY);
   {$ELSE}
   EscapeCode := GETPRINTINGOFFSET;
   if Escape(Printer.Handle,
               QUERYSCSUPPORT,
               sizeof(EscapeCode),
               @EscapeCode, nil) <> 0 then
    if Escape(Printer.Handle,
               QUERYSCSUPPORT,
               0,
               nil, @Margin) < 1 then begin
       EscapeCode := GETPHYSPAGESIZE;
       if Escape(Printer.Handle,
               QUERYSCSUPPORT,
               sizeof(EscapeCode),
               @EscapeCode, nil) <> 0 then
       if Escape(Printer.Handle,
               GETPHYSPAGESIZE,
               0,
               nil, @Margin) > 0 then begin
        Margin.x := (Margin.x - GetDeviceCaps(Pinter.Handle, HorzRes)) div 2;
        Margin.y := (Margin.y - GetDeviceCaps(Pinter.Handle, VertRes)) div 2;
       end else begin
        Margin.x := 0;
        Margin.y := 0;
       end;
     end;
   {$ENDIF}
   Memo1.Lines.Add(IntToStr(Margin.x));
   Memo1.Lines.Add(IntToStr(Margin.y));
 end;
end;


●디스크의 시리얼 숫자를 가져 오려면?
 윈도우 API 함수인 GetVolumnInformation()을 사용한다.


procedure TForm1.Button1Click(Sender : TObject);
var
 VolumnSerialNumber : DWORD;
 MaximunCoponentLength : DWORD;
 FileSystemFlags : DWORD;
 SerialNumber : string;
begin
 GetVolumeInfomation('C:',
                       nil,
                       0,
                       @VolumeSerialNumber,
                       MaxinumComponentLength,
                       FilesystemFlags,
                       nil,
                       0);
 Serialnumber := IntToHex(HiWord(VolumeSerialNumber), 4) + '-' +
                IntToHex(LoWord(VolumeSerialNumber), 4);
 Memo1.Lines.Add(SerialNumber);
end;


●Universal Time에서 시간과 날짜를 얻어 오려면?
 윈도우 API 함수인 GetSystemTime을 사용한다.


procedure TForm1.Button1Click(Sender : TObject);
var
 lt : TSYSTEMTIME;
 st : TSYSTEMTIME;
begin
 GetLocalTime(lt);
 GetSystemTime(st);
 Memo1.Lines.Add('LocalTime = ' +
                       IntToStr(lt.wmonth) + '/' +
                       IntToStr(lt.wDay) + '/' +
                       IntToStr(lt.wYear) + '' +
                       IntToStr(lt.wHour) + ':' +
                       IntToStr(lt.wMinute) + ':' +
                       IntToStr(lt.wSecond));
 Memo1.Lines.Add('UTCTime = ' +
                       IntToStr(st.wmonth) + '/' +
                       IntToStr(st.wDay) + '/' +
                       IntToStr(st.wYear) + '' +
                       IntToStr(st.wHour) + ':' +
                       IntToStr(st.wMinute) + ':' +
                       IntToStr(st.wSecond));
end;


●윈도우로부터 사용자명과 회사 정보를 가져 오려면?
 윈도우의 레지스트리의 “HKEYCURRENT USER" 섹션 아래에 이 정보가 저장되어 있다. TRegIniFile을 사용하여 입력 정보를 가져 온다.


uses Registry;


procedure TForm1.Button1Click(Sender : TObject);
var
 reg : TRegIniFile;
begin
 reg := TRegIniFile.Create('SOFTWAREMICROSOFTMS SETUP(ACME)');
 Memo1.Lines.Add(reg.ReadString('USER INFO', 'DefName', 'Frank Borland'));
 Memo1.Lines.Add(reg.ReadString('USER INFO', 'DefCompany', 'A Valued Borland
                                       Customer'));
 reg.free;
end;


●응용프로그램의 시작 동안 키를 눌렀는지 알려면?
 윈도우 API 함수인 GetKeyState를 사용하여 메인 프로젝트 소스에서 키를 눌렀는지를 체크한다.


program Project1;


uses
 Windows, Forms,
 Unit1 in 'Unit1.pas' {Form1};


{$R *.RES}


begin
 if GetKeyState(vk_F8) < 1 then
   MessageBox(0, 'F8 was pressed during startup', 'MyApp', bm_ok);
 Application.Initialize;
 Application.CreateForm(TForm1, Form1);
 Application.Run;
end.


●설치된 com 포크들의 이름들을 알려면?
 다음은 Win32 레지스트리에 설치된 정보를 가져 오는 예이다.


uses Registry;


procedure TForm1.Button1Click(Sender : TObject);
var
 reg : TRegistry;
 ts : TStrings;
 I : integer;
begin
 reg := TRegistry.Create;
 reg.RootKey := HKEY_LOCAL_MACHINE;
 reg.OpenKey('hardwaredevicemapserialcomm', false);
 ts := TStringList.Create;
 reg.GetValueNames(ts);
 for I := 0 to ts.Count-1 do begin
   Memo1.Lines.Add(reg.ReadString(ts.Strings[i]));
 end;
 ts.Free;
 reg.CloseKey;
 reg.free;
end;


●Win32 아래에서 모뎀을 통해서 전화하는 방법은?
 com 포크에 대한 핸들을 가져 오기 위해서 윈도우 API 함수인 CreateFile()을 사용 할 수 있다. 그리고 주어진 포트를 가지고 통신하기 위해서 표준 파일 I/O를 사용한다.


var
 hCOmmFile : THandle;


procedure TForm1.Button1Click(Sender : TObject);
var
 PhoneNumber : String;
 CommPort : string;
 NumberWritten : LongInt;
begin
 PhoneNumber := 'ATDT 1-555-555-1212' + #13 + #10;
 CommPort := 'COM2';
 {Open the comm port}
 hCommFile := CreateFile(PChar(CommPort),
                       GENERIC_WRITE,
                       0,
                       nil,
                       OPEN_EXISTING,
                       FILE_ATTRIBUTE_NORMAL,
                       0);
 if hCommFile = INVALID_HANDLE_VALUE then
 begin
   ShowMessage('Unable to open '+ CommPort);
   exit;
 end;


 {Dial the phone}
 NumberWritten := 0;
 if WriteFile(hCommfile,
               PChar(PhoneNumber)^,
               Length(PhoneNumber),
               NumberWrutten,
               nil) = false then begin
   ShowMessage('Unable to open '+ CommPort);
 end;


peocedure Tform1.Button2click(Sender : TObject);
begin
 {close the port}
 CloseHandle(hCommFile);
end;


●기본 윈도우 폴더들을 가져 오려면?
 다음 예는 TMemo 컴포넌트에 기본 쉘 폴더들의 완전한 목록을 가져 오는 것이다.


uses Registry;


procedure TForm1.Button1Click(Sender : TObject);
var
 reg : TRegistry;
 ts : TStrings;
 I : integer;
begin
 reg := TRegistry.Create;
 reg.RootKey := HKEY_CURRENT_USER;
 reg.LazyWrite := false;
 reg.OpenKey(
  'SoftwareMicrosoftwindowsCurrentVersionExplorerSell Folders', false);
 ts := TStringList.Create;
 reg.GetValueNames(ts);
 for I := 0 to ts.Count-1 do begin
   Memo1.Lines.Add(ts.Strings[i] + ' = ' +reg.ReadString(ts.Strings[i]));
 end;
 ts.Free;
 reg.CloseKey;
 reg.free;
end;


●현재 디스플레이 모드가 지원하는 색들의 수를 찾는 방법은?
 다음 방법에서 Display context 의 Color Delth를 찾을 수 있다.


GetDeviceCaps(Form1.Canvas.Handle, BITSPIXEL) *
GetDeviceCaps(Form1.Canvas.Handle, PLANES)


픽셀당 사용된 색의 bit 들의 총수를 가져 온다.


1 = 2 colors bpp
4 = 16 colors bpp
8 = 256 colors bpp
15 = 32768 colors(will return 16 on most drivers) bpp
16 = 65535 colors bpp
24 = 16,777,216 colors bpp
32 = 16,777,216 colors (same as 24) bpp


색상들의 총수를 계산하기 위해서 다음을 사용한다.


NumberOfColors := (1 뇌
   (GetDeviceCaps(Form1.Canvas.Handle, BITSPIXEL) *
    GetDeviceCaps(Form1.Canvas.Handle, PLANES));


●문자열의 배경을 투명하게 하려면?
 윈도우 API 함수인 SetBkMode() 함수를 사용한다.


procedure TForm1.Button1Click(Sender : TObject);
var
 OldBkMode : integer;
begin
 with Form1.Canvas do begin
   Brush.Color := ClRed;
   FillRect(Rect(0, 0, 100, 100));
   Brush.Color := ClBlue;
   TextOut(10, 20, 'Not Transparent!');
   OldBkMode := SetBkMode(Handle, TRANSPARENT);
   TextOut(10, 50, 'Transparent!');
   SetBkMode(Handle, OldBkMode);
 end;
end;


●주어진 폴더에서 탐색기 윈도우를 열 수 있나?
 다음 예는 Windows 디렉토리의 내용을 포함한 탐색기 윈도우를 여는 것이다.


uses ShellApi;


procedure TForm1.Button1Click(Sender : TObject);
begin
 ShellExecute(0, 'explore', 'C:WIDOWS', nil, nil, SW_SHOWNORMAL);
end;


●프로그램의 실행에 대한 인스턴스를 한 개만 가능하도록 할 수 있나? 즉, 한 개 이상의 인스턴스를 시작하려면 이전의 인스턴스를 저장하고 Shut Down 시킬 수 있나?
 Win16에서는 HPrevInst를 변수를 시작하기 전에 체크하여 0이 아니면 애플리케이션이 이미 실행중임을 나타내는데, Win32에서는 hPrevInst를 사용할 수 없다. 다음의 예제를 참고하기 바란다.


{The code for OneInstance.dpr}


program OneInstance;


uses
 Windows, Forms,
 Unit1 in 'Unit1.pas' {Form1};


{$R *.RES}
begin
 {Attempt to create a named mutex}
 CreateMutex(nil, false, 'MyApp');
 {if it failed then there is another instance}
 if GetLastError = ERROR_ALREADY_EXISTS then begin
   {Send all windows our custom message - only our other}
   {instance will recognise it, and restore itself}
   SendMessage(HWND_BROADCAST, RegisterWindowMessage('MyApp'), 0 ,0);
   {Lets quit}
   Halt(0);
 end;


 Application.Initialize;
 {Tell Delphi to un-hide it's hidden application window}
 {This allows our instance to have a icon on the task bar}
 Application.ShowMainform := true;
 ShowWindow(Application.Handle, SW_RESTORE);
 Application.CreateForm(TForm1, Form1);
 Application.Run;
end.


{The code for unit1.pas}


unit Unit1;


interface
uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls,
 Forms, Dialogs;


type
 TForm1 = class(TForm)
   procedure FormCreate(Sender : TObject);
   procedure FormDestroy(Sender : TObject);
 private
 {             }
 public
   {            }
 end;


var
 Form1 : Tform1;


implemantation
{$R *.DFM}


var
 OldWindowProc : Pointer; {Variable for the old windows proc}
 MyMsg : DWord; {custom systemwide message}


function NewWindowProc(WindowHandle : hWnd;
                       TheMessage : LongInt;
                       ParamW : LongInt;
                       ParamL : LongInt) : LongInt stdcall;
begin
 if TheMessage = MyMsg then begin
   {Tell the application to restore, let it restore the form}
   SendMessage(Application.handle, WM_SYSCOMMAND, SC_RESTORE, 0);
   SetForegroundWindow(Application.Handle);
   {We handled the message - we are done}
   Result := 0;
   exit;
 end;
 {Call the original winproc}
 Result := CallWindowProc(OldWindowProc, WindowHandle, TheMessage, ParamW,
                               ParamL);
end;


procedure TForm1.FormCreate(Sender : TObject);
begin
 {Register a custom windows message}
 MyMsg := RegisterWindowMessage('MyApp');
 {Set form1's windows proc to ours and remember the old window proc}
 OldWindowProc := Pointer(SetWindowLong(Form1.Handle, GWL_WNDPROC,
                                          LongInt(@NewWindowProc)));
end;


procedure TForm1.FormDestory(Sender : TObject);
begin
 {Set form1's window proc back to it's original procedure}
 SetWindowLong(Form1.Handle, GWL_WNDPROC, LongInt(OldWindowProc));
end;


begin
 {Tell Delphi to hide it's hidden application window for now to avoid}
 {a "flash" on the taskbar if we halt due to another instance}
 ShowWindow(Application.Handle, SW_HIDE);
end.


●응용프로그램에서 Task Switching(Alt-Tab, Ctrl-Esc, Ctrl-Alt-Del)를 막으려면?
 응용프로그램에서 스위칭을 저지하는 것은 Screen Saver가 실행중인 것처럼 하여 윈도우에 속임수를 사용함으로써 가능하다.
 이 방법은 윈도우 NT에서는 불가능하다.
 다음의 코드는 Screen Saver가 실행중인 것처럼 속임수를 쓰는 것이다.


var
 OldValue : LongBool;
begin
 {turns the trap on}
 SystemParametersInfo(97, Word(True), @OldValue, 0);


 {turn the trap off}
 SystemParametersInfo(97, Word(False), @OldValue, 0);
end;


●TPrinter 유닛을 사용하지 않고 델파이에서 인쇄할 수 있나?
 다음 예는 윈도우 API 함수인 PrintDlg()를 사용하는 것으로, 이는 리턴된 dc를 사용하여 프린터를 선택하고 2개페이지를 인쇄하는 것이다.


uses CommDlg;


{$IFDEF WIN32}
const MAX_PATH = 144;
{$ENDIF}


procedure TForm1.Button1Click(Sender : TObject);
var
 pd : TPrintDlg;
 docInfo : TDocInfo;
begin
 FillChar(Pd, sizeof(Pd), #0);
 Pd.lStructSize := sizeof(Pd);
 Pd.hWndOwner := Form1.Handle;
 Pd.Flags := PD_RETURNDC;
 if PrintDlg(pd) then begin
   FillChar(DocInfo, sizeof(DocInfo), #0);
   docInfo.cbSize := Sizeof(DocInfo);
   GetMem(DocInfo.lpszDocName, 32);
   GetMem(DocInfo.lpszOutput, MAX_PATH);
   lStrCpy(DocInfo.lpszDocName, 'My documant');
   {Add this line to print to a file}
   lStrCpy(DocInfo.lpszOutPut, 'C:DownloadTest.doc');
   StartDoc(Pd.hDc, docInfo);
   StartPage(Pd.hDc);
   TextOut(Pd.hDc, 100, 100, 'Page1', 6);
   EndPage(Pd.hDc);
   StartPage(Pd.hDc);
   TextOut(Pd.hDc, 100, 100, 'Page 2', 6);
   EndPage(Pd.hDc);
   EndDoc(Pd.hDc);
   FreeMem(DocInfo.lpszDocName, 32);
   FreeMem(DocInfo.lpszOutput, MAX_PATH);
 end;
end;


●응용프로그램이 Custom Print Driver를 사용한다면, 사용자의 개입 없이 윈도우 3.1이나 윈도우 95에서 프린터 드라이버를 설치하는 것이 가능한가?
 다음 예는 프린터 드라이버를 설치하는 것이다. WindowsSystem 디렉토리에 프린트 드라이버 파일들을 복사하고, Win.ini 파일에 다음 값들을 추가해야 한다.


procedure TForm1.Button1Click(Sender : TObject);
var
 s : array[0..64] of char;
begin
 WriteProfileString('PrinterPorts', 'DriverName', 'DRVFILE,FILE : ,15,45');
 WriteProfileString('Devices', 'DriverName', 'DRVFILE,FILE : ');
 StrCopy(S, 'PrinterPorts');
 SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, LongInt(@S));
 StrCopy(S, 'Devices');
 SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, LongInt(@S));
end;


●프로그램에서 다른 응용프로그램을 종료시키려면?
 WM_QUIT 메시지를 응용프로그램에 보내면 된다.


PostMessage(FindWindow(Nil, 'window caption'), WM_QUIT, 0, 0);


 Window Caption에 메시지를 보낼 윈도우의 Caption이 들어가야 한다.


●Windows Desktop 아이콘들을 Refresh하려면?
 다음 예는 Windows Desktop 아이콘들을 Refresh하는 것이다.


procedure TForm1.Button1Click(Sender : TObject);
begin
 SendMessage(FindWindow('Program', 'Program Manager'), WM_COMMAND, $A065,
                                                                       0);
end;


●폼의 Caption Bar를 없애려면?
 폼의 스타일과 높이를 재설정한다.


procedure TForm1.formCreate(Sender : TObject);
begin
 SetWindowLong(Form1.Handle, GWL_STYLE,
               GetWindowLong(Handle,GWL_STYLE) and not WS_CAPTION);
 Height := ClientHeight;
end;


●응용프로그램에 전달되는 명령 라인으로부터 스페이스를 포함하는 긴 파일 이름을 가져 오려면?
 윈도우 API 함수인 GetCommandLine()은 응용프로그램에 완전한 명령 라인을 제공한다.


procedure TForm1.Button1Click(Sender : TObject);
var
 s : string;
begin
 s := GetCommandLine;
 Delete(s, 1, pos('exe"', s) + 4);
 Memo1.Lines.Add(s);
end;


●Windows의 32bit 버전에서 사용자의 로그인 이름을 가져 오려면?
 윈도우 API 함수인 GetuserName()을 호출함으로써 가능하다.


procedure TForm1.Button1Click(Sender : TObject);
var
 buffer : array[0..255] of char;
 buffSize : DWORD;
begin
 buffSize := sizeof(buffer);
 GetUserName(@buffer, buffSize);
 ShowMessage(buffer);
end;


char 배열을 사용한 메모리는 응용프로그램이 종료될 때 까지 free될 것이다.
이처럼 Long String를 사용할 수 있다.


procedure TForm1.button2Click(Sender : TObject);
var
 buffer : string;
 buffSize : DWORD;
begin
 buffSize := 128;
 SetLength(buffer, BuffSize);
 GetUserName(pChar(buffer), buffSize);
 ShowMessage(buffer);
end;


Long String을 사용한 메모리는 스코프가 끝날 때 해제된다.


●주어진 확장자를 가지는 프로그램들을 가져 오려면?
 다음 예는 파일 확장자를 가진 연결된 파일들 가져 오는 예이다.


uses
{$IFDEF WIN32}
 Registry; {We will get it from the registry}
{$ELSE}
 IniFiles; {We will get it from the win.ini file}
{$ENDIF}


{$IFNDEF WIN32}
 const MAX_PATH = 144;
{$ENDIF}


function GetProgramAssociation(Ext : string) : string;
var
{$IFDEF WIN32}
 reg : TRegistry;
 s : string;
{$ELSE}
 WinIni : TIniFile;
 WinIniFileName : array[0..MAX_PATH] of char;
 s : string;
{$ENFIF}
begin
{$IFDEF WIN32}
 s := '';
 reg := TRegistry.Create;
 reg.RootKey := HKEY_CLASSES_ROOOT;
 if reg.OpenKey('.' + ext + 'shellopencommand', false) <> false then begin
 {The Open command has been found}
   s := reg.ReadString('');
   reg.CloseKey;
 end else begin
   {perhaps thier is a system file pointer}
   if reg.OpenKey('.'+ext, false) <> false then begin
     s := reg.ReadString('');
     reg.CloseKey;
     if s <> '' then begin
       {A system file pointer was found}
       if reg.OpenKey(s + 'shellopencommand', false) <> false then
       {The Open command has been found}
         s := reg.ReadString('');
       reg.CloseKey;
     end;
   end;
 end;
{Delete any command kine, quotes and spaces}
 if Pos('%', s) > 0 then
   Delete(s, Pos('%', s), length(s));
 if ((length(s) > 0) and (s[1] = '"')) then
   Delete(s, 1, 1);
 if ((length(s) > 0) and (s[length(s)] = '"')) then
   Delete(s, Length(s), 1);
 while ((Length(s) > 0) and ((s[length(s)] = #32) or (s[Length(s)] = '"'))) do
   Delete(s, Length(s), 1);
{$ELSE}
 GetWindowsDirectory(WinIniFileName, sizeof(WinInifileName));
 StrCat(WinIniFileName, 'win.ini');
 WinIni := TIniFile.Create(WinIniFileName);
 s := WinIni.ReadString('Extensions', ext, '');
 WinIni.Free;
 {Delete any command line}
 if Pos(' ^', s) > 0 then
   Delete(s, Pos(' ^', s), length(s));
{$ENDIF}
 result := s;
end;


procedure TForm1.Button1click(Sender : TObject);
begin
 ShowMessage(GetProgramAssociation('gif'));
end;


●윈도우가 시작될 때마다 응용프로그램이 시작되도록 하려면?
 다음은 Windows 부트 시퀸스에 응용프로그램을 추가하는 것이다. 다음 코드는 Win32와 Win16 플랫폼에서 모두 가능하다.


uses
 Registry, {For Win32}
 IniFiles; {For Win16}


{$IFNDEF WIN32}
 const MAX_PATH = 144;
{$ENDIF}


{For Win32}
procedure TForm1.Button1Click(Sender : TObject);
var
 reg : TRegistry;
begin
 reg := TRegistry.Create;
 reg.RootKey := HKEY_LOCAL_MACJINE;
 reg.LazyWrite := false;
 reg.OpenKey('SoftwareMicrosoftWindowsCurrentVersionRun', false);
 reg.WriteString('My App', Application.ExeName);
 reg.CloseKey;
 reg.free;
end;


{for Win16}
procedure TForm1.Button2click(Sender : TObject);
var
 WinIni : TIniFile;
 WinIniFileName : array[0..MAX_PATH] of char;
 s : string;
begin
 GetWindowsDirectory(WinIniFileName, sizeof(WininiFileName));
 StrCat(WinIniFileName, 'win.ini');
 WinIni := TIniFile.Create(WinIniFileName);
 s := Winini.ReadString('windows', 'run', '');
 if s = '' then
   s := Application.ExeName else
   s := s + ';'+ Application.ExeName;
 WinIni.WriteString('windows', 'run', s);
 WinIni.Free;
end;

 

 

'Delphi' 카테고리의 다른 글

델파이 API  (0) 2014.02.13
날짜/시간형식 변경 및 강제 시간세팅  (0) 2014.02.13
Q&A 정리  (0) 2014.02.13
Tip 정리  (0) 2014.02.13
올림 / 내림(버림)  (0) 2011.08.03
델파이의 소숫점 반올림 방식  (2) 2011.08.03
Trackback 0 Comment 0
2014. 2. 13. 10:22

Tip 정리

<윈도우 캡션 깜박이게 하기>

//---------------------------------------------------------
BOOL FlashWindow(
   HWND hWnd,   // 폼의 Handle속성을 지정
   BOOL bInvert   // 윈도우즈 95에서는 이 변수값을 무시하며,
   // True로 지정된 경우 타이틀바가 활성/비활성 상태가 토글된다
);
//---------------------------------------------------------

procedure TForm1.FormActivate(Sender: TObject);
begin
   Timer1.Enabled := True;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
   FlashWindow(Form1.Handle, True);
end;

 

<윈도우 디렉토리 알아내기>

//---------------------------------------------------------
UNIT GetWindowDirectory(
   LPTSTR lpBuffer, // 시스템 디렉토리를 저장할 버퍼의 포인터
   UINT uSize          // 디렉토리 버퍼의 크기
);
//----------------------------------------------------------

procedure TForm1.Button1Click(Sender: TObject);
var
   Windir : array[0..30] of char;
begin
   GetWindowsDirectory(Windir,sizeof(windir));
   Label1.Caption := Windir;
end;
 


<비퍼(beeper) ON/OFF 시키기>

//----------------------------------------------------
BOOL SystemParametersInfo(
   UINT uiAction,    // 조회하거나 변경할 시스템 파라미터변수
   UINT uiParam,    // 시스템 파라미터 변수에 따라 지정
   PVOID pvParam, // 시스템 파라미터 변수에 따라 지정
   UINT fWinini        // 시스템 파라미터 변수의 내용이 변경될 경우
                            // 사용자프로파일의 변경여부를 지정
);

BOOL MessageBeep(
   UINT uType
);
//-----------------------------------------------------
procedure TForm1.Button1Click(Sender: TObject);
begin
   SystemParametersInfo(SPI_SETBEEP, 1, Pchar(0), 0); // Beeper ON
   Label1.Caption := 'Beep On';
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
   SystemParametersInfo(SPI_SETBEEP, 0, Pchar(0), 0); //Beeper OFF
   Label1.Caption := 'Beep Off';

end;

procedure TForm1.Button3Click(Sender: TObject);
begin
   MessageBeep(MB_OK);
end;

 

<시스템 가동방법 알아내기>

//----------------------------------------------------
int GetSystemMetrics(
   int nIndex;    // 시스템에서 사용하는 정보에대한 변수값
);
//----------------------------------------------------

procedure TForm1.Button1Click(Sender: TObject);
var
   boot : integer;

begin
   boot := GetSystemMetrics(SM_CLEANBOOT);
   case boot of
      0 : Label1.Caption := 'Normal Boot';
      1 : Label1.Caption := 'Fail-safe Boot';
      2 : Label1.Caption := 'Fail-safe with Network Boot';
   end;
end;

 

<마우스버튼 역할 바꾸기>

//----------------------------------------------------
BOOL SystemParametersInfo(
   UINT uiAction,          // 조회하거나 변경할 시스템 파라미터변수
   UINT uiParam,          // 시스템 파라미터 변수에 따라 지정
   PVOID pvParam,       // 시스템 파라미터 변수에 따라 지정
   UINT fWinini             // 시스템 파라미터 변수의 내용이 변경될 경우
                                 // 사용자 프로파일의 변경여부를 지정
);

BOOL MessageBeep(
   UINT uType
);
//------------------------------------------------------
procedure TForm1.Button1Click(Sender : TObject);
begin
   SystemParametersInfo(SPI_SETMOUSEBUTTONSWAP, 1, PChar(0), 0);
   Label1.Caption := 'Left : Popup Right : Pointing and Execute';
end;

procedure TForm1.Button2Click(Sender : TObject);
begin
   SystemParametersInfo(SPI_SETMOUSEBUTTONSWAP, 0, PChar(0), 0);
   Label1.Caption := 'Left : Pointing and Execute Right : Popup';
end;

 

<스크린세이버 ON/OFF시키기>

//-----------------------------------------------------
BOOL SystemParametersInfo(
   UINT uiAction,     // 조회하거나 변경할 시스템 파라미터변수
   UINT uiParam,     // 시스템 파라미터 변수에 따라 지정
   PVOID pvParam,  // 시스템 파라미터 변수에 따라 지정
   UINT fWinini        // 시스템 파라미터 변수의 내용이 변경될 경우
//사용자프로파일의 변경여부를 지정
);

BOOL MessageBeep(
   UINT uType
);
//------------------------------------------------------

procedure TForm1.Button1Click(Sender : TObject);
begin
   SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 1, PChar(0), 0);
   Label1.Caption := 'SCREEN SAVER ON';
end;

procedure TForm1.Button1Click(Sender : TObject);
begin
   SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 0, PChar(0), 0);
   Label1.Caption := 'SCREEN SAVER OFF';
end;

 

<마우스버튼 개수 알아내기>

//--------------------------------------------------
int GetSystemMetrics(
   int nIndex;    // 시스템에서 사용하는 정보에대한 변수값
);
//--------------------------------------------------

procedure TForm1.Button1Click(Sender: TObject);
var
   ButtonNo : integer;

begin
   ButtonNo := GetSystemMetrics(SM_CMOUSEBUTTONS);
   Label1.Caption := IntToStr(ButtonNo)+'개입니다';
end;

 

<WIN.INI파일에 문자열쓰기>

//----------------------------------------------
BOOL WriteProfileString(
LPCTSTR lpszSection, //Win.ini파일 Section명
LPCTSTR lpszKey, //Section에 출력할 Key명
LPCTSTR lpszString //Key에 할당할 문자열
};

// INI파일의 Section, Key, String의 구성형태
// [Section]
// Key = String;
//-----------------------------------------------

procedure TForm1.Button1Click(Sender : TObject);
begin
   WriteProfileString(Edit1.Text, Edit2.Text, Edit3.Text);
   // Win.ini 파일에 Edit 컴포넌트에 입력된문자열을 출력한다.
end;
 


<WIN.INI파일에서 문자열 읽어오기>

//------------------------------------------------------------
DWORD GetProfileString(
   LPCTSTR lpAppName,        // Win.ini파일 Section명
   LPCTSTR lpKeyName,        // Section에 포함되어 있는 Key명
   LPCTSTR lpDefault,            // 함수에러 발생시 되돌려지는 문자열
   LPCTSTR lpReturnedString, // Key에 할당되어 있는 문자열을 읽어오는 문자열의 버퍼의 포인터
   DWORD nSize                    // 문자열 버퍼의 크기
);
//-------------------------------------------------------------

procedure TForm1.Button1Click(Sender : TObject);
var
   retstr : string;
begin
   GetProfileString(Edit1.Text, Edit2.Text, Edit3.Text, retstr,sizeof(retstr));
   Label1.Caption := retstr;
end;
 


<특정 INI 파일에 문자열 쓰기>

//-----------------------------------------------------
BOOL WritePrivateProfileString(
LPCTSTR lpszSection,   // INI파일 Section명
LPCTSTR lpszKey,         // Section에 출력할 Key명
LPCTSTR lpszString,      // Key에 할당할 문자열
LPCTSTR lpszFile          // 문자열을 출력할 INI파일명으로 확장자까지 입력해야한다.
);
//-----------------------------------------------------
procedure TForm1.Button1Click(Sender : TObject);
begin
   WritePrivateProfileString(Edit1.Text, Edit2.Text, Edit3.Text, Edit4.Text);
   // Edit4에서 지정한 파일에 각 Edit컴포넌트에 입력된 문자열을 출력한다.
   // 출력하고자 하는 파일이 없을 경우 새로 만든다.
end;

 

<특정 INI 파일에서 문자열 읽어오기>

//----------------------------------------------------------
DWORD GetPrivateProfileString(
   LPCTSTR lpAppName,      // 특정 INI파일 Section명
   LPCTSTR lpKeyName,      // Section에 포함되어 있는 Key명
   LPCTSTR lpDefault,          // 함수에러 발생시 되돌려지는 문자열
   LPTSTR lpReturnedString, // Key에 할당되어 있는 문자열을 읽어오는 문자열버퍼의 포인터
   DWORD nSize,                 // 문자열버퍼의 크기
   LPCTSTR lpFileName        // INI파일명으로 확장자까지 입력해야한다.
);
//-----------------------------------------------------------
procedure TForm1.Button1Click(Sender : TObject);
var
   retstr : string;
begin
   GetPrivateProfileString(Edit1.Text, Edit2.Text, Edit3.Text, retstr,sizeof(retstr),Edit4.Text);
   // 특정 INI파일의 지정한 Section 및 Key에 할당된 문자열을 읽어온다.
   // GetPrivateProfileString함수에 지정한 Section이나 Key가 없을 경우
   // Default String을 되돌린다.ㅏ
   Label1.Caption := retstr;
end;

 

<현재 실행중인 OS버전 알아내기>

//-------------------------------------------------------
DWORD GetVersion(VOID)

Platform High order bit Low order byte (major version number)
Windows NT zero 3 or 4
Windows 95 1 4
Win32s with Windows 3.1 1 3
//--------------------------------------------------------
procedure TForm1.Button1Click(Sender : TObject);
var
   Version : LongInt;
begin
   Version := GetVersion;
   Label1.Caption := 'Windows ' + IntToStr(LoByte(LoWord(Version))) + '.' +
   IntToStr(HiByte(LoWord(Version)));
   Label2.Caption := 'DOS ' + IntToStr(HiByte(HiWord(Version))) + '.' +
   IntToStr(LoByte(HiWord(Version)));
end;

 

<윈도우 배경화면 바꾸기>

//----------------------------------------------------
BOOL SystemParametersInfo(
   UINT uiAction,    // system parameter to query or set
   UINT uiParam,    // depends on action to be taken
   PVOID pvParam, // depends on action to be taken
   UINT fWinIni       // user profile update flag
);
//----------------------------------------------------
procedure ChangeBatang;
var
   Reg : TRegIniFile;
begin
   Reg := TRegIniFile.Create('Control Panel');
   Reg.WriteString('desktop','Wallpaper','c:\babo.bmp');
   // 바탕화면으로 c:\babo.bmp를 사용함.
   Reg.WriteString('desktop','TitleWallpaper','1');
   Reg.Free;

   SystemParametersInfo(SPI_SETDESKWALLPAPER, 0,
      nil, SPIF_SENDWININICHANGE);
end;

 

<CPU종류 알아내기>

//-------------------------------------------------------------------
VOID GetSystemInfo(
   LPSYSTEM_INFO lpSystemInfo // address of system information structure
);

// SYSTEM_INFO 구조체 내용 - 자세한 사항은 도움말 참조
typedef struct _SYSTEM_INFO { // sinf
   union {
      DWORD dwOemId;
      struct {
         WORD wProcessorArchitecture;
         WORD wReserved;
      };
   };
   DWORD dwPageSize;
   LPVOID lpMinimumApplicationAddress;
   LPVOID lpMaximumApplicationAddress;
   DWORD dwActiveProcessorMask;
   DWORD dwNumberOfProcessors;
   DWORD dwProcessorType;
   DWORD dwAllocationGranularity;
   WORD wProcessorLevel;
   WORD wProcessorRevision;

} SYSTEM_INFO;
//--------------------------------------------------------------------

procedure TForm1.Button1Click(Sender: TObject);
var
   Sysinfo : TSysteminfo;
begin
   GetSystemInfo(Sysinfo);
   case Sysinfo.dwProcessorType of
      386 : Label1.Caption := 'Intel 386 ';
      486 : Label1.Caption := 'Intel 486 ';
      586 : Label1.Caption := 'Intel Pentium';
      4000 : Label1.Caption := 'MIPS R4000';
      21046 : Label1.Caption := 'Alpha 21046'
   end;
end;

 

<메모리상태 알아내기>

//------------------------------------------------------------
BOOL GetDiskFreeSpace(
LPCTSTR lpRootPathName, // 디스크 루트 패스
LPDWORD lpSectorsPerCluster, // 클러스터당 섹터수
LPDWORD lpBytesPerSector, // 섹터당 바이트수
LPDWORD lpNumberOfFreeClusters, // 사용하지 않은 클러스터수
LPDWORD lpTotalNumberOfClusters // 총 클러스터수
);
//------------------------------------------------------------
procedure TForm1.Button1Click(Sender : TObject);
var
   MemStat : TMemoryStatus;

begin
   MemStat.dwLength := sizeof(TMemoryStatus);
   GlobalMemoryStatus(MemStat);
   with MemStat do
   begin
      Label1.Caption := Format('%d KB',[Trunc(dwTotalPhys/1024)]); //총메모리
      Label2.Caption := Format('%d KB',[Trunc(dwAvailPhys/1024)]); //MemAvailable
      Label3.Caption := Format('%d %%',[trunc(dwAvailPhys/dwTotalPhys*100)]); //사용메모리
      Label4.Caption := Format('%d KB',[Trunc(dwTotalPageFile/1024)]); //SwapFileSetting
      Label5.Caption := Format('%d KB',[Trunc((dwTotalPageFile-dwAvailPageFile)/1024)]);      
      // SwapFileSize
     
      Label6.Caption := Format('%d %%',[100-trunc(dwAvailPageFile/dwTotalPageFile*100)]);      
      // SwapFileUsage
   end;
end;

 

<OEM 코드페이지 알아내기>

//-------------------------------------
UINT GetOEMCP(VOID);
// OEM 코드값 리턴

437 MS-DOS United States
708 Arabic (ASMO 708)
709 Arabic (ASMO 449+, BCON V4)
710 Arabic (Transparent Arabic)
720 Arabic (Transparent ASMO)
737 Greek (formerly 437G)
775 Baltic
850 MS-DOS Multilingual (Latin I)
852 MS-DOS Slavic (LatinII)
855 IBM Cyrillic (primarily Russian)
857 IBM Turkish
860 MS-DOS Portuguese
861 MS-DOS Icelandic
862 Hebrew
863 MS-DOS Canadian-French
864 Arabic
865 MS-DOS Nordic
866 MS-DOS Russian (former USSR)
869 IBM Modern Greek
874 Thai
932 Japan
936 Chinese (PRC, Singapore)
949 Korean
950 Chinese (Taiwan, Hong Kong)
1361 Korean (Johab)
//------------------------------------------
procedure TForm1.Button1Click(Sender : TObject);
var
   ret : integer;
begin
   ret := GetOEMCP;
   case ret of
      437 : Label1.Caption := 'MS_DOS United States(CP 437)';
      // 리턴값은 아래 설명 참조
      // .....
      default : Label1.Caption := 'Etc';
   end;
end;

 

<토글키 상태 알아내기>

//-----------------------------
SHORT GetKeyState(
   int nVirtKey // 가상키 코드
);

// 키값
VK_CAPITAL Caps Lock키
VK_NUMLOCK Num Lock키
VK_SCROLL Scroll Lock키
//------------------------------
procedure TForm1.Button1Click(Sender : TObjcet);
begin
   if GetKeyState(VK_INSERT) = 1 then
      Label1.Caption := 'ON'
   else
      Label1.Caption := 'OFF';
      // Insert 키가 눌려졌으면 1, 아니면 0을 리턴
      // 다른 토글키도 마찬가지
end;

 

<윈도우즈 가동시간 알아내기>

procedure TForm1.Button1Click(Sender : TObject);
var
   hh, mm, ss : integer;
   ret : LongInt;
   buff : string;
begin
   ret := GetTickCount/1000;
   hh := ret/3600;   // 시간계산

   ret := ret -(3600*hh);
   mm := ret/60 //분 계산

   ret := ret - (60*mm);
   ss := ret; //초 계산

   strcpy(buff,IntToStr(hh)+'시간 '+IntToStr(mm)+'분 '+IntToStr(ss'+초');
   Label1.Caption := buff;
end;

 

<날짜정보 리셋하기>

//-----------------------------------------------------------------
BOOL SetSystemTime(

   CONST SYSTEMTIME *lpSystemTime     // address of system time to set
);

// SYSTEMTIME 구조체
typedef struct _SYSTEMTIME {     // st
   WORD wYear;
   WORD wMonth;
   WORD wDayOfWeek;
   WORD wDay;
   WORD wHour;
   WORD wMinute;
   WORD wSecond;
   WORD wMilliseconds;
} SYSTEMTIME;
//------------------------------------------------------------------
procedure TForm1.Button1Click(Sender: TObject);
var
   s_time : TSystemTime;
begin
   s_time.wYear := StrToInt(Edit1.Text);
   s_time.wMonth := StrToInt(Edit2.Text);
   s_time.wDay := StrToInt(Edit3.Text);
   SetSystemTime(s_time);

   Label1.Caption := DateToStr(Now);
end;

 

<윈도우즈 종료시키기>

//----------------------------------------------
BOOL ExitWindowsEx(
   UINT uFlags,                  // shutdown operation
   DWORD dwReserved       // reserved
);
//----------------------------------------------
procedure TForm1.Button1Click(Sender: TObject);
begin
   case RadioGroup1.ItemIndex of
      0 : ExitWindowsEx(EWX_FORCE, 0);           // 강제종료
      1 : ExitWindowsEx(EWX_LOGOFF, 0);         // LOG OFF
      2 : ExitWindowsEx(EWX_POWEROFF,0);     // Shut Down & Turn Off
      3 : ExitWindowsEx(EWX_REBOOT, 0);         // Shut Down & Reboot
      4 : ExitWindowsEx(EWX_SHUTDOWN, 0);    // ShutsDown
   end;
end;

 

<환경변수 알아내기>

//---------------------------------------
LPVOID GetEnvironmentStrings(VOID)
//환경변수에 대한 문자포인터를 리턴
//---------------------------------------
procedure TForm1.Button1Click(Sender: TObject);
var
   Dosenv : Pchar;
   len, i : Integer;
begin
   Dosenv := GetEnvironmentStrings;

   while Dosenv <> '\0' do
   begin
      len := StrLen(Dosenv);
      if (len = 0) then break
      else begin
         Memo1.Lines.Add(Dosenv);
         for i := 0 to len do
         Inc(Dosenv);
      end;
   end;
end;

 

<디스크 볼륨정보 알아내기>

//------------------------------------------------------------------------
BOOL GetVolumeInformation(
   LPCTSTR lpRootPathName,                      // 디스크 루트 패스
   LPTSTR lpVolumeNameBuffer,                  // 볼륨이름에 대한 버퍼 포인터
   DWORD nVolumeNameSize,                     // 볼륨이름 버퍼 크기
   LPDWORD lpVolumeSerialNumber,            // 시리얼 넘버
   LPDWORD lpMaximumComponentLength, // 지정 가능한 파일이름의 최대길이
   LPDWORD lpFileSystemFlags,                  // 파일시스템 플래그
   LPTSTR lpFileSystemNameBuffer,            // 파일시스템 네임버퍼 포인터
   DWORD nFileSystemNameSize                // 파일시스템 네임버퍼 크기
);
//------------------------------------------------------------------------
procedure TForm1.Button1Click(Sender: TObject);
var
   RPName : Pchar;
   VolBuf : Pchar;
   VolSNum : Longint;
   MaxLen : Longint;
   FileFlags : Longint;
   FileNameBuf : Pchar;
begin
   GetVolumeInformation(RPName, VolBuf, sizeof(VolBuf), VolSNum, MaxLen,
      FileFlags, FileNameBuf, sizeof(FileNameBuf));

   Label1.Caption := RPName;
   Label2.Caption := VolBuf;
   Label3.Caption := IntToStr(VolSNum);
   Label4.Caption := IntToStr(MaxLen);

end;

 

<현재 작업디렉토리 알아내기/지정하기>

//------------------------------------------------
DWORD GetCurrentDirectory(
   DWORD nBufferLength,  // 디렉토리 버퍼의 크기
   LPTSTR lpBuffer            // 디렉토리 버퍼에 대한 포인터
);
//-----------------------------------------------
procedure TForm1.Button1Click(Sender: TObject);
var
   CurrDir : array[0..200] of char;
begin
   GetCurrentDirectory(sizeof(CurrDir), CurrDir);
   // 현재 지정된 디렉토리를 알아낸다.
   Label1.Caption := CurrDir;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
   SetCurrentDirectory(Pchar(Edit1.Text));
   // 새로운 디렉토리를 지정한다.
end;

 

<해상도 알아내기>

procedure TForm1.Button1Click(Sender: TObject);
begin
   Label1.Caption := IntToStr(GetSystemMetrics(SM_CXSCREEN)) +
      '*' + IntToStr(GetSystemMetrics(SM_CYSCREEN));
end;

 

<Image의 회전>

 "Here's code to rotate a bitmap 90
 degrees"
 
 From: Dave Shapiro
 
 Counterclockwise, that is. This rotates a 640x480 24-bit bitmap 90 degrees in
 about 2/10 of sec on my P133 (4MB video card, 128MB RAM). It works for
 Delphi 2, and should work for 1 and 3, too.
 
 One thing: This does not work for bitmaps that aren't an integral number of colors
 per pixel. If that's the case, you'll have to do some bit twiddling. I'm working on that
 part right now (I need it too), but it'll be a few days. Anyways, suggestions,
 comments, etc., always welcome.
 
 Special thanks to David Ullrich (ooh, I hope I spelled that correctly) for pointing out
 the non-published-but-public-anyway SaveToStream method for the TBitmap class.
 
 Advance apologies for any formatting problems. Netscape's editor is so ridiculously
 crippled that I can't accomplish anything (give me rtin and vim any day).
 
 
 
 procedure RotateBitmap90Degrees(ABitmap: TBitmap);
 
 const
   BITMAP_HEADER_SIZE = SizeOf(TBitmapFileHeader) +
 SizeOf(TBitmapInfoHeader);
 
 var
   { Things that end in R are for the rotated image. }
   PbmpInfoR: PBitmapInfoHeader;
   bmpBuffer, bmpBufferR: PByte;
   MemoryStream, MemoryStreamR: TMemoryStream;
   PbmpBuffer, PbmpBufferR: PByte;
   PbmpBufferRFirstScanLine, PbmpBufferColumnZero: PByte;
   BytesPerPixel, BytesPerScanLine, BytesPerScanLineR: Integer;
   X, Y, T: Integer;
 
 begin
   {
     Don't *ever* call GetDIBSizes! It screws up your bitmap.
     I'll be posting about that shortly.
   }
 
   MemoryStream := TMemoryStream.Create;
 
   {
    To do: Put in a SetSize, which will eliminate any reallocation
    overhead.
   }
 
   ABitmap.SaveToStream(MemoryStream);
 
   {
    Don't need you anymore. We'll make a new one when the time comes.
   }
   ABitmap.Free;
 
   bmpBuffer := MemoryStream.Memory;
 
   { Set PbmpInfoR to point to the source bitmap's info header. }
   { Boy, these headers are getting annoying. }
   Inc( bmpBuffer, SizeOf(TBitmapFileHeader) );
   PbmpInfoR := PBitmapInfoHeader(bmpBuffer);
 
   { Set bmpBuffer to point to the original bitmap bits. }
   Inc(bmpBuffer, SizeOf(PbmpInfoR^));
   { Set the ColumnZero pointer to point to, uh, column zero. }
   PbmpBufferColumnZero := bmpBuffer;
 
   with PbmpInfoR^ do
   begin
     BytesPerPixel := biBitCount shr 3;
     { ScanLines are DWORD aligned. }
     BytesPerScanLine := ((((biWidth * biBitCount) + 31) div 32) * SizeOf(DWORD));
     BytesPerScanLineR := ((((biHeight * biBitCount) + 31) div 32) * SizeOf(DWORD));
 
     { The TMemoryStream that will hold the rotated bits. }
     MemoryStreamR := TMemoryStream.Create;
     {
      Set size for rotated bitmap. Might be different from source size
      due to DWORD aligning.
     }
     MemoryStreamR.SetSize(BITMAP_HEADER_SIZE  + BytesPerScanLineR * biWidth);
   end;
 
   { Copy the headers from the source bitmap. }
   MemoryStream.Seek(0, soFromBeginning);
   MemoryStreamR.CopyFrom(MemoryStream, BITMAP_HEADER_SIZE);
 
   { Here's the buffer we're going to rotate. }
   bmpBufferR := MemoryStreamR.Memory;
   { Skip the headers, yadda yadda yadda... }
   Inc(bmpBufferR, BITMAP_HEADER_SIZE);
 
   {
    Set up PbmpBufferRFirstScanLine and advance it to end of the first scan
    line of bmpBufferR.
   }
   PbmpBufferRFirstScanLine := bmpBufferR;
   Inc(PbmpBufferRFirstScanLine, (PbmpInfoR^.biHeight - 1) * BytesPerPixel);
 
   { Here's the meat. Loop through the pixels and rotate appropriately. }
 
   { Remember that DIBs have their origins opposite from DDBs. }
   for Y := 1 to PbmpInfoR^.biHeight do
   begin
     PbmpBuffer := PbmpBufferColumnZero;
     PbmpBufferR := PbmpBufferRFirstScanLine;
 
     for X := 1 to PbmpInfoR^.biWidth do
     begin
       for T := 1 to BytesPerPixel do
       begin
         PbmpBufferR^ := PbmpBuffer^;
         Inc(PbmpBufferR);
         Inc(PbmpBuffer);
  end;
       Dec(PbmpBufferR, BytesPerPixel);
       Inc(PbmpBufferR, BytesPerScanLineR);
     end;
 
     Inc(PbmpBufferColumnZero, BytesPerScanLine);
     Dec(PbmpBufferRFirstScanLine, BytesPerPixel);
   end;
 
   { Done with the source bits. }
   MemoryStream.Free;
 
   { Now set PbmpInfoR to point to the rotated bitmap's info header. }
   PbmpBufferR := MemoryStreamR.Memory;
   Inc( PbmpBufferR, SizeOf(TBitmapFileHeader) );
   PbmpInfoR := PBitmapInfoHeader(PbmpBufferR);
 
   { Swap the width and height of the rotated bitmap's info header. }
   with PbmpInfoR^ do
   begin
     T := biHeight;
     biHeight := biWidth;
     biWidth := T;
   end;
 
   ABitmap := TBitmap.Create;
 
   { Spin back to the very beginning. }
   MemoryStreamR.Seek(0, soFromBeginning);
   ABitmap.LoadFromStream(MemoryStreamR);
 
   MemoryStreamR.Free;
 end;
 


<조합형 완성형 체크 프로시져>

Function isKs(buf : PChar) : Integer;
var
 Hangul_Code, ks_count, kssm_count : Integer;
 First,Second : Char;
 ptr,ptr2 : PChar;
begin
 ks_count := 0;
 kssm_count := 0;
 ptr := buf;
 ptr2 := buf;
 while ptr^ <> #0 do
 begin
  first := ptr^;
  INC(ptr,1);
  IF (Ord(first) < $80) then Continue;
  second := ptr^;
  if (ptr - ptr2 > 20480) then break;
  hangul_code := (Ord(First) * 256) + Ord(second);
        //  완성형의 특수문자 코드 검사
  if( ( ((hangul_code > $a1a1) And (hangul_code < $a1ff)) OR
        ((hangul_code > $a2a0) And (hangul_code < $a2e6)) OR
        ((hangul_code > $a3a0) And (hangul_code < $a3ff)) OR
        ((hangul_code > $a4a0) And (hangul_code < $a4ff)) OR
        ((hangul_code > $a5a0) And (hangul_code < $a5f9)) OR
        ((hangul_code > $a6a0) And (hangul_code < $a6e5)) OR
        ((hangul_code > $a7a0) And (hangul_code < $a7f0)) OR
        ((hangul_code > $a8a0) And (hangul_code < $a8ff)) OR
        ((hangul_code > $a9a0) And (hangul_code < $a9ff)) OR
        ((hangul_code > $aaa0) And (hangul_code < $aaf4)) OR
        ((hangul_code > $aba0) And (hangul_code < $abf7)) OR
        ((hangul_code > $aca0) And (hangul_code < $acc2)) OR
        ((hangul_code > $acd0) And (hangul_code < $acf2)) OR
        //  1998.2.21 새로 추가(Cherie)
        (hangul_code = $aec2) OR
        //  완성형 한글코드 검사
        Check_HanRange( hangul_code, $b0a0, $b0ff, 16 ) OR
        Check_HanRange( hangul_code, $c0a0, $c0ff, 9  ) OR
        //  완성형 한자코드 검사
        Check_HanRange( hangul_code, $caa0, $caff, 6  ) OR
        Check_HanRange( hangul_code, $d0a0, $d0ff, 16 ) OR
        Check_HanRange( hangul_code, $e0a0, $e0ff, 16 ) OR
        Check_HanRange( hangul_code, $f0a0, $f0ff, 14 ) ) AND
        //  1998.2.23 새로 추가(Cherie)
        //  조합형 일어의 경우 완성형과 동일한 부분이 있는데,
        //  완성형에서는 거의 사용되지 않는 문자이므로,
        //  아래 코드가 있을경우 무조건 조합형으로 인식
        //  만일 조합형 일어 코드가 아니라면...
      ( NOT (( (hangul_code >= $d000) And (hangul_code <= $d3ff) ) OR
          ( (hangul_code >= $dda1) And (hangul_code <= $de98 )) OR
          ( (hangul_code >= $dba1) And (hangul_code <= $dbc8 )) OR
        //  1998.2.27 새로 추가(Cherie)
        //  조합형 선문자일경우도 무조건 조합형으로 인식
        //  만일 조합형 선문자 코드가 아니라면...
          ( (hangul_code >= $d9b0) And (hangul_code <= $d9cf) ) OR
          ( (hangul_code >= $d4b0) And (hangul_code <= $d4cf) ) ) ) ) then
    begin
      INC(ks_count);
      if ks_count >= KS5061_VERIFY_COUNT then
        break;
    end
    else
    begin
      INC(kssm_count);
      if kssm_count >= KS5061_VERIFY_COUNT then
        break;
    end;
    INC(ptr)
  end;
  //  대부분 조합형보다는 완성형 글이 많으므로 카운트 값이
  //  같을 경우 완성형으로 처리하도록 한다.
  if( ks_count >= kssm_count ) then
    isKS := 0
  else
    isKS := 1;
end;
 


<caption에 여러줄 쓰기>

기존에 caption이 여러줄 올 수가 없었습니다.

다음은 caption에 여러줄을 쓰는 간단한 팁입니다.

 unit Newbtn;

 interface

 uses
    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
    stdCtrls;

 type
    TNewButton = class(TButton)

 private
 { Private declarations }
 public
 { Public declarations }
    procedure createParams(var Params: TCreatParams); override
    {생성된 윈도의 형태를 결정하는 메소드를 겹지정합니다.}
 end;

 procedure Register;

 implementation

 {$R *.DFM}

 procedure TNewButton.CreateParams(var Params: TCreatParams);
 begin
    inheritde CreateParams(Params);
    //상위 클래스의 메소드를 먼저 호출한 뒤
    Params.Style := Params.style or BS_TILINE;
    //스타일 형태를 multi-line(다중 라인)으로 설정한다.
 end;

 procedure Register;
 begin
    RegisterComponents('sample',[TNewButton]);
 end;

 end.

 

<파일 다루기>

  파일의 종류를 보면 텍스트 파일과 바이너리 파일이 있다.

 델파이에서는 텍스트 파일은 아주 간단히 액세스가 가능하며, 바이너리 파일도 역시 간단히 액세스를 할 수 있다. 텍스트 파일은 아주 간단하여 초보자도 쉽게 읽고 쓸수 있다는 장점이 있다.

 델파이에서 바이너리 파일은 Typed 파일로 정수나 실수 그리고 레코드 등을 파일로 저장할 수 있도록 한다. 첫 강좌는 파일을 다루는 기본적인 함수와 텍스트 파일을 다루는 방법에 대하여 알아본다.

 1. 파일 변수 선언

 파일 변수란 파일을 제어하기 위한 디스크의 실제적인 파일을 가리키는 변수이며 흔히 파일 핸들이라고 한다. 파일 변수란 복잡한 구성 요소들을 대표하는 변수이며 디스크의 파일과 일단 한 번만 연결해 주면 파일 변수를 통해 간단하게 파일 입출력을 할 수 있다.

 텍스트 파일 타입

 Var
    FH: TextFile;

 FH는 텍스트 파일의 파일 핸들 변수이다.

 

 2. 파일과 핸들 연결

 파일과 핸들을 대응하는 작업은 파일 핸들이 어떤 파일을 가리키는가를 지정해 주는 작업이며 다음의 함수를 사용한다.

 AssignFile(파일핸들, 파일명);

 예: AssignFile(FH, 'C:\autoexec.bat');

 

 3. 파일의 오픈

 파일을 오픈한다는 것은 파일 입출력을 위한 준비 과정이라 하겠다. 파일을 입출력하기 위해서는 파일에서 읽은 내용을 저장할 메모리가 필요하며 또한 파일을 어디쯤 읽고 있는가, 어떤 형태의 파일인가 등의 정보를 기억할 여러가지 내부적인 변수들이 필요하고 에러 처리를 위한 준비가 필요하다. 이런 일체의 작업을 통틀어 파일 오픈이라 한다.

 

 3-1. Rewrite(FileHandle)

 파일로 데이타를 출력하기 위한 파일 오픈 함수이다. 만약 파일이 디스크 상에 없으면 파일을 직접 만들고 파일이 있으면 기존 파일을 삭제한 후 다시 만든다.

 3-2. Reset(FileHandle)

 파일로부터 데이타를 입력하기 위한 파일 오픈 함수이다. 읽기 위해서 오픈한 것이므로 데이터를 출력할 수는 없다. 파일이 디스크상에 존재하지 않으면 에러가 발생한다.

 3-3. Append(FileHandle)

 디스크상의 기존에 있는 파일에 데이터를 추가로 출력하기 위한 파일 오픈 함수이다.

 

 4. 파일 입출력

 파일로부터 데이타를 읽거나 쓸 때 필요한 과정이다.

 ReadLn(FileHandle, Variant);
 WriteLn(FileHandle, Value);

 위의 두 함수가 실제로 텍스트 파일을 읽고 쓰는데 많이 쓰이는 함수이다.

 

 5. 파일 닫기

 입출력을 위하여 파일을 열었으면 원래대로 닫아주어야 한다. 파일을 닫는다는 말은 메모리에서 파일에서 사용된 내용을 제거한다는 것이다.

 CloseFile(FileHandle)

 입출력이 끝난 후에 파일을 닫는 것은 무척 중요한 일이면서도 실수로 빼먹고 안하는 경우가 많은데

 반드시 해 주어야 한다. 그렇지 않으면 말짱하던 파일이 사라진다거나 깨지거나 할 가능성이 있다. 위의 다섯가지 순으로 파일로 작업을 한다.

 

 6. 파일 쓰기

 이제 위의 다섯 가지를 사용하여 파일 쓰기를 하도록 하자.

 Var
    FH: TextFile;

 Begin
    AssignFile(FH, 'C:\DSPF.txt');
    Rewrite(FH);
    WriteLn(FH, '델프동 만세');
    WriteLn(FH, '볼랜드 사용자 그룹 = 델프동');
    CloseFile(FH);
 End;

 FH가 파일 핸들 변수이다 'c:\dspf.txt'파일을 파일 핸들 변수에 할당하고 쓰기 모드로 오픈하였다. WriteLn을 사용하여 파일로 한 라인 출력을 하였다. 마지막으로 파일을 닫는 CloseFile함수가 사용되었다.

 온라인 도움말을 이용하여 WriteLn에 대하여 더 자세히 살펴보기를 바란다.

 

 7. 파일 읽기

 파일로부터 데이터를 읽어 보자. dspf.txt에 저장된 데이터를 읽어 보자.

 Var
    FH: TextFile;
    MyStr: String;

 Begin
    AssignFile(FH, 'c:\dspf.txt');
    Reset(FH);
    While Not Eof(FH) Do Begin
    ReadLn(FH, MyStr);
    ShowMessage(MyStr);
 End;

 CloseFile(FH);

 End;

 파일에서 읽은 데이터를 우리는 스트링 변수에 저장한다. Reset함수는 읽기 모드 오픈이다. Eof(FH)함수는 파일의 끝이다인지를나타낸다. ReadLn을 통하여 MyStr변수에 데이타를 읽어들이고 ShowMessage함수로 화면에 디스플레이하여 주는 것이 파일의 끝일 때까지 반복된다. 마지막에는 CloseFile함수로 파일을 닫는다.

 

 8. 파일 추가

 파일에 데이터를 쓰기에서 발전된 것으로 보면 되겠다... 파일에 데이타가 존재할 때 어떻게 하면 그 파일에 내용을 더할 수 있을까? 그것은 Rewrite대신에 Append함수로 수행할 수 있다.

=======================================================

 델파이는 모든 변수들을 파일로 저장할 수 있도록 하는 기능을 제공하는데 바로 이것이 Typed File이다. 파일로 저장될 때 개별 데이타의 데이터형을 가진다는 것으로 해석하면 될 것이다.

 우선 정수값을 저장하는 파일

 Typed File을 사용하는 방법은 텍스트 파일을 사용하는 방법과 거의 동일하다. 단 타입드 파일 변수를 선언하는 형식적인 차이가 있다.

 선언은

 Var
    TFH: File Of Integer;

 Integer와 같이 어떤 Type이 오는 파일인 Typed File을 선언하는 방법이다.

 

 자 이제 정수형 타입의 파일을 액세스 하자.

 Var
    FH: File Of Integer;
    i : Integer;

 Begin
    AssignFile(FH, 'c:intfile.txt');
    Rewrite(FH);
    For i := 1 To 1000 Do
    Write(FH, i);
    CloseFile(FH);
 End;

 레코드형 Typed File

 위의 예는 단순히 Typed File의 구현은 이렇게 할 수도 있다는 것을 보여주는 예가 되겠다.

 그럼, 레코드를 단위로 파일에 읽고 쓰는 방법에 대하여 알아보자.

 Type
    TMyRec = Record
    Name : String[20];
    Age : Integer;
    Male : Boolean;
 End;

 위의 레코드 선언은 신상의 예가 되는 3개의 필드만을 레코드의 멤버로 선언하였다.

 이런 방법으로 주소록이나 전화번호부, 고객 관리등을 작성한다면 유용하게 쓰일 수 있다.

 아래에서 예를 들어 쉽게 설명하도록 하겠다.

 Var
    MyRec: Array[1..100] Of TMyRec;
    FH: File Of TMyRec;
    i: Integer;

 Begin
    AssignFile(FH, 'c:\recfile.txt');
    Rewrite(FH);
    For i := 1 To 100 Do
       Write(Fh, MyRec[i]);
    CloseFile(FH);
 End;

 TMyRec형의 배열 MyRec을 크기 100으로 선언하고 MyRec 전체를 c:\recfile.txt로 출력한다.

 물론 위의 코드는 출력 예만 보이기 위하여 만든 것이기에 MyRec에는 전혀 쓸모없는 값이 들어 있을 것이다.

 MyRec에 값을 대입해 준 후 파일로 출력하면 레코드 전체가 파일로 저장되며 이 정보는 Read함수를 사용하여 읽어 들일 수 있다.

 

 Random Access

 Typed File에서는 Random Access가 가능하다. 이는 순차 접근(Sequential Access)의 반대의 개념으로 파일에 있는 데이터 중 특정 위치의 데이터를 언제든지 읽을 수 있다.

 파일 입출력은 항상 현재의 위치를 기준으로 수행되며 레코드 하나를 읽으면 현재 위치가 레코드의 길이만큼 증가하여 다음 레코드를 읽을준비를 한다. 현재 위치를 변경하려면 Seek함수를 사용하며 인수로 파일 핸들과 몇번째 레코드를 읽을 것인지 알려주면 된다.

 10번째 레코드를 읽고자 할 때 다음과 같다.

 Seek(FH, 10);
 Read(FH, MyRec[10]);

 파일의 현재 위치를 구하려면 FilePos(FH)함수를 사용하여 파일의 총크기를 구하려면 FileSize(FH)함수를 사용하면 된다.

 

<한, 영 전환하기>

 // 'uses' Clause 에 'Imm' 을 추가함.
 unit Unit1;

 interface

 uses
    Windows,Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Imm, StdCtrls;

 type
    TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    Label1: TLabel;

 procedure Button1Click(Sender: TObject);
 procedure FormCreate(Sender: TObject);

 private
 { Private declarations }

 public
 { Public declarations }

 procedure ConvK_Emode;
 function GetK_Mode: Boolean;

 end;

 var
    Form1: TForm1;

 implementation

 {$R *.DFM}

 var
    K_Emode : HIMC;
    procedure TForm1.ConvK_Emode;     {한/영 모드 전환 }

begin
    K_Emode := ImmGetContext(handle);

    if GetK_Mode then        {한글모드이면 영문모드로}
       ImmSetConversionStatus(K_Emode, IME_CMODE_ALPHANUMERIC,          IME_CMODE_ALPHANUMERIC)

    else       {영문모드이면 한글모드로}
       ImmSetConversionStatus(K_Emode, IME_CMODE_HANGEUL, IME_CMODE_HANGEUL);

 end;

 function TForm1.GetK_Mode: Boolean;     {한/영 모드 얻기}

var
    Conversion, S: DWORD;

 begin
    K_Emode := ImmGetContext(handle);
    ImmGetConversionStatus(K_Emode, Conversion, S);

    if Conversion = IME_CMODE_HANGEUL then
       GetK_Mode := True
    else
       GetK_Mode := False;

 end;

 procedure TForm1.Button1Click(Sender: TObject);

 begin
    ConvK_Emode;

    if GetK_Mode then Label1.Caption := '한글'
    else Label1.Caption := '영문';
 end;

 procedure TForm1.FormCreate(Sender: TObject);

 begin
    if GetK_Mode then Label1.Caption := '한글'
    else Label1.Caption := '영문';
 end;

 end.

 

<키보드의 임의키 발생>

 아래 예제가 있습니다.

 사용법은 Memo1 에 임의의 문장을 작성한 후 E_VirtualKey 콤포넌트에 문자열" BACK"이라고 입력한 후 SpeedButton1 을 누르시면 한 글자씩 지워집니다.

 다른 키의 조합도 사용해 보세요.

 unit Unit1;

 interface

 uses
    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
    Buttons, StdCtrls;

 type
    TForm1 = class(TForm)
    SpeedButton1: TSpeedButton;
    Memo1: TMemo;
    E_VirtualKey: TEdit;
    procedure SpeedButton1Click(Sender: TObject);
  
 private
 { Private declarations }
 public
 { Public declarations }
 end;

 var
    Form1: TForm1;

 implementation {$R *.DFM}

 procedure SimulateKeystroke(VirtualKey: byte; ScanCode: DWORD);
 begin

    // keybd_event 함수를 사용한 키 조합(down, up) 발생
    keybd_event(VirtualKey,     // 키의 down
       ScanCode,  0,  0);

    keybd_event(VirtualKey,     // 키의 up
       ScanCode, KEYEVENTF_KEYUP, 0);

 end;

 procedure SimulateKeyDown(Key : byte);
 begin
    // keybd_event 함수를 사용한 키 down 발생
    keybd_event(Key, 0, 0, 0);
 end;

 procedure SimulateKeyUp(Key : byte);
 begin
    // keybd_event 함수를 사용한 키 up 발생
    keybd_event(Key, 0, KEYEVENTF_KEYUP, 0);
 end;

 procedure TForm1.SpeedButton1Click(Sender: TObject);
 var
    hs: String;
    w : word;

 begin
    Memo1.SetFocus;
    hs := UpperCase(E_VirtualKey.Text);

    if pos('INS',hs)> 0 then SimulateKeystroke(VK_INSERT, 0) else
    if pos('DEL',hs)> 0 then SimulateKeystroke(VK_DELETE, 0) else
    if pos('RT',hs)> 0 then SimulateKeystroke(VK_RETURN, 0) else
    if pos('TAB',hs)> 0 then SimulateKeystroke(VK_TAB, 0) else
    if pos('ESC',hs)> 0 then SimulateKeystroke(VK_ESCAPE, 0) else
    if pos('BACK',hs)> 0 then SimulateKeystroke(VK_BACK, 0) else
    if pos('UP',hs)> 0 then SimulateKeystroke(VK_UP, 0) else
    if pos('DOWN',hs)> 0 then SimulateKeystroke(VK_DOWN, 0) else
    if pos('LEFT',hs)> 0 then SimulateKeystroke(VK_LEFT, 0) else
    if pos('RIGHT',hs)> 0 then SimulateKeystroke(VK_RIGHT, 0) else
    if pos('PGDN',hs)> 0 then SimulateKeystroke(VK_NEXT, 0) else
    if pos('PGUP',hs)> 0 then SimulateKeystroke(VK_PRIOR, 0) else
    if pos('END',hs)> 0 then SimulateKeystroke(VK_END, 0) else
    if pos('HOME',hs)> 0 then SimulateKeystroke(VK_HOME, 0);
    { ... 이하 가상키의 조합을 발생시킬 수 있습니다}

     // 그리고 위의 SimulateKeyDown, SimulateKeyUp 를 사용하여 Shift, Ctrl, Alt 등은
     // down 상태를 유지하고(SimulateKeyDown), 이를 해제(SimulateKeyUp)할 수 있습니다
     // 또한 일반 문자의 ScanCode는 VkKeyScan() 함수로 알 수 있습니다

 end;

 end.

 

<스크린 해상도 변경>

해상도 변경을 위하여 TDevMode 개체를 사용합니다...

 var
    DevMode : TDevMode;

 를 선언하시고...

 구현부에서는 아래와 같죠...

 With DevMode Do Begin
    dmSize := SizeOf(TDevMode);
    dmPelsWidth := 800;
    dmPelsHeight := 600;
    dmFields := DM_PELSWIDTH Or DM_PELSHEIGHT;
 End;

 스크린 해상도의 변경은 좀 신중을 기해야 겠죠...

 

<DELPHI에서 STRING 가지고 놀기>

String Type 의 변수를 가지고 할 수 있는 일 !

 1. Concat (문자열을 합쳐 준다)

    function Concat(str1, str2: String);string;
       str1 = 첫 번째 문자열
       str2 = 두 번째 문자열

 var
    str : String;

 begin
    str := '멍멍이';
    str := concat(str, '강아지');

 실행 결과 : 멍멍이강아지

 //---------------------
 str := '멍멍이;
 str := str + '강아지';
// -----------------------

 위의 문장과 다를게 없다.

 

 2. Copy (원하는 만큼의 문자열을 RETURN 해 준다)

 function Copy(str: String, Index, Counter: integer);string;
    Index = 시작 위치
    Counter = 시작위치부터의 리턴할 문자열까지의 카운터

 var
    str : String;

 begin
    str := '송아지 망아지';
    str := Copy(str, 1, 6);

 실행 결과 : 송아지

 

 3. Insert (원하는 위치의 문자열을 삽입 시킨다)

 procedure Insert(Source: string; var S: string; Index: Integer);
    Source = 원본 문자열
    S = 삽입시킬 문자열
    index = 삽입시킬 위치

 var
    str: string;

 begin
    str := '강지';
    Insert('아', str, 2);
 end;

 실행 결과 : 강아지

 

 4. Delete (원하는 위치의 문자열을 삭제 한다)

 procedure Delete(var S: string; Index, Count:Integer);
    S = 소스 문자열
    index = 삭제를 시작할 위치
    Count = 시작위치부터의 지울위치까지의 카운터

 var
    s: string;

 begin
    s := '강앙아지';
    Delete(s,3, 2);
 end;

 실행 결과 : 강아지

 

 5. Length (문자열의 길이를 반환 해 준다)

 function Length(S: string): Integer;

    s = 소스 문자열

 var
    s : String
    Len : integer;

 begin
    s := '강아지';
    Len := Length('강아지');

 실행 결과 : 6

 

 6. Pos (찾고자 하는 문자열의 위치를 반환하여 준다)

 Pos(Substr: string; S: string): Integer;
    Substr = 찾고자 하는 문자열
    S = 원본 문자열

 var
    str : String;
    sub : String;
    Position : integer;

 begin
    str := '송아지';
    Position := Pos('아', S);
 end;

 실행 결과 : 3

 

<Tray에 아이콘 넣기>

Win95의 오른쪽 귀퉁이에는 스피커의 볼륨조절과 같은 작은 아이콘들이 있습니다.. 자신의 프로그램을 그곳으로 밀어넣는 방법입니다..

 먼저 트레이에서 발생하는 메세지를 받아야 하므로 메세지를 정해야 합니다. 다음줄을 {$R *.DFM} 아랫줄에 넣어주세요.

 물론 그 한참 위에 넣어도 되지만 다른 유닛에서 쓸게 아니니 아랫쪽에 넣는게 좋죠.

    const MY_SHOWFORM_ID = WM_USER+1;

 이제 넣는 부분입니다. 다음의 코드를 FormCreate에 넣어줍니다.

 

 procedure TfmTrayMain.FormCreate(Sender: TObject);
 var
    iconData : TNotifyIconData;

 begin
    // 폼을 트레이에 넣어준다.
    ShowWindow (Application.Handle, SW_HIDE);
    // 폼이 안 보임
    Application.ShowMainForm:= False;
    with IconData do
    begin
       cbSize := SizeOf ( IconData );
       // 델파이에서는 Wnd로 바뀌었음
       Wnd := Handle;
       uID := 100;
       uFlags := NIF_MESSAGE + NIF_ICON + NIF_TIP;
       uCallbackMessage := WM_USER + 1;
       hIcon := Application.Icon.Handle;
       StrPCopy(szTip, Application.Title);
    end;

    Shell_NotifyIcon( NIM_ADD, @IconData );
 end;

 

 넣기만 하면 안되겠죠.. 마우스로 클릭하면 다시 화면에 표시가 되어야 죽이든지 바꾸든지 할테니까요.. 다음과 같이 다시 살릴 수 있습니다.

 

 // 메세지 프로시져
 procedure TfmTrayMain.WndProc;
 begin
    case Message.Msg of
       MY_SHOWFORM_ID:
    case Message.lParam of
       WM_LBUTTONDBLCLK: Self.Show;
 end;

 end;

 inherited;
 end;

 

 WndProc는 구지 설명할 필요는 없을테구, 모르시는 분을 위해 선언부까지 얹어드립니다.

    procedure WndProc ( var Message : TMessage ); override;

 

<다른 프로그램실행 시킨후 Wait하기>

How do I execute a program and have my code wait until it is finished?

 //-------A: Here is the 16 bit version:

 uses Wintypes,WinProcs,Toolhelp,Classes,Forms;

 Function WinExecAndWait(Path : string; Visibility : word) : word;
 var
    InstanceID : THandle;
    PathLen : integer;

 begin
    { inplace conversion of a String to a PChar }
    PathLen := Length(Path);
    Move(Path[1],Path[0],PathLen);
    Path[PathLen] := #00;
    { Try to run the application }
    InstanceID := WinExec(@Path,Visibility);
    if InstanceID< 32 then    { a value less than 32 indicates an Exec error }
    WinExecAndWait := InstanceID

 else begin
    Repeat
       Application.ProcessMessages;
    until Application.Terminated or (GetModuleUsage(InstanceID) = 0);

    WinExecAndWait := 32;
 end;

 end;


 //--------- Here is the 32 bit version:

 function WinExecAndWait32(FileName:String; Visibility : integer):integer;
 var
    zAppName:array[0..512] of char;
    zCurDir:array[0..255] of char;
    WorkDir:String;
    StartupInfo:TStartupInfo;
    ProcessInfo:TProcessInformation;

 begin
    StrPCopy(zAppName,FileName);
    GetDir(0,WorkDir);
    StrPCopy(zCurDir,WorkDir);
    FillChar(StartupInfo,Sizeof(StartupInfo),#0);
    StartupInfo.cb := Sizeof(StartupInfo);
 
    StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
    StartupInfo.wShowWindow := Visibility;
    if not CreateProcess(nil,
       zAppName,   { pointer to command line string }
       nil,                { pointer to process security attributes }
       nil,                { pointer to thread security attributes }
       false,            { handle inheritance flag }
       CREATE_NEW_CONSOLE or   { creation flags }
       NORMAL_PRIORITY_CLASS,
       nil,                { pointer to new environment block }
       nil,                { pointer to current directory name }
       StartupInfo,   { pointer to STARTUPINFO }
       ProcessInfo) then Result := -1    { pointer to PROCESS_INF }

    else begin
       WaitforSingleObject(ProcessInfo.hProcess,INFINITE);
       GetExitCodeProcess(ProcessInfo.hProcess,Result);
    end;
 end;

 

<문자열 대.소문자로 바꾸기>

 EDITBOX 같은데서 키보드 입력 제한을 할때 영문(대.소문자)를 가리기 위해 대부분이 keypress 나 keyup 또는 keydown EVENT에서 처리 하는 것으로 알고 있습니다.

  좀 뭐랄까 ??? 약간 무식한 방법이였지요.... 소스코드도 지저분해 지고.......

  EditChange Event에서 다음과 같은 방법을 권합니다.

 

 procedure _MYForm.WoonoEdit1Change(Sender : TObject);
 begin
        WoonoEdit1.CharCase := clLowerCase;
        // 입력 받을때 무조건 영문 소문자로 받는다.
 end;

 

 ecLowerCase : 모든 영문자를 소문자로 받는다.
 ecUpperCase : 모든 영문자를 대문자로 받는다.
 ecNormal       : 모든 영문자를 보통 상태로 유지한다.

 

<파일정보(생성,변경,접근일자,속성,종류...)>

 아래 소스는 파일의 각종 정보를 읽어오는 루틴인데 완전히 모듈화가 된 것은 아니지만, 파일의 생성,변경,접근일자를 읽는 부분이 있어 올립니다  

  function FileSize(hi,lo: integer) :longint; 
  begin
    Result := (hi * MAXDWORD) + lo;
  end;

  // This function retrieves the last time, the given file was written to disk
 function GetLocalTime(a:tfiletime):string;

 var
      mtm:   TSystemTime;
      at:    TFileTime;
      ds,ts: ShortString;

 begin
      filetimetolocalfiletime(a,at);
      filetimetosystemtime(at,mtm);
      SetLength(ds, GetDateFormat(LOCALE_USER_DEFAULT, 0, @mtm, NIL, @ds[1], 255) - 1);
      SetLength(ts, GetTimeFormat(LOCALE_USER_DEFAULT, time_noseconds, @mtm, NIL,
            @ts[1], 255)  - 1);
      Result:=ds+'  '+ts;
 end;

 procedure TFileInfoForm.GetFileInfo(FileName: String);

 var
    SHFinfo: TSHFileInfo;
    FindData: TWin32FindData;    FindHandle :THandle;

 begin
    L_FileName.Caption := ExtractFileName(FileName); // 파일명(Name)
    ShGetFileInfo(PChar(FileName), 0, SHFinfo, SizeOf(SHFinfo), // 파일종류만 알아낸다
                  SHGFI_TYPENAME);
    L_Filetype.Caption := SHFinfo.szTypeName; // 파일종류(Type)
    FindHandle := Windows.FindFirstFile(PChar(FileName), FindData);

    try
      L_Filesize.Caption := FloatToStr(Trunc(FileSize(FindData.nFileSizeHigh,
         FindData.nFileSizeLow) / 1024))+' KB ('+ IntToStr(FileSize(FindData.nFileSizeHigh,
         FindData.nFileSizeLow))+' Bytes)';

      OldAttributes := FileGetAttr(FileName);  // 파일의 속성(attribute)
      CB_ReadOnly.Checked := (OldAttributes and faReadOnly) = faReadOnly;
      CB_Archive.Checked  := (OldAttributes and faArchive) = faArchive;
      CB_System.Checked   := (OldAttributes and faSysFile) = faSysFile;
      CB_Hidden.Checked   := (OldAttributes and faHidden) = faHidden;
       L_Created.Caption    := GetLocalTime(FindData.ftCreationTime);   // 파일생성일(Created)
      L_Modified.Caption   := GetLocalTime(FindData.ftLastWriteTime);  // 파일변경일(Modified)
      L_LastAccess.Caption := GetLocalTime(FindData.ftLastAccessTime);
      // 파일접근일(LastAccess)

    finally
      Windows.FindClose(FindHandle);
    end;
 end;

 

<JPEG 파일 처리>

우선 uses 에 JPEG 를 추가한다.

procedure TForm1.Button1Click(Sender : TObjcect);
var
   TempImg : TImage;
   Jpg : TJPEGImage;
begin
   TempImg:=TImage.Create(Self);
   with TempImg do   begin
      Width:=PaintBox1.Width;
      TempImg.Height:=PaintBox1.Height;
   end;
   Jpg:=TJPEGImage.Create;
   with PaintBox1 do begin
      BitBlt(TempImg.Canvas.Handle,0,0,Width,Height,Canvas.Handle,0,0,SrcCopy);
   end;
   TempImg.Picture.Bitmap.SaveToFile('TempImg.bmp');
   Jpg.Assign(TempImg.Picture.Bitmap);
     //Bitmap File을 Jpeg파일로
   Jpg.SaveToFile('TestImg.jpg');
   TempImg.Free;
   Jpg.Free;
end;

 

다른 방법(함수 이용 - 천리안 류님께서 올린 함수)
* Source

Implementation
uses
   JPeg;
 
procedure LoadJPeg(FileName:String; PicIn:TPicture);
var
   JPegImage : TJPegImage;
begin
   JPegImage:= TJPegImage.Create;
   JPegImage.LoadFromFile(FileName);
   PicIn.Assign(JPegImage);
   JPegImage.Free;
end;
 
procedure TForm1.Button1Click(Sender : TObject);
begin
  if OpenDialog1.Execute then
     LoadJPeg(OpenDialog1.Filename, Image1.Picture);
      //JPEG파일을 로드하여 Image1에 보여줌
end;

 

<Image 컴포넌트 위에 글씨쓰기>

procedure TForm1.Button1Click(Sender: TObject);
var
   OldBkMode : integer;
begin
   Image1.Picture.Bitmap.Canvas.Font.Color := clRed;
   OldBkMode := SetBkMode(Image1.Picture.Bitmap.Canvas.Handle, TRANSPARENT);
   Image1.Picture.Bitmap.Canvas.TextOut(10, 10, 'Hi, I am Park');
   SetBkMode(Image1.Picture.Bitmap.Canvas.Handle, OldBkMode);
end;

 

<파일의 날짜와 시간을 알아내기>

아래 함수를 이용합니다.
function GetFileDate(TheFileName: string): string;
var
   FHandle: integer;
begin
   FHandle := FileOpen(TheFileName, 0);
   try
      Result := DateTimeToStr(FileDateToDateTime(FileGetDate(FHandle)));
   finally
      FileClose(FHandle);
   end;
end;

 

<드라이브에 디스크 존재여부 알아내기>

function DriveReady(Drive : char):Boolean;
var
   OldErrorMode : word;
   OldDir : string;
begin
   OldErrorMode:= SetErrorMode(SEM_NOOPENFILEERRORBOX);
   GetDir(0, OldDir);
   Result:= True;
   try
      ChDir(Drive + ':\');
   except
      Result:= False
   end;
   ChDir(OldDir);
   SetErrorMode(OldErrorMode);
end;
 
procedure TForm1.Button1Click(Sender: TObject);
begin
   if DriveReady('A') then ShowMessage('Drive is Ready')
   else ShowMessage('Drive not Ready');
end;

 

<화면 캡쳐하여 저장하기>

procedure TForm1.Button1Click(Sender: TObject);
var
   DeskTop : TCanvas ;
begin
   DeskTop := TCanvas.Create ;
   try
   with DeskTop do
      Handle := GetWindowDC (GetDesktopWindow) ;
   with PaintBox1.Canvas do
   CopyRect (Rect (0, 0, Width, Height),   DeskTop, Rect (0, 0, Width, Width))
   finally
      DeskTop.Free
   end;
end;
 
procedure TForm1.Button2Click(Sender: TObject);
var
   MyBmp: TBitmap;
begin
   MyBmp := TBitmap.Create;
   with MyBmp do begin
     Height := PaintBox1.Height;
     Width := PaintBox1.Width;
     Canvas.CopyRect (Rect (0, 0, Width, Height), PaintBox1.Canvas, Rect (0, 0, Width, Height));
     SaveToFile('c:\Grim.bmp');
   end;
      MyBmp.Free;
end;

 

<텍스트 문서 미리보기>

솔직히 미리보기라기 보다는 텍스트 파일의 내용을 Bitmap파일로 변환하여 저장합니다.
procedure TForm1.Button1Click(Sender: TObject);
var
   Bmp : TBitmap;
   Line : string;
   I : integer;
   ch : char;
   F : TextFile;
begin
   I := 0;
   Bmp := TBitmap.Create;
   with Bmp do begin
      Width := ClientRect.Right;
      Height := ClientRect.Bottom;
      AssignFile(F, 'c:\mytext.txt'); {저장하고자 하는 파일명을 삽입}
      Reset(F);
      repeat
        Inc(I);
        Line := '';
        repeat
          Read(F, ch);
          Line := Line+ch;
       until ch= #10;
       Canvas.TextOut(10, I*20, Copy(Line, 1, Length(Line)-2));
      until EOF(F);
   CloseFile(F);
   BitBlt(Canvas.Handle, 0, 0, Width, Height, GetDc(Handle),  ClientRect.Left, ClientRect.Top, SRCCOPY);
   SaveToFile('c:\preview.bmp');
   Free;
   end;
end;

 

<폼의 크기 제한하기>

폼의 크기를 조절할 때 최대, 최소의 크기제한을 두려면
"WM_GETMINMAXINFO"의 메시지 핸들러를 작성해야 한다.
type
   TForm1 = class(TForm)
     procedure FormCreate(Sender: TObjcet);

   private
     MinSize : TPoint;       //최소크기 제한
     MaxSize : TPoint;      //최대크기 제한
     procedure WMGetMinMaxInfo(var Msg: TWMGetMinMaxInfo);
     message WM_GETMINMAXINFO;
     //메시지 WM_GETMINMAXINFO에 반응하는 메소드

   public
end;
 
procedure TForm1.WMGetMinMaxInfo(var Msg: TWMGetMinMaxInfo);
begin
   if visible then begin
   Msg.MinMaxInfo^.PtMinTrackSize := MinSize;
   Msg.MinMaxInfo^.PtMaxTrackSize := MaxSize;
   end;
end;
 
procedure TForm1.FormCreate(Sender: TObject);  //최대,최소 사이즈 지정
begin
   MaxSize.X := 200;   
   MaxSize.Y := 500;
   MinSize.X := 100;
   MinSize.Y := 200;
end;

 

<마우스 동작범위 제한하기>

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
   R : TRect;
begin
   R := BoundsRect;
   InflateRect(R,-30,-30);
   ClipCursor(@R);
end;
 
procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
   ClipCursor(Nil);
end;

 

<스플레시 화면 만들기>

프로그램 시작시 나타나는 로고화면을 제작하는 방법이다. 이는 프로젝트파일(.dpr)를 직접
수정해야만 한다.
Project Option에서 SplashForm을  Available forms로 옮긴다.
program project1;
 
uses
   Forms,
   Unit1 in 'Unit1.pas' {Form1},
   Splash in 'Splash.pas' {SplashForm},
 
{$R *.RES}
begin
  SplashForm := TSplashForm.Create(Application);
  SplashForm.Show;
  SplashForm.Update;
  Application.CreateForm(TForm1, Form1);
  SplashForm.Hide;
  SplashForm.Free;
   Application.Run;
end.

 

<구멍난 폼 만들기>

하나의 폼 위에 다섯개의 판넬을 올려놓고 각각의 속성을  아래의 '표1' 과 같이 설정하고,
폼의 OnResize이벤트 헨들러를 생성 해 아래의 코드를 입력하자.
 
procedure TForm1.FormResize(Sender: TObject);
var
   WindowRgn, HoleRgn : HRgn;
begin
   WindowRgn := 0;
   GetWindowRgn(Handle, WindowRgn);
   DeleteObject(WindowRgn);
   WindowRgn := CreateRectRgn(0,0,Width, Height);
   HoleRgn := CreateRectRgn(Panel3.Width + 6, Panel1.Height + 25,
                   Width - (Panel4.Width + 6), Height - (Panel2.Height + 6));
   CombineRgn(WindowRgn, WindowRgn, HoleRgn, RGN_DIFF);
   SetWindowRgn(Handle, WindowRgn, TRUE);
   DeleteObject(HoleRgn);
end;
 
표1
---------------------------------
Panel1
---------------------------------
Align alTop
BevelOuter bvNone
Caption
Height 17
---------------------------------
Panel2
---------------------------------
Align alBottom
BevelOuter bvNone
Caption
Height 17
---------------------------------
Panel3
---------------------------------
Align alRight
BevelOuter bvNone
Caption
Width 17
---------------------------------
Panel4
---------------------------------
Align alRight
BevelOuter bvNone
Caption
Width 17
---------------------------------
Panel5
---------------------------------
Align alClient
BevelOuter bvLowered
Caption
---------------------------------

 

<원형 폼 만들기>

procedure TForm1.FormCreate(Sender : TObjcet);
var
   MyForm : HRGN;
begin
   MyForm := CreateEllipticRgn(0, 0, Width, Height);  //타원의 폼 설정
   SetWindowRgn(Handle, MyForm, TRUE);
end;
procedure TForm1.FormDestory(Sender : TObject);
begin
   DeleteObject(MyForm);
end;

 

<다각형의 폼 만들기>

다각형의 폼도 마찬가지로 CreatepolygonRgn함수를 사용해 만들 수 있다.
아래와 같이 하면 역삼각형의 폼이 만들어진다.
procedure TForm1.FormCreate(Sender : TObject);
var
   MyForm : HRGN;
   Pixel : array[0..2] of TPoint;
begin
   Pixel[0] := Point(0, 0);        //폼의 좌표를 설정
   Pixel[1] := Point(Width, 0);
   Pixel[2] := Point(Width div 2, Height);
   MyForm := CreatePolygonRgn(Pixel, 3, ALTERNATE);
   SetWindowRgn(Handle, MyForm, TRUE);
end;

 

<힌트의 속성바꾸기>

델파이에서는 힌트속성을 쉽게 구현할 수 있는 반면 힌트의 속성을 바꿀 수 있는 프로퍼티가 없습니다.
아래의 방법을 통해 속성을 바꿔보세요.
....
type
  TUserHint = class(THintWindow)
  constructor Create(AOwner: TComponent); override;
end;                                         //interface부에 삽입
...
constructor TUserHint.Create;
begin
   inherited Create(AOwner);
   Canvas.Font.Name := '궁서체';    // 원하는 폰트의 이름 지정
   Canvas.Font.Size := 10;              // 원하는 폰트의 사이즈 지정   
   Canvas.Brush.Color := clYellow;  // 원하는 바탕색 지정
end;                                             // implementation부에 삽입
 
procedure TForm1.FormCreate(Sender: TObjcet);
var
   OldHint : Boolean;
begin
   OldHint := Application.ShowHint;
   Application.ShowHint := False;
   HintWindowClass := TUserHint;
   Application.ShowHint := OldHint;
end;
end.

 

<상태바에 힌트보이기>

public
{ Public declarations }
   procedure ShowHint(Sender : TObject);  //힌트를 보이기위한 프로시저
end;
 
procedure TForm1.ShowHint(Sender : TObject);
begin
    StatusBar1.Panels[0].Text := Application.Hint;
end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
    Application.HintPause := 100;  //힌트가 나타나는 속도조절
    Application.OnHint := ShowHint;
end;
또한 힌트와 상태바에 동시에 힌트를 나타내고자 하는 경우에는 Hint속성을 '|'문자를 끊어서
동시에 지정할 수 있다. ("풍선도움말|OnHint이벤트에서 사용할 힌트")

 

<Drive Type을 알아내자>

임의의 드라이브 타입을 알려면, 윈도우 API 함수 중 GetDriveType이라는 함수를 사용하면 된다.

 

procedure TForm1.Button1Click(Sender: TObject);

var
   Drive: Char;
   DriveLetter: String[4];

begin
   for Drive := 'A' to 'Z' do
   begin
      DriveLetter := Drive + ':\';
      //  Syntax
      //  GetDriveType(
      //  lpRootPathName: PChar   {a pointer to the root path string}
      //  ): UINT;                 {returns a value based on the drive type}

      case GetDriveType(PChar(Drive + ':\')) of
         Drive_UnKnown : ListBox1.Items.Add( DriveLetter + ': 알 수 없는 드라이브');
         Drive_Removable: ListBox1.Items.Add( DriveLetter + ' : 플로피 드라이브');
         Drive_Fixed:      ListBox1.Items.Add( DriveLetter + ' : 하드 드라이브');
         Drive_Remote:    ListBox1.Items.Add( DriveLetter + ' : 네트워크 드라이브');
         Drive_Cdrom:     ListBox1.Items.Add( DriveLetter + ' : CD-Rom 드라이브');
         Drive_RamDisk:   ListBox1.Items.Add( DriveLetter + ' : RamDisk 드라이브');
      end;
   end;
end;


[TMemo Component] 현재 라인번호 알아내기

메모에서 현재 Caret이 위치하고 있는 줄이 몇 번째 줄인지를 리턴한다.

Label1.Caption := IntToStr(GetCurrLine(Memo1));

function GetCurrLine(Memo : TMemo) : integer;
begin
      Result := Memo.Perform(EM_LINEFROMCHAR, Memo.SelStart, 0);
end;

 

[TMemo Component] 현재 컬럼번호 알아내기

메모에서 현재 Caret이 위치하고 있는 줄에서 몇 번째 컬럼인지를 리턴한다.

Label1.Caption := IntToStr(GetCurrCul(Memo1));

function GetCurrCul(Memo : TMemo)) : integer;
begin
     Result := Memo.SelStart - Memo.Perform(EM_LINEINDEX, GetCurrLine(Memo), 0);
end;

 

[TMemo Component] Caret를 원하는 라인으로 이동하기

Caret을 원하는 위치로 이동시키는데 이때 넘겨주는 값이 라인의 한계를 벗어나면 그 안 범위로 위치시킨다.

만약 라인의 맨끝으로 이동시키고 싶다면 아주 큰값을 주면된다.

SetCurrLine(Memo1. 10);

procedure SetCurrLine(Memo : TMemo; Value : integer);
begin
   if Value < 0 then Value := 0;
   if Value > Memo.Lines.Count then Value := Memo.Lines.Count;
   Memo.SelLength := 0;
   Memo.SelStart := Memo.Perform(EM_LINEINDEX, Value, 0);
end;

[TMemo Component] Caret을 원하는 컬럼으로 이동하기

SetCurrCul(Memo1. 10);

procedure SetCurrCul(Memo : TMemo; Value : integer);
var
   CurrLine : integer;
begin
   CurrLine := GetCurrLine(Memo);
   if Value < 0 then Value := 0;
   if (Value > Length(Memo.Lines[CurrLine])) then
      Value := Length(Memo.Lines[CurrLine]);
   Memo.SelLength := 0;
   Memo.SelStart := Memo.Perform(EM_LINEINDEX, CurrLine, 0) + Value;
end;

 

[TMemo Component] Text가 쓰여지는 영역 알아내기

현재 Text가 쓰여지는 영역을 TRect형으로 리턴한다.

즉 글자의 높이가 10이고 메모의 높이가 25라면 2라인만이 그려지게 된다.

따라서 글자가 그려지는 정확한 영역을 알아내기 위해서는 아래 함수를 사용한다.

Rect := GetTextRect(Memo1);

function GetTextRect(Memo : TMemo) : TRect;
var
   lParam : TRect;
begin
   Memo.Perform(EM_GETRECT, 0, Integer(@lParam));
   Result := lParam;
end;

 

[TMemo Component] 메모에서 현재 보이는 라인수 알아내기

Label1.Caption := IntToStr(GetVisibleLine(Memo1));

function GetVisibleLine(Memo : TMemo) : integer;
var
   Metric : TTextMetric;
   DC : hDC;
begin
   DC := GetWindowDC(Memo.Handle);
   GetTextMetrics(DC, Metric);
   Result := (GetTextRect(Memo).Bottom div Metric.tmHeight);
end;

 

[TMemo Component] 원하는 라인만큼 스크롤하기

현재상태에서 원하는 x, y만큼 스크롤한다.

DoScroll(Memo1, 10, 10);

procedure DoScroll(Memo : TMemo; x : integer; y : integer);
begin
   Memo.Perform(EM_LINESCROLL, x, y);
end;

 

[TRichEdit Component] 블록설정부분 폰트 변경하기

리치에디트컴포넌트는 메모컴포넌트와는 달리 설정부분만 폰트를 변경한다던가, 정렬상태를 바꾸는게 가능하다.

procedure TForm1.FontBtnClick(Sender : TObject);

begin
   if RichEdit1.SelLength > 0 then
   begin
      FontDialog1.Font.Assign(RichEdit1.DefAttributes);
     if FontDialog1.Execute then
         RichEdit1.SelAttributes.Assign(FontDialog1.Font);
   end

   else
     ShowMessage('No Text Selected');
end;

  

[TRichEdit Component] 블록설정부분 속성 변경하기

아래의 소스는 굵게(Bold) 속성을 지정한다.

이탤릭(fsItalic), 밑줄(fsUnderLine) 등의 속성도 마찬가지로 바꿀 수 있다.

procedure TForm1.BoldBtn(Sender : TObject);
begin
   if BoldBtn.Down then
      RichEdit1.SelAttributes.Style := RichEdit1.SelAttributes.Style + [fsBold]
   else
      RichEdit1.SelAttributes.Style := RichEdit1.SelAttributes.Style - [fsBold];
end;

 

[TRichEdit Component] 블록설정부분 복사, 삭제, 잘라우기, 붙이기 설정방법

interface부의 uses절에 Clipbrd를 추가한다.

procedure TForm1.CopyBtnClick(Sender : TObject);
begin
   RichEdit1.CopyToClipboard;  {복사}
   RichEdit1.CutToClipboard;   {잘라두기}
   RichEdit1.ClearSelection;  {지우기 - 클립보드에 저장되지 않는다}
   if Clipboard.HasFormat(CF_TEXT) then begin
      PasteBtn.Enabled := True;   {복사가 되었으면붙이기 버튼을 활성화}
   end;
end;

procedure TForm1.PasteBtnClick(Sender : TObject);
begin
   RichEdit1.PasteFromClipboard;
end;

 

[TRichEdit Component] Insert 키 상태 알아내기

이 소스는 RichEdit 컴포넌트에서만 사용할 수 있다.(메모컴포넌트는 삽입, 수정의 개념이 없음)

procedure TForm1.RichEdit1Key(Sender: TObject; var Key: Word; Shift: TShiftState);
var
  ret : integer;
begin
   ret := GetKeyState(45);
   if ret=1 then
      Label1.Caption := 'Overwrite'
   else
      Label1.Caption := 'Insert';
end;

 

[Find Dialog Component] 리치에디트에서 문자열찾기

먼저 폼에 Memo, FindDialog컴포넌트를 배치합니다. 델파이 도움말에서 참조했습니다.

procedure TForm1.FindBtnClick(Sender : TObject);
begin
   FindDialog1.Execute;
   { or ReplaceDialog1.Execute;}
end;

procedure TForm1.FindDialog1Find(Sender: TObject);
var
   SelPos: Integer;
begin
   with TFindDialog(Sender) do
   begin
      { Perform a global case-sensitive search for FindText in Memo1 }
      SelPos := Pos(FindText, Memo1.Lines.Text);
      if SelPos > 0 then 
      begin
         Memo1.SelStart := SelPos - 1;
         Memo1.SelLength := Length(FindText);
       end
     
      else MessageDlg(Concat('Could not find "', FindText, '" in Memo1.'),
          mtError,[mbOk], 0);
   end;
end;

procedure TForm1.ReplaceDialog1Replace(Sender: TObject);
var
   SelPos: Integer;
begin
   with TReplaceDialog(Sender) do
   begin
     { Perform a global case-sensitive search for FindText in Memo1 }
     SelPos := Pos(FindText, Memo1.Lines.Text);
     if SelPos > 0 then
     begin
        Memo1.SelStart := SelPos - 1;
        Memo1.SelLength := Length(FindText);
        { Replace selected text with ReplaceText }
        Memo1.SelText := ReplaceText;
      end
   
     else MessageDlg(Concat('Could not find "', FindText, '" in Memo1.'),
          mtError,[mbOk], 0);

   end;
end;

 

<System Modal 폼을 만들려면>

Windows API 함수인 SetSysModalWindow를 사용하면 가능합니다.

다음은 System Modal 창을 보여주는 간단한 예제입니다.

procedure TMainForm1.Create(Application) do
begin
   SetSysModalWindow(Handle);
end;

 

<.RES 화일에서 비트맵을 불러오려면>

다음과 같이 선언합니다.

implementation
{$R C:\Delphi\MyDir\MyRes.Res} <- .RES 화일이 있는 경로명과 파일명

위와 같이 선언한 후에 사용시에는 다음과 같이 Windows API함수를 이용합니다.

Image1.Picture.Bitmap.Handle := LoadBitmap(HInstance, 'BITMAP1');

 

<Win95 와 W3.X 를 구별하는 법>

Windows API 함수인 GetVersion 을 쓰시면 가능합니다.

다음은 버튼을 누르면 윈도우의 버전을 보여줍니다.

procedure TForm1.Button1Click(Sender: TObject);
Var
   x :longint;
   y,z :integer;
begin
   x := GetVersion;
   y := integer(x and $ff);
   z := integer((x shr 8) and $ff);
   Edit1.Text := IntToStr(y);
   Edit2.Text := IntToStr(z);
end;

 

<마우스 커서를 보이지 않게 하려면>

Window API함수인 ShowCursor 에서 값을 False로 줍니다.

 

<정의된 message handler에 다른 작업을 추가하려면>

예를 들어 CM_DIALOGKEY message가 발생되었을 때 원하는 작업을 추가하려고한다면 public section에 다음과 같이 선언합니다.

Procedure CMDialogKey(var Message: TCMDialogKey);message CM_DIALOGKEY;

procedure이름을 message 이름에서 _(밑줄) 표시를 뺍니다. procedure의 정의는 다음과 같습니다.

Procedure TForm1.CMDialogKey(var Message: TCMDialogKey);
begin
   if CharCode = VK_TAB then begin
      {Process the Alt+Tab key here}
      result := 1;
      exit;
   end;
   inherited;
end;

result를 1로 setting하면 더 이상 실행시키지 않고 중단시키겠다는 뜻이고, inherited문은 parent handler로 제어를 보냄을 의미합니다. 모든 작업을 일일이 처리하고자 하지 않으면 inherited문을 사용하십시오.

 

<Run-Time시에 DLL을 Load하고 Free 시키는 방법>

Windows API 함수인 LoadLibrary를 쓰면 Load가 가능합니다. 또한 FreeLibrary를 쓰면 메모리에서 제거할 수 있습니다.

 

<비정상적으로 종료된 DLL 프로그램을 강제적으로 unload 하는 방법>

Windows API 함수인 GetModuleHandle은 DLL의 handle을 돌려주므로ModuleHandle이 0을 리턴할 때 까지 freelibrary를 call한다. 만약에 DLL이 다른 DLL을 Load 했다면 child DLL을 먼저 free시킨다.

 

<DLL의 data segment를 fixed에서 movable로 바꾸는 방법>

DLL 외부에서 GlobalPageUnlock(DSEG)를 부르면 됩니다. 이 함수는DLL 소스에서 Pointer등을 이용하지 않는다면 정상적으로 실행될 것입니다.

 

<최소화되어 있는 Icon을 안보이게 하는 방법>

SetWindowPos나 MoveWindow를 이용하여 좌표값을 음수로 주면 됩니다.

 

<외부의 Exe 화일 호출하는 방법>

Windows API 함수인 WinExec 를 사용하면 됩니다. 다음은 간단한 예제 코드입니다.

WinExec('프로그램명', SW_SHOW);

 

<Title Bar가 없는 Form을 움직이게 하려면>

폼위에서 마우스 커서가 움직이면, 윈도우는 폼에 WM_NCHitTest 메시지를보냅니다. 이 때 폼은 마우스가 폼의 어느 위치에 있는지를 메시지로 주게 됩니다. 마우스의 버튼을 누르는 것과 같은 event가 발생하면 윈도우는 이 정보를 써서 특정행동을 수행하게 되는 것입니다.

다음은 WM_NCHitTest 메시지가 특정한 값을 주는 예제 코드입니다.

procedure TNoCapForm.WMNCHitTest(var Msg: TMessage);
begin
   if GetAsyncKeyState(VK_LBUTTON) < 0 then
      Msg.Result := HTCAPTION
   else
      Msg.Result := HTCLIENT;
end;

 

<Resource를 동적으로 load/free 하는 방법>

Windows가 제공하는 LoadResource(), FreeResource() API 함수를사용합니다.

 

<System 또는 User resource, memory 상태를 구하는 방법>

Windows API를 이용하면 됩니다. GetFreeSystemResource 함수를 참고하시면 됩니다.

다음은 버튼을 누르면 시스템 자원을 보여주는 간단한 코드입니다.

procedure TForm1.Button1Click(Sender: TObject);
begin
   Label1.Caption := IntToStr(GetFreeSystemResources(GFSR_SYSTEMRESOURCES));
   Label2.Caption := IntToStr(GetFreeSystemResources(GFSR_USERRESOURCES));
   Label3.Caption := Formatfloat('#,##0', (GetFreeSpace(0) div 1000));
end;

 

<Visual Basic의 DoEvent와 같은 기능을 사용하려면>

다음과 같이 함수를 만드실 수 있습니다.

function DoEvents: Boolean;
var msg: TMsg;

begin
   while PeekMessage(msg, 0, 0, 0, PM_REMOVE) do
   begin
      if msg.message = WM_QUIT then
      begin
         PostQuitMessage(msg.wParam);
         DoEvents := true;
         exit;
      end
     
      else
      begin
         TranslateMessage(msg);
         DispatchMessage(msg);
      end;
   end;
   DoEvents := false;
end;

 

<프로그램의 실행이 끝나기를 기다리는 법>

WinExec 함수는 핸들을 돌려주므로, 이것을 이용합니다.

procedure SomeProc;
var
   ProgramHandle : THandle;
begin
   ProgramHandle := WinExec('C:\Program.exe', SW_SHOWNORMAL);

   {프로그램이 종료될 때까지 반복}
   while GetModuleusage(ProgramHandle) <> 0 do application.processmessages;
end;

 

<프로그램 실행중에 잠시 멈추고 다른 프로세스를 실행시키려면>

다음과 같은 코드를 작성하실 수 있습니다.

procedure TForm1.Delay(msecs:integer);
var
   FirstTickCount:longint;
begin
   FirstTickCount:=GetTickCount;

   repeat
   {실행을 잠시 중지하고 다른 프로세스를 실행합니다.}
      Application.ProcessMessages;
      until ((GetTickCount-FirstTickCount) >= Longint(msecs));
end;

참고로 Application.ProcessMessage 는 메시지 큐에 쌓여있는 메시지중 하나를처리하고 메시지가 큐에 없으면 false를 리턴합 니다.

 

<control의 handle이나 ID를 얻는 방법>

control object의 pointer를 알고 있다면 PointerToMyControl^.HWindow가 바로 window handle입니다.

만약, control의 handle을 알고 있다면 GetDlgCtrlID() API 함수는 ID를 돌려줍니다.

ControlID := GetDlgCtrlID(ControlHandle);

만약 contorl의 pointer를 모르고 ID만 알고 있다면, GetDlgItem() API 함수는handle을 돌려줍니다.

ControlHandle := GetDlgItem(DialogHandle, ControlID);

 

<프로그램이 실행된 디렉토리를 알 수 있는 방법>

다음의 함수는 Application이라는 개체의 ExeName 속성으로부터 디렉토리 경로를 추출해 냅니다.

function GetExePath : String;
var
   LastBackSlashPos, Index : Integer;
begin
   Result := Application.ExeName;
   for Index := 1 to length(Result) do
   if Result[Index] = '\' then LastBackSlashPos := Index;

   {'\' 기호가 붙지 않도록 하려면 LastBackSlashPos 에서 1을 빼야합니다. }
   Result[0] := chr(LastBackSlashPos - 1);
end;

 

<Directory를 만드는 방법>

MKDIR procedure를 이용하면 됩니다.

MkDir('C:\Delphi\MyDir');

 

<MediaPlayer를 이용하지 않고 sound를 발생할 수 있는 방법>

mmSystem에 있는 SndPlaySound Function을 이용하면 됩니다.

SndPlaySound('C:\Windows\Ding.WAV', snd_Async);

 

<Windows의 Message를 처리하는 방법>

다음 Windows 메시지를 처리하는 procedure를 참고하십시오.

procedure YieldToOthers ;
var MSG : TMSG ;
begin
   while PeekMessage(MSG, 0,0,0,PM_REMOVE) do begin
      if Msg.Message = WM_QUIT then exit ;
      TranslateMessage(Msg) ;
      DispatchMessage(Msg) ;
   end ;
end ;

 

<Windows의 Main Message Procedure를 만드는 방법>

다음 예제 procedure를 참고하십시오.

procedure TForm1.ClientWndProc(VAR Message: TMessage);
begin
   with Message do
   case Msg of
      WM_MOUSEMOVE : Memo1.Lines.Add('Mouse Move') ;
      WM_LBUTTONDOWN : Memo1.Lines.Add('LeftButton Down') ;
   else
      Result := CallWindowProc(FPrevClientProc, Handle, Msg, wParam, lParam);
   end;
end;

 

<다른 Application의 메뉴 기능을 실행하도록 하려면>

다음 예제 procedure를 참고하십시오.

CurrWnd := GetWindow(application.handle, gw_hwndfirst);
length := GetWindowText(Currwnd, tmpstr, 255);

if length > 0 then
begin
   if (pos('훈민정음', strpas(tmpstr)) > 0) and (strpas(pAttach^.filepath.tmpstr)<> nil) then
      CurrWnd := 0;
end;

tmpname := ExtractFilename(strpas(pAttach^.filepath));

While CurrWnd <> 0 do
begin
   length := GetWindowText(Currwnd, tmpstr, 255);

   if (length > 0) and (pos('훈민정음', strpas(tmpstr) > 0) and (pos(tmpname,StrPas(tmpstr)) > 0) then
   break;

   CurrWnd := GetWindow(CurrWnd, GW_HWNDNEXT);
   Application.ProcessMessages;
end;

Handle := CurrWnd;

if Handle <> 0 then
begin
   SendMessage(Handle, WM_COMMAND, 4005, 0);
   SendMessage(Handle, WM_SYSCOMMAND, SC_CLOSE, 0);
end;

 

<폼이 최소화 되지 못하도록 하려면>

다음과 같이 WM_SYSCOMMAND 메시지를 처리하면 됩니다.

type
   TForm1 = class(TForm)
public :
   procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND;
end;

procedure TForm1.WMSysCommand(var Msg:TWMSysCommand) ;
begin
   {최소화/최대화 버튼을 누를때 아무 작용을 하지 않게 합니다}
   if (Msg.CmdType = SC_MINIMIZE) or (Msg.CmdType = SC_MAXIMIZE) then
      Msg.CmdType := SC_RESTORE;

   DefaultHandler(Msg);
end;

 

<DPR 화일의 Application.Run이 실행되기 전에 Windows 메시지를 가로채는방법>

다음과 같이 새로운 Windows Message procedure를 정의하고 그것을Main Windows procedure로 설정합니다. 다음 예제 procedure를 참고하십시오.

program Project1;

uses
   Forms, messages, wintypes, winprocs,
   Unit1 in 'UNIT1.PAS';

{$R *.RES}

var
   OldWndProc: TFarProc;

function NewWndProc(hWndAppl: HWnd; Msg, wParam: Word; lParam: Longint):Longint; export;
begin
   result := 0; { Default WndProc return value }

   {message 처리 루틴이 들어갈 곳}

   result := CallWindowProc(OldWndProc, hWndAppl, Msg, wParam, lParam);
end;

begin
   Application.CreateForm(TForm1, Form1);
   OldWndProc := TFarProc(GetWindowLong(Application.Handle, GWL_WNDPROC));
   SetWindowLong(Application.Handle, GWL_WNDPROC, longint(@NewWndProc));
   Application.Run;
end.

 

<Task Handling 방법>

ToolHelp unit에 정의되어 있는 함수들을 이용하면 됩니다. 다음은 TaskFirst, TaskNext 등을 이용한 예제입니다.

function isTaskInstance(HInst : Longint) : Boolean;
var CurrentTask : TTaskEntry;
   Success : boolean;
begin
   Result := false;
   Yield;
   CurrentTask.dwSize := SizeOf(CurrentTask);
   Success := TaskFirst(@CurrentTask);
   while Success do begin
      if CurrentTask.HInst = HInst then begin
         Result := true;
         exit;
      end;
      Success := TaskNext(@CurrentTask);
   end;
end;

 

<MDI 어플리케이션에서 focus를 가지고 있는 form이 어느 것인지 알수 있는 방법>

TForm의 ActiveMDIChild property를 이용합니다.

if Application.MainForm.ActiveMDIChild as TEditForm then
TEditForm(ActiveMDIChild).Save1Click(Sender);

 

<Delphi의 MDI에서 title bar가 없는 child form 을 만드는 방법>

다음과 같이 MDI Parent Form에 코드를 입력하시면 가능합니다.

type
   TForm1 = class(TForm) {TForm1 는 child form의 이름입니다.}
   procedure CreateParams(var Params: TCreateParams);
   override;
end;

procedure TForm1.CreateParams(var Params: TCreateParams);
begin
   inherited CreateParams(Params);
   Params.Style := Params.Style and not WS_OVERLAPPEDWINDOW or WS_BORDER ;
end;

 

<MDI application에서 특정 child를 항상 일정한 크기/위치로 고정하는방법>

Child Form의 onActivate event에서 다음과 같이 크기와 위치를 정해주면됩니다.

procedure TEditForm.FormActivate(Sender: TObject);
begin
   Left := 200;
   Height := 140;
end;

단, 이 이후에 생성하는 child form은 윈도우의 기본 특성에 따라 다른 위치로생성됩니다.

 

<MDI에서 차일드 윈도우의 위치 지정>

사용자가 Run-Time시에 Child Windows를 열면 각각은 이전 윈도우의 약간 우측 아래에 위치하게 됩니다. 이렇게 하고 싶지 않을 경우 어떻게 해야 합니까?


이것은 MDI 윈도우가 어떻게 작업하느냐 입니다. VCL은 이 상황에서윈도우의 기본적인 행동을 무시하진 못합니다.

단, Position Property 에서 poScreenCenter 값을 사용할 수 있습니다. 그러나 이 속성을 선택하면 child form이 항상 Parent Form의 가운데에 위치합니다.

 

<Caps Lock 키 조절>

어떻게 Caps Lock 키를 조절할 수 있습니까?

SetKeyboardState 함수를 사용하면 됩니다.

다음은 버튼을 누를 때 마다 Caps Lock 키의 상태가 변하도록 하는 코드입니다.

procedure TForm1.Button1Click(Sender: TObject);
   var
      Level : Integer;
      KeyState : TKeyBoardState;
      begin
         Level := GetKeyState(VK_CAPITAL); {Caps Lock 키를 체크한다}
         GetKeyboardState(KeyState);
         If Level = 0 then
         begin
            KeyState[VK_CAPITAL] := 1;
            setKeyboardState(KeyState);
        end
        else if Level = 1 then
        begin
           KeyState[VK_CAPITAL] := 0;
         setKeyboardState(KeyState);
   end;
end;

 

<눌려진 Key가 무엇인지 확인하는 방법>

Form의 KeyPreview 속성을 True 로 하고, KeyDown 이벤트에서 처리하면됩니다.

다음은 Key를 처리하는 예제 procedure 입니다.

procedure TForm1.Edit3KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
var
tempstr: string; {used to spell out keys typed}
begin

{be sure to set Form.KeyPreview to True}
Edit4.Text := '';
if (Shift = ([ssShift])) then Edit4.Text := Edit4.Text + 'Shift';
if (Shift = ([ssShift, ssAlt])) then Edit4.Text := Edit4.Text + 'Shift+Alt';
if (Shift = ([ssShift, ssCtrl])) then Edit4.Text := Edit4.Text + 'Shift+Ctrl';
if (Shift = ([ssShift, ssAlt, ssCtrl])) then Edit4.Text := Edit4.Text +'Shift+Ctrl+Alt';
if (Shift = ([ssAlt])) then Edit4.Text := Edit4.Text + 'Alt';
if (Shift = ([ssAlt, ssCtrl])) then Edit4.Text := Edit4.Text + 'Ctrl+Alt';
if (Shift = ([ssCtrl])) then Edit4.Text := Edit4.Text + 'Ctrl';

tempstr := '';

case Key of
VK_CANCEL: tempstr := 'CANCEL';
VK_BACK: tempstr := 'BACKSPACE';
VK_TAB: tempstr := 'TAB';
VK_CLEAR: tempstr := 'CLEAR';
VK_RETURN: tempstr := 'ENTER';
VK_PAUSE: tempstr := 'PAUSE';
VK_CAPITAL: tempstr := 'CAPS LOCK';
VK_ESCAPE: tempstr := 'ESC';
VK_SPACE: tempstr := 'SPACEBAR';
VK_PRIOR: tempstr := 'PAGE UP';
VK_NEXT: tempstr := 'PAGE DOWN';
VK_END: tempstr := 'END';
VK_HOME: tempstr := 'HOME';
VK_LEFT: tempstr := 'LEFT ARROW';
VK_UP: tempstr := 'UP ARROW';
VK_RIGHT: tempstr := 'RIGHT ARROW';
VK_DOWN: tempstr := 'DOWN ARROW';
VK_SELECT: tempstr := 'SELECT';
VK_EXECUTE: tempstr := 'EXECUTE';
VK_SNAPSHOT: tempstr := 'PRINT SCREEN';
VK_INSERT: tempstr := 'INS';
VK_DELETE: tempstr := 'DEL';
VK_HELP: tempstr := 'HELP';

{VK_1..VK_0 and VK_A..VK_Z are not defined so you have to use the Ord()
function instead which yields the equivilent VK code}

Ord('0'): tempstr := '0';
Ord('1'): tempstr := '1';
Ord('2'): tempstr := '2';
.
.
Ord('A'): tempstr := 'A';
Ord('B'): tempstr := 'B';
Ord('C'): tempstr := 'C';
.
.
VK_NUMPAD0: tempstr := 'Numeric keypad 0';
VK_NUMPAD1: tempstr := 'Numeric keypad 1';
VK_NUMPAD2: tempstr := 'Numeric keypad 2';
.
.
VK_MULTIPLY: tempstr := 'Multiply';
VK_ADD: tempstr := 'Add';
VK_SEPARATOR: tempstr := 'Separator';
VK_SUBTRACT: tempstr := 'Subtract';
VK_DECIMAL: tempstr := 'Decimal';
VK_DIVIDE: tempstr := 'Divide';
VK_F1: tempstr := 'F1';
VK_F2: tempstr := 'F2';
VK_F3: tempstr := 'F3';
.
.
VK_NUMLOCK: tempstr := 'NUM LOCK';
VK_SCROLL: tempstr := 'SCROLL LOCK';
end;
if Edit4.Text = '' then Edit4.Text := tempstr
else if tempstr <> '' then Edit4.Text := Edit4.Text + '+' + tempstr;
Key := 0; {set key to 0 to send no key stroke}
end;

 

<특정 component에서 Enter 키를 눌렀을 때 원하는 처리 추가 방법>

[A8] KeyDown event handler에서 Key가 VK_Return 값인지 체크하면 됩니다.
다음은 그러한 event handler의 간단한 예제입니다.

procedure TForm1.Edit1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
if Key = VK_Return then
Edit2.Text := FormatFloat('###.###',StrToFloat(Edit1.Text)) ;
end;

 

<Enter키에 Tab키 효과를 주려면>

Edit 컴포넌트의 OnKeyPress 이벤트에 다음과 같은 코드를 사용하면됩니다.

procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
If Key = #13 Then
Begin
SelectNext(Sender as TWinControl, True, True );
Key := #0;
end;
end;

이것은 Enter를 Tab처럼 동작하게 합니다. 폼에 있는 전체의 콘트롤(버튼을제외한)에 대해서 이와같은 동작을 원하면 전체의 콘트롤을 선택한 후에 OnKeyPress핸들러를 Edit1KeyPress로 지정하면 됩니다.
이제 각각의 콘트롤에 대해서 Enter가 Tab처럼 작동됩니다.
만약, 폼 레벨에서 이와같은 동작을 원하면(폼에 있는 전체의 콘트롤의 OnKeyPress핸들러에 전부 지정하기를 원하지 않는다면) 폼의 OnKeyPress 에 다음과 같은코드를 사용하면 됩니다. 위의 코드에서 Sender만 ActiveControl로 바꾸고 폼의Property에서 KeyPreview를 true로 바꾸어 주면 됩니다.

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
If Key = #13 Then
begin
SelectNext(ActiveControl as TWinControl,True, True );
{Perfome(wm_NextDlgCtl,0,0); 라는 명령문도 가능합니다.}
Key := #0;
end;
end;

이것은 폼에 있는 각각의 콘트롤에 대해서 Enter가 Tab처럼 작동합니다.

 

<Task 전환키인 ALT+TAB 키를 disable 시키려면>

WM_KeyDown message를 처리하거나 Form의 KeyDown event handler를작성합니다.

다음은 간단한 예제 코드입니다.

procedure TForm1.WMKEYDOWN(var Message : TWMKEYDOWN); message WM_KEYDOWN;
begin
if ssAlt in KeyDataToShiftState(Message.KeyData) then
if Message.CharCode = VK_TAB then
begin
Message.CharCode := 0 ;
exit ;
end ;
end;

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
if ssAlt in Shift then
if Key = VK_TAB then
begin
Key := 0 ;
exit ;
end ;
end;

 

<Keyboard 명령을 사용하여 TForm component에서 스크롤 기능 사용하기>

예를 들어, 폼을 위/아래로 스크롤 하기 위해 PgUp과 PgDn키를 사용하고 싶습니다.

다음과 같이 프로그램 합니다.

procedure TForm1.FormCreate(Sender: TObject);
begin
with VertScrollBar do
begin
Range := 500;
Visible := True;
end;
end;

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
Const
PageDelta = 100;
Begin
With VertScrollBar do
If Key = VK_NEXT then Position := Position + PageDelta
Else If Key = VK_PRIOR then Position := Position - PageDelta;
End;

주의) TMemo와 같은 component에서는 동작하지 않을 수도 있습니다.

 

<화일 크기를 알고 싶다면>

다음과 같이 프로그램 합니다.

이것은 특정화일의 크기를 에디트박스에 보여주는 예제입니다.

Function FileGetSize(YourFile : String) : LongInt;
Var
   F : Integer;
   Begin
   F:=FileOpen(YourFile,0); { ReadOnly Mode }
   FileGetSize := FileSeek(F,0,2);
   FileClose(F)
End;

procedure TForm1.Button1Click(Sender: TObject);
begin
   Edit1.Text := IntToStr(FileGetSize('c:\bin\q.exe'));
end;

 

<화일을 복사 하려면>

다음 FileCopy 함수를 사용해 보십시오.

function FileCopy(source,dest: String): Boolean;
var
   fSrc,fDst,len: Integer;
   size: Longint;
   buffer: packed array [0..2047] of Byte;
   begin
      Result := False; { Assume that it WONT work }
      if source <> dest then begin
      fSrc := FileOpen(source,fmOpenRead);
      if fSrc >= 0 then begin
         size := FileSeek(fSrc,0,2);
         FileSeek(fSrc,0,0);
         fDst := FileCreate(dest);
         if fDst >= 0 then begin
         while size > 0 do begin
            len := FileRead(fSrc,buffer,sizeof(buffer));
            FileWrite(fDst,buffer,len);
            size := size - len;
         end;
         FileSetDate(fDst,FileGetDate(fSrc));
         FileClose(fDst);
         FileSetAttr(dest,FileGetAttr(source));
         Result := True;
      end;
      FileClose(fSrc);
   end;
end;
end;

 

<화일의 날짜와 시간을 설정하려면>

SetFTime 함수를 사용합니다.

다음은 화일의 날짜와 시간을 바꾸는 간단한 예제 코드입니다.

var
   f: file;
   begin
      Assign(f, DirInfo.Name);
   Reset(f);
   SetFTime(f, Time);
   Close(f);
end;

 

<INI file을 어떻게 처리합니까>

TIniFile Object를 이용하면 응용프로그램에서 .INI화일을 생성하여조작할 수 있습니다.
중요한 method로는 Create, ReadString, WriteString 등이 있습니다.

다음은 그러한 method 들의 간단한 예제 코드입니다.

var
   IniFile: TIniFile;
   begin
      IniFile := TIniFile.Create('C:\Windows\Delphi.INI');
      IniFile.ReadString('Library', 'SearchPath', 'C:\Delphi\Bin');
      IniFile.WriteString('Library', 'SearchPath', 'C:\Delphi\Bin;C:\MyDir');
      IniFile. Free;
end;

 

<특정 디렉토리에 있는 모든 화일을 다루는 방법>

FindFirst와 FindNext 함수를 사용합니다.

다음은 특정 디렉토리에 있는 화일의 이름과 크기를 보여주는 간단한 예제입니다.

var
   SearchRec: TSearchRec;

procedure TForm1.Button1Click(Sender: TObject);
begin
   FindFirst('c:\dl\bin\*.*', faAnyFile, SearchRec);
   Label1.Caption := SearchRec.Name + ' is ' + IntToStr(SearchRec.Size) +'bytes in size';
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
   FindNext(SearchRec);
   Label1.Caption := SearchRec.Name + ' is ' + IntToStr(SearchRec.Size) +'bytes in size';
end;

 

<인쇄관리자에서 표시되는 인쇄작업의 제목을 주고 싶을때>

다음과 같은 코드를 쓰시면 가능합니다.

Printer.Title := 'your title';

 

<프린터의 인치당 픽셀 구하기>

Windows API 함수인 GetDeviceCaps 을 사용하면 가능합니다.
다음은 에디트박스에 프린터의 가로, 세로 인치당 픽셀을 보여주는 간단한 코드입니다.

procedure TForm1.Button2Click(Sender: TObject);
begin
   Edit1.Text := IntToStr(GetDeviceCaps(Printer.Handle, LogPixelsX));
   Edit2.Text := IntToStr(GetDeviceCaps(Printer.Handle, LogPixelsY));
end;

 

<프린터에 escape 코드를 전달하는 방법>

다음은 삼보 KSSM 모드에서 축소 escape 코드를 사용하는 예제입니다.

procedure TForm1.Button1Click(Sender: TObject);
var
   MyFile: Textfile ;
   s, s1 : string ;
   ff : string ;

begin
   {삼보 KSSM Mode}
   s[0] := #1 ; {축소 지정}
   s[1] := #15 ;
   s1[0] := #1 ; {축소 해제}
   s1[1] := #18 ;
   ff[0] := #1 ; {Form Feed}
   ff[1] := #12 ;

   AssignFile(MyFile,'PRN') ;
   Rewrite(MyFile);
   s := 'Normal font size' + s + 'small font' + s1 + 'Normal font size' +ff ;
   Writeln(MyFile, s);
   System.CloseFile(MyFile);
end;

또는 Windows API 함수 Escape()를 참고 하십시오.

 

<특정 어드레스에 데이타를 저장하려면>

Object Pascal에서는 사용자가 직접 메모리를 다룰 수 있도록 다음과같은 함수를 제공합니다.

Mem
MemW
MemL

Mem의 각 요소는 Byte이고, MemW의 각 요소는 Word이며 MemL의 요소들은 Longint입니다.
Mem 배열함수는 인덱스로 특정한 형식을 취합니다.

다음은 예제 코드입니다:

Mem[$0040:$0049] := 7; {7 을 $0040:$0049에 저장한다}
Data := MemW[Seg(V):Ofs(V)]; {변수 V의 첫 2바이트에 저장된 워드 값을 변수데이타로 옮긴다.}

 

<TPrinter Object를 사용하려면>

다음 예제를 참고하십시오.

var Printer : TPrinter ;

FontDialog1.Font.Assign(Edit1.Font);
if Font1.Dialog.Execute then Edit1.Font.Assign(FontDialog1.Font);

Printer.Canvas.TextOut(X, Y, '문자열');
Printer.Canvas.TextRect(TRect, X, Y, '문자열');
Printer.Canvas.TextHeight('문자열');
GetDeviceCaps(Printer.Handle, LOGPIXELSX);
GetDeviceCaps(Printer.Handle, LOGPIXELSY);

Printer.NewPage;

 

<RES파일 추가후 Resource를 찾지 못할 경우>

사용자가 .RES화일을 추가 했어도 왜 사용자의 프로그램은 Resource의어느것도 찾지 못하는지요? 만약 사용자의 폼에 Unit 이름과 .RES가 같아서그럴까요?

만약 포함된 .RES화일의 이름이 .DPR화일 이름과 같다면 Delphi는자신의 .RES 화일로 덮어쓰기를 할 것입니다. 추가적으로, Project RES 화일은단지 Delphi Project 관리에 대한 것입니다.이 RES 화일에 Resources를 추가하거나,편집할 수 없습 니다.

 

<RC file을 컴파일하는 방법과 Bitmap, Cursor, Icon등을 사용하려면>

DOS Prompt에서 Delphi\Bin directory에 있는 BRCC.EXE를 이용하여컴파일하면 됩니다. 컴파일된 RC file은 .RES 형 태의 binary file로 생성됩니다.
생성된 .RES file을 다음과 같이 선언하여 program에서 사용하면 됩니다.

implementation

{$R C:\Delphi\MyDir\MyRes.Res}

위와같이 선언한 후 사용시에는 Windows API를 이용하면 됩니다.

Image1.Picture.Bitmap.Handle := LoadBitmap(HInstance, 'BITMAP1');
Screen.Cursors[1] := LoadCursor(HInstance, 'CURSOR1');
Image1.Picture.Icon.Handle := LoadIcon(HInstance, 'ICON1');
LoadString(HInstance, 1000, Buffer, 255);

 

<사용자에게 에러를 보여주기 전에 가로채기>

그러한 역할을 하는 새로운 Exception을 다음과 같이 만들 수 있습니다.
다음에 프로시져를 main 폼에 선언해줍니다.

type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);

{Exception처리를 하기 위한 procedure를 선언한다}
procedure MyException(Sender:TObject; E:Exception);
private
{ Private declarations }
public
{ Public declarations }
end;

procedure TMyForm.MyException(Sender:TObject; E:Exception);
begin
   if (E.ClassType.ClassName='EConvertError') then
begin
   {사용자가 원하는 처리 내용}
end
else Application.ShowException(E);
end;

procedure TMyForm.FormCreate(Sender: TObject);
begin
   Application.OnException := MyException;
end;

 

<Delphi는 Run-Time 오류를 어떻게 조정합니까>

Delphi에서 Run-Time 오류가 발생할때에 Exception이 생성됩니다.Delphi에서 사용자의 프로그램이 실행되는 동안 Ex ception이 발생할때, 개발환경에서특수한 옵션이 설정된다면, Delphi는 발생한 Line에 커서를 위치시킬 것입니다.그러면서도, 프로그램은 종료되지 않습니다. 따라서 Exception이 생성되면 사용자의어플리케이션은 자동적으로 종료되지 않습니다.

 

<'Stream Read Error'을 조정할 수 있는 방법>

*.DSM을 삭제한후 다시 Project를 컴파일합니다.

 

<WinPrn Unit 컴파일시 에러>

[Q] WinPrn Unit라 불리우는 코드를 컴파일할때, Delphi는 'It can't findWinPrn.DCU'를 나타냅니다.

[A] Option/Project의 search path에 \Delphi\Source\Rtl70'을 추가 합니다.

 

<새로운 커서를 만들어 사용하려면>

다음과 같이 RES 화일을 project에 포함시킵니다.

{$R c:\dl\testcur.res} {RES 화일의 이름과 경로를 명시}

procedure TForm1.Button1Click(Sender: TObject);
Var
   ddd: PChar;
begin
   GetMem(ddd, 8);
   ddd := 'Cursor_1';
   SetClassWord(Form1.handle, GCW_HCURSOR, LoadCursor(hinstance, ddd));
end;

 

<Cursor 모양을 바꾸려면>

다음은 어떤 작업시에 HourGlass 커서를 보여주고, 다시 정상적인커서를 보여주는 예제입니다.

Begin
Try
Screen.Cursor:=crHourGlass;
ReportForm := TReportForm.Create(Application);
Screen.Cursor:=crDefault;
ReportForm.ShowModal;
ReportForm.Free;
Finally
Screen.Cursor:=crDefault;
end;
end;

 

<이미지의 크기를 조절하여 보려주려면>

다음 예제를 참고하십시오.

procedure TForm.ZoomImage;
var Bitmap: TBitmap;
   DstRect: TRect;
begin
      Bitmap := TBitmap.Create;
      Bitmap.Width := { 원하는 길이 }
      Bitmap.Height := { 원하는 높이 }
      Bitmap.Canvas.StretchDraw(Bitmap.Canvas.ClipRect,{원하는 이미지});

      Image1.Picture.Graphic := Bitmap;
      Image1.Invalidate;
end;

 

<아이콘을 Glyphs으로 바꾸려면>

다음을 프로그램 하여 보십시오.

unit Procs;

interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms,StdCtrls, Buttons, ExtCtrls, ShellAPI;

procedure LlenaBoton(boton: TSpeedButton; Programa: string);
procedure LimpiaBoton(boton: TSpeedButton);

var
{Botones de programas}
Pic: TPicture;
Fname : String;
TempFile: array[0..255] of Char;
Icon : TIcon;

implementation
uses ttotro;

procedure LlenaBoton(boton: TSpeedButton; Programa: string);
var
NumFiles, NameLength : integer;
nIconsInFile : word;
rBoton : TRect;
oBitmap : TBitmap;
oBitmap2: TBitmap;
NombreBitmap: string;

begin

try
screen.cursor := crHourglass;

{Extrae el Icono}
Icon := TIcon.Create;
StrPCopy(TempFile, Programa);
Icon.Handle := ExtractIcon(HInstance, TempFile, 0);

{Crea una instancia de TPicture}
Pic := TPicture.Create;
{Asigna el icon.handle a la propiedad Pic.icon}

Pic.Icon := Icon;

{Configura el tamano del bitmap como el del icono y el del segundo bitmapcon el tamano del boton}
oBitmap := TBitMap.create;
oBitmap2 := TBitMap.create;
oBitmap2.Width := Icon.Width;
oBitmap2.Height := Icon.Height;
oBitmap.Width := boton.Width-4;
oBitmap.Height := boton.Height-4;

{ Dibuja el icono en el bitmap }
oBitmap2.Canvas.Draw( 0, 0, Pic.Graphic );
rBoton.left := 1;
rBoton.Top := 1;
rBoton.right:= boton.Width-6;
rBoton.Bottom := boton.Height-6;
oBitmap.Canvas.StretchDraw(rBoton, oBitmap2);

Boton.Hint := Programa;

NombreBitmap := Copy(programa, 1, Length(programa)-3)+'BMP';
{Salva el bitmap en un fichero}
If Not FileExists(NombreBitmap) Then
begin
oBitmap.SaveToFile(ExtractFilePath(Application.ExeName)+ExtractFileName(NombreBitmap));
Boton.Glyph := oBitmap;
end
else
{Carga el BMP en el boton}
Boton.Glyph.LoadFromFile(ExtractFilePath(Application.ExeName)+ExtractFileName(NombreBitmap));

finally
Icon.Free;
oBitmap.Free;
oBitmap2.Free;
screen.cursor := crDefault;
end;
end;

procedure LimpiaBoton(boton: TSpeedButton);
var
oBitmap : TBitmap;
rBoton : TRect;
begin

try
{Configuara el tamano del bitmap como el del icono y el del segundo
bitmap con el tamano del boton}
oBitmap := TBitMap.create;
oBitmap.Width := boton.Width-4;
oBitmap.Height := boton.Height-4;
Boton.Glyph := oBitmap;
finally
oBitmap.Free;
end;
end;

end.

 

<image component에 특정 application의 icon을 보이게 하는 방법>

Windows API인 ExtractIcon function을 이용하면 됩니다.

uses SHELLAPI;

Image1.Picture.Icon.Handle := ExtractIcon(Handle, 'C:\Delphi\Bin\Delphi.exe',0);

 

<날짜와 시간의 형식을 DD/MM/YY 에서 DDMMYYYY 로 바꾸려면>

다음 예제를 참고하십시오.

LongDate := FormatDateTime('ddmmyyyy', StrToDate(ShortDate));

위의 코드는 DD/MM/YY 와 같은 제어판의 날짜 형식을 형식문자열(여기서는 DDMMYYYY)로바꾸어줍니다.

 

<Date 또는 시간차이 구하는 법>

다음은 시간차이를 구하는 예제입니다.

procedure TForm1.MaskEdit2Exit(Sender: TObject);
begin
   MaskEdit2.Text := FormatDateTime('HH:MM', StrToTime(MaskEdit2.Text));
   Edit2.Text := FormatDateTime('HHMM', StrToTime(MaskEdit2.Text));
   if StrToTime(MaskEdit2.text) < StrToTime(MaskEdit1.text) then
      ShowMessage('From 시간보다 작습니다.')
   else
      MaskEdit3.Text := FormatDateTime('HH:MM', StrToTime(MaskEdit2.text) - StrToTime(MaskEdit1.text));
end;

다음은 날짜차이를 구하는 예제입니다.

procedure TForm1.MaskEdit5Exit(Sender: TObject);
begin
   MaskEdit5.Text := FormatDateTime('YYYY-MM-DD', StrToDate(MaskEdit5.Text));
   Edit5.Text := FormatDateTime('MMDDYYYY', StrToDate(MaskEdit5.Text));
   if StrToDate(MaskEdit5.text) < StrToDate(MaskEdit4.text) then
      ShowMessage('From 날짜보다 작습니다.')
   else begin
      MaskEdit6.Text := FormatDateTime('YYYY-MM-DD', StrToDate(MaskEdit5.text)- StrToDate(MaskEdit4.text));
      Edit6.Text := FloatToStr(StrToDate(MaskEdit5.text) - StrToDate(MaskEdit4.text));
   end;
end;

 

<number를 천단위로 분리해서 comma를 찍어주는 방법>

다음과 같이 하면 됩니다.

function FormatNumber(l: longint): string;
begin
   FormatNumber := FormatFloat('#,##0', StrToFloat(IntToStr(l)));
end;

 

<Application에서 사용되는 날짜형식을 특정한 format으로 고정하는 방법>

SysUtils Unit에 선언된 변수들을 원하는 특정값으로 주면 됩니다.
Application 전체에 원하는 형태로 날짜 format을 지정하려면 main form의 onCreateEvent에 다음과 같이 하면 됩니다.

ShortDateFormat := 'YY-MM-DD';
LongDateFormat := 'YYYY-MM-DD';

 

<윈도우/대화상자의 크기를 재지정 했을때, 버튼을 윈도우내의 하단에 자동적으로 정렬할 수 있는 방법>

TPanel을 생성한후, TPanel의 Align특성을 사용하여 하단에 정렬하십시오.
그리고 나서 이 Panel 위에 버튼을 위치 시키면 됩니다. 만약 Button만 나타내고싶은 경우 Panel의 특성중 Ctl3D를 'Off'로 설 정하시고, Bevels를 none' 으로Parentcolor를 True로 설정하면 됩니다.

 

<파라독스의 계산 필드에서 25.55 가 24.499999 가 되는 이유>

숫자의 소수점 자리수가 틀리면 그러한 잘못된 값을 줍니다.
다음과 같이 Round 함수나 str함수를 써서 자리수를 맞춰서 계산하시기 바랍니다.

SalesIncVAT:=round(SalesIncVAT*100)/100; {소숫점 둘째자리 수}

혹은

var
s : string;
begin
str(SalesIncVat:10:2,s); {10 자리수와 소수점 둘째짜리}
Label1.Caption:=s;
end ;

 

<금주가 몇번째 주인지 구하는 법 (윤년 계산법)>

다음 함수를 사용해 보십시오.

윤년을 계산하는 함수 :
function kcIsLeapYear( nYear: Integer ): Boolean;
begin
Result := (nYear mod 4 = 0) and ((nYear mod 100 <> 0) or (nYear mod
400 = 0));
end;


한달에 몇일이 있는지를 계산하는 함수 :
function kcMonthDays( nMonth, nYear: Integer ): Integer;
const
DaysPerMonth: array[1..12] of Integer = (31, 28, 31, 30, 31, 30, 31, 31,30, 31, 30, 31);
begin
Result := DaysPerMonth[nMonth];
if (nMonth = 2) and kcIsLeapYear(nYear) then Inc(Result);
end;


위의 두 함수를 써서 몇번째 주인지 계산하는 함수 :
function kcWeekOfYear( dDate: TDateTime ): Integer;
var
X, nDayCount: Integer;
nMonth, nDay, nYear: Word;
begin

nDayCount := 0;
deCodeDate( dDate, nYear, nMonth, nDay );
For X := 1 to ( nMonth - 1 ) do
nDayCount := nDayCount + kcMonthDays( X, nYear );

nDayCount := nDayCount + nDay;
Result := ( ( nDayCount div 7 ) + 1 );
end;

 

<Hint가 나타나는 속도를 빠르게 하는 방법>

TApplication의 property중 HintPause property를 이용하면 됩니다.기본값은 800 millisecond 입니다.

Application.HintPause := 100;

 

<실행중 Component를 생성하고 property를 주려면>

다음의 코드를 참고하십시오.

{component를 만듭니다.}
procedure TForm1.Button1Click(Sender: TObject);
begin
   SomeComponent:= TComponentClass(FindClass(Edit1.Text)).Create(Self);
   (SomeComponent as TControl).Parent := Self;
end;

{만들 수 있는 component의 유형}
procedure TForm1.FormCreate(Sender: TObject);
begin
   RegisterClasses([TButton, TEdit, TMemo, TLabel]);
end;

{component의 property를 주는 방법}
procedure TForm1.Button2Click(Sender: TObject);
var
   PropType: pTypeInfo;
   PropInfo: pPropInfo;
begin
   PropInfo := GetPropInfo(SomeComponent.ClassInfo, Edit2.Text);
   PropType := PropInfo^.PropType;
   case PropType^.Kind of
      tkInteger:
      SetOrdProp(SomeComponent, PropInfo,StrToInt(Edit3.Text));
      tkChar:
      SetOrdProp(SomeComponent, PropInfo, Ord(Edit3.Text[1]));
      tkEnumeration:
      SetOrdProp(SomeComponent, PropInfo, GetEnumValue(PropType,Edit3.Text));
      tkFloat:
      SetFloatProp(SomeComponent, PropInfo,StrToFloat(Edit3.Text));
      tkString:
      SetStrProp(SomeComponent, PropInfo, Edit3.Text);
   end;
end;

 

<실행 중 만든 컴포넌트에 설정한 기본값이 설정되지 않은 경우>

[Q] 실행중에 component 하나를 만들었습니다. 그런데 제가 사용한 기본값이 설정되지 않은 것 같습니다. 어떻게 해야 합니까?

[A] 그 component의 Create constructor에서 property의 기본값을 설정했는지 확인하십시오. 기존 property의 기본값은 실행중에 만든 component에는 적용되지않습니다.

 

<Run-Time시에 VCL 컴포넌트의 개체를 생성하려면>

다음의 코드는 Runtime시에 Form을 생성하는 것입니다.

with TPasswordForm.Create(Application) do
Begin { i.e TForm1, TPasswordForm etc. }
ShowModal; { Diaplay form as a modal window }
Free; { Free the form when it is closed }
end;

다음의 코드는 Button을 생성하는 것입니다.

Var
TempButton : TButton; {This is only a pointer to a TButton }
Begin
TempButton := TButton.Create(Self);
TempButton.Parent := Self; { Must assign the Parent }
TempButton.Caption := 'Run-time';{ Assign properties new }
TempButton.Visible := True; { Show to button }
End;

이 개체는 사용후에 반드시 Free 시켜야 합니다.

 

<'Tab Order 설정방법>

Control을 정하기위해 Form에서 클릭한후 Object Inspector에서 TabOrderproperty를 설정해 줍니다.

 

<이름에 의해서 component를 access 하기>

FindComponent method를 사용하면 됩니다.

for I := 1 to 10 do
with Form1.FindComponent('SpeedButton' + IntToStr(i)) as TSpeedButton do
Enabled := False;

 

<Lasso 제어>

다음을 참고하십시오.

1. 폼의 OnMouseDown 이벤트:
bMarquee := True; {bMarquee는 Boolean변수}
ptOrigin := Point( X, Y );
ptMove := Point( X, Y );{ptOrigin, ptMove는 Point변수}

Canvas.Pen.Color := clBlack;
Canvas.Pen.Width := 1;
Canvas.Pen.Style := psDash;
Brush.Style := bsClear;

DrawMarquee(ptOrigin, ptMove, pmNotXor );

2. 폼의 OnMouseMove 이벤트
if bMarquee = True then begin
   DrawMarquee(ptOrigin, ptMove, pmNotXor );
   DrawMarquee(ptOrigin, Point( X, Y ), pmNotXor );
   ptMove := Point( X, Y );
   Canvas.Pen.Mode := pmCopy;
end;

3. 폼의 OnMouseUp 이벤트
if bMarquee = True then begin
   bMarquee := False;
   DrawMarquee(ptOrigin, Point( X, Y ), pmNotXor );
   ptMove := Point( X, Y );
end;

4. DrawMarquee procedure

procedure myForm.DrawMarquee( mStart, mStop : TPoint; AMode : TPenMode);
begin
   Canvas.Pen.Mode := AMode;
   Canvas.Rectangle( mStart.X, mStart.Y, mStop.X, mStop.Y );
end;

 

<inline Assembler 코드를 사용하려면>

다음은 시스템의 시간을 맞추는 예제입니다.

procedure TForm1.Button1Click(Sender: TObject);
begin
   {set system time}
   asm
      mov Ah,2dh { function number}
      mov ch,1 { hours }
      mov cl,10 { minutes }
      mov dx,0 { seconds }
      INT 21h
   end ;
end;

 

'Delphi' 카테고리의 다른 글

날짜/시간형식 변경 및 강제 시간세팅  (0) 2014.02.13
Q&A 정리  (0) 2014.02.13
Tip 정리  (0) 2014.02.13
올림 / 내림(버림)  (0) 2011.08.03
델파이의 소숫점 반올림 방식  (2) 2011.08.03
동적 체크박스 생성  (0) 2010.03.24
Trackback 0 Comment 0
2009. 11. 24. 17:18

델파이의 개요

1. 델파이란

(1) RAD(Rapid Application Development) Tool이다.
델파이는 최상의 윈도우 개발 환경을 지원한다. Delphi는 분산된 엔터프라이즈 및 웹에서 운용 가능한 가장 종합적이고 시각 적인, 고성능의 Client/Sever 응용프로그램 개발툴이다. Delphi에서 제공하는 다양한 도구는 리모트 서버 시스템, 그리고 랩 탑 컴퓨터 및 웹 브라우저와 같은 다양한 시스템을 구성할 때 가벼운 클라이언트 응용프로그램 환경을 제공할 뿐만 아니라 확 장성과 유연성을 동시에 갖는다.
Delphi 자체가 Delphi 언어(Object Pascal)로 작성되었으며, 전체환경 은 하나의 델파이 응용프로그램이다.
 

(2) 빠른 통신 기능 및 분배 그리고 확장성

(3) CORBA를 이용한 전사적 데이터 통합

(4) 어떠한 데이터도 언제나 어느 곳에서도 유연한 접속 처리
프로그래머라면 모두 아는 바와 같이 많이 사용되고 있는 RAD 도구로 Visual Basic이 있다. 델파이와 비주얼베이직을 살펴보면 개발환경이 거의 비슷하다는 것을 느낄 수 있다. 두 제품은 마치 형제처럼 보인다. 단지 내부 문법이 다를 뿐이지 외형은 너무 비슷하다. 볼랜드 사가 델파이를 만들게된 동기를 다음과 같이 유추해 볼수 있을 것이 다. 마이크로소프트 사는 윈도우(Windows3.1) 환경에 새로운 기법으로 프로그램을 작성할 수 있는 새로운 형태의 언어를 비주 얼 베이직으로 개발해 출시했고 터보 C로 유명하던 볼랜드사도 이에 자극을 받아 델파이라는 제품을 개발하게 되었을 것이다. 그런데 기본이 되는 언어를 무엇으로 할것 인가에서 옛날에 각광을 받았든 쉬우면서도 강력했던 파스칼 언어를 채용한 것이다. 마이크로소프트 사가 배우기 쉬운 QBASIC을 그대로 사용하면서 객체 개념을 추가하니 볼렌드에서도 파스칼 언어에 객체 기법을 포함한 객체 지향 파스칼 언어(Object Pascal Language)를 사용했다. 지금까지 교육용 언어로 가장 많은 지지를 얻고 있던 파스칼 언어가 비주얼베이직을 이길 수 있을 것이라고 확신하였을 것이다. 


2. 델파이의 성능

성능을 이야기하려면 다른 RAD 제품과 비교해 보는 것이 가장 알기 쉬운 방법이 될 것이다. 

컴파일 속도:
전반적인 컴파일 속도는 이전 버젼(3.0)에 비해 느려졌다. 그러나 체감 속도를 비교했을 때 VB나 PB보다 약간 빠른 것으 로 평가된다. 실제로 델파이는 순수한 컴파일러방식 이기 때문에 다른 RAD계열의 툴보다 빠른 속도를 보인다.
 

실행파일크기:
기장 기본적인 폼을 이용해 창(윈도우)를 화면에 출력하는 형태의 프로젝트를 생성할 경우(단, 컴파일 옵션에서 디버깅 정보를 제외하고 컴파일한 후에 생성된 실행파일의 크기를 기준) 델파이는 별도의 런타임(Run-Time) 라이브러리가 필요하지 않으므로 275KByte이다. 하지만 VB는 생성된 프로젝트 크기16,384Byte 에다 배포용 해당 컨트롤까지 모두 복사해야 하므로 기계어방식으 로 컴파일하든 인터프리터 방식으로 컴파일하든 2MByte의 크기가 넘게 된다. PB도 VB와 비슷하다. 배포해야 할 DLL(PBVM60.DLL) 파일의 크기가 3MB가 넘는다.

Win32 API 지원:
델파이4.0은 Window API를 완벽하게 지원한다. 이점 때문에 C언어에서 파스칼로 포팅이 용이하다. VB은 포인터와 유니온(Union) 의 부재로 인한 모든 API를 100% 사용은 불가능하다. AddressOf 연산자를 이용해 CallBack 함수의 사용이 5.0버젼부터 지원되지 만 6.0버젼에서는 쓰레드 관련 API에서 문제가 보이고 있다. 반면에 Win32 타입 라이브러리를 이용하면 아주 손쉽게 API를 사용 할 수 있기도 하다. PB는 포인터가 없어서 모든 API와 100% 호환이 불가능하다. Win32 API를 사용하는데 문제는 없지만 RECT와 같은 구조체를 자체적으로 지원하지 않아서 사용자가 직접 정의해 사용해야 하는 불편함이 있다.

포인터지원:
델파이4.0부터는 자체적인 지원으로 기존의 DB툴을 사용하지 않고 단지 링크드리스트(Linked List)나 더블 링크드 리스트(Double Linked List) 같은 자료구조용 알고리즘을 이용한 데이터베이스 구축이 가능하다. 이것으로 인해 게임 제작이시 유용성이 크다. VB는 자체 포인터 개념이 없다. MS사는 VB를 최대한 안정성에 역점을 두고 제작했기 때문에 포인터를 제공하지 않았다고 한다. PB도 포인터를 사용할 수 없다. 그러나 구조체나 배열을 이용하면 어느 정도 포인터를 대신한 역할이 가능하다.

다양한 컴포넌트 지원:
매우 편리하고도 다양한 컴포넌트를 지원한다.


3. 델파이의 장점

멀티-티어(Multi-Tier) DB 아키텍처 마이다스(MIDAS):
100개 이하의 DB클라이언트를 관리하는 경우 C/S 모델의 2-티어 만으로 충분하겠지만, 1천 개 또는 1만 개 이상의 클라이언트가 접속하면 병목현상이 일어난다. 델파이에서는 미들 서버를 통해 DB서버의 부하를 줄이고 자원을 효율적으로 관리함으로써 보다 많은 클라이언트의 연결을 가능하게 하는 마이다스 아키텍처를 제공한다. 마이다스는 DCOM,CORBA, OLEnterprise, Socket 등 많은 프로토콜을 제공하며 부분적으로 균형과 실패 복구(Fail-over) 기능을 지원하다.

CORBA 지원:
개발환경에서 CORBA 지원이 잘 통합되어 있는 유일한 개발 툴(RAD 툴中)이다. CORBA 객체와 멀티-티어를 위한 DB CORBA 서버 객 체(Data Module)를 생성하는 위저드를 제공한다.

인라인 어셈블리(Inline Assembly):
소소코드에 어셈블리어를 포함시켜 컴파일할 수 있기 때문에 속도를 원하거나 보다 직접적인 제어가 필요한 부분은 에셈블리어 를 사용해서 최적화할 수 있다. 델파이 런타임 라이브러리의 많은 부분이 인라인 어셈블리로 코딩되어 있어서 델파이의 응용프 로그램은 그만큼 빠르다.

순수한 컴파일러방식:
순수한 컴파일러 방식을 사용하기 때문에 VCL(Visual Component Library)이 없이도 자체 언어와 Window API 함수만으로도 윈도 우용 응용프로그램을 제작할 수 있으며 또한 C언어와 유사한 점이 많아서 C로 작성된 프로그램을 파스칼로 포팅이 가능하다.
 

독자적인 실행 파일:
별도의 배포용 동적연계라이브러리(DLL: Dynamic Linked Library)가 없이 실행 파일만으로 완전 동작을 한다. 다만, 데이터베이 스사용시 볼랜드 데이터베이스 엔진(BDE)을 사용한 경우 실행 파일과 함께 BDE를 배포해야 한다.


4. 델파이의 단점

한글지원이 없다:
소스코드에서 문제가 없는 한글이 실행 파일로 가면서 문제가 발생 될 수도 있으며 변수나 속성 등을 한글로 사용할 없다.
한글 처리가 취약한 편이다. 

자체분석/설계 모델링 툴이 없다:
최근 들어서 대부분의 개발툴은 자신이 작성한 응용프로그램의 분석,설계에 관한 모델링 툴을 지원하고 있다.

로컬 SQL은 다음의 경우 테이블(Table)의 수정이 불가능하다:
3개 이상의 테이블을 조인(Join)한 경우.
UNION, INTERSECT 또는 MINUS를 사용한 경우.
서브 쿼리(Sub Query)를 사용한 경우.
색인이 없는 데이터베이스의 필드를 Order By 구문에 사용한 경우.

 
5. 델파이 프로그램의 개발 방법

(1) 시스템 분석과 설계

(2) 화면(Form) 디자인
화면에 출력할 사용자 인터페이스를 디자인한다.

(3) 컴포넌트 배치 및 속성 설정
이것에 배치할 각종 컴포넌트 종류와 기능을 사용자가 숙지해야 한다.

(4) 코딩
델파이는 코드 작성을 쉽게 하도록 마련한 여러 가지 위저드와 도우미가 있다.
이런 것들을 이용해서 코딩하면 보다 편리한 작업 환경에서 프로그램을 작성할 수 있다.

(5) 컴파일 및 테스트
프로그램을 컴파일하고 에러를 수정한다.

(6) 실행
프로그램을 실행한다.

'Delphi' 카테고리의 다른 글

단축키 모음  (0) 2010.03.22
TDateTime형 - 3  (0) 2009.12.01
TDateTime형 - 2  (0) 2009.12.01
TDateTime형 - 1  (0) 2009.12.01
델파이의 데이터형  (0) 2009.11.24
델파이의 개요  (0) 2009.11.24
Trackback 0 Comment 0