procedure WaitForWindowDestroy(lpClassName, lpWindowName: PChar); var H: HWND; Value: DWORD; begin H := FindWindow(lpClassName, lpWindowName); if H = 0 then raise Exception.Create('FindWindow failed');
GetWindowThreadProcessId(H, @Value); H := OpenProcess(PROCESS_ALL_ACCESS, False, Value); if H = 0 then raise Exception.Create('OpenProcess failed');
try GetExitCodeProcess(H, Value); while Value = STILL_ACTIVE do GetExitCodeProcess(H, Value); finally CloseHandle(H); end; end;
TCanvas 에는 TextWidth, TextHeight 가 있어 폭과 높이를 구할 수 있다. TListBox, TListView, TStringGrid 등에서 CustomDraw 를 할 경우 텍스트 위치를 잡아주기 위해 필요한 정보다. 그 함수를 들여다 보면 둘 모두 TextExtent 를 호출하여 가로, 세로 폭을 얻은 뒤 한 쪽 정보만을 넘겨준다. 한 쪽 정보만 필요하다면 어차피 같겠지만 가로, 세로 모두 필요한 경우 저 두 함수를 호출 하면 크기 정보를 두번 가져오게 된다. 그냥 TextExtent 를 직접 호출 하여 TSize 형태의 정보로 가져온 뒤 값을 참조 한다면 쓸데없는 호출은 줄일 수 있다.
설명 TComponentState 는 TComponent 인스턴스의 ComponentState 속성의 가능한 상태 집합을 정의한다. 아래 표는 TComponentState 유형과 각 표시 문자에 대응하는 의미의 목록을 보여준다.
표시 문자: 컴포넌트 상태 csAncestor: 컴포넌트가 조상 폼에 삽입되었다.csDesigning 이 설정된 상태에서 설정된다. csDesigning: 컴포넌트가 폼 위에 있고 폼 디자이너에 의해 조정됨. csDestroying: 컴포넌트가 소멸 될 때. csFixups: 컴포넌트가 로드되지 않은 다른 폼의 컴포넌트와 연결되었음. 이 표시는 모든 연결이 해결되었을 때 지워진다. csFreeNotification: 하나 이상의 컴포넌트들이 이 컴포넌트가 파괴될 때 알려달라고 요청하였다. 이 표시 문자는 다른 컴포넌트가 이 컴포넌트의 FreeNorification 메소드를 호출할 때 설정된다. csInline: 컴포넌트가 최상위 컴포넌트로 디자인 시에 수정할 수 있고 또한 폼에 넣을 수 있다. 이 표시문자는 읽거나 쓰는 중에 포함된 프레임을 식별하기 위해 사용된다. csLoading: filer 객체가 현재 컴포넌트를 로드하고 있다. 이 표시 문자는 컴포넌트가 처음 생성되고 컴포넌트와 이에 포함된 자식 컴포넌트들이 초기화 되지 않았을 때 까지 설정된다. (Loaded 메소드가 호출되었을 때). csReading: 스트림에서 속성 값을 읽고 있는 상태. 참고로 csReading 이 설정되었을 때 csReading 이 항상 설정된다. 다시 말하면, csReading 은 컴포넌트가 불러오는 중 속성 값을 덮어 쓰는 시간의 부분 구간에서 설정한다. csUpdating: 컴포넌트가 조상 폼의 변화를 반영하기 위해 갱신된다. csAncestor 가 설정된 상태에서 설정된다. csWriting: 속성 값을 스트림에 쓰고 있는 상태. csDesignInstance: 컴포넌트가 디자이너에서 뿌리 객체다. 예를 들어, it is set for a frame when you are designing it, but not on a frame that acts like a component. 이 표시 문자는 csDesigning 과 함께 나타난다.
오늘 SendMessage 의 Param 의 형태가 C++, Delphi 언어마다 다르다는 소리에 발끈해 뒤졌다. 도대체 API 함수인데 어떻게 다를 수가 있고, Delphi 는 포팅해서 쓴다는 소리는 뭐냐고, Windows 유닛에 뻔히 있는데 다른데 있다니...
글 아래의 자료는 거슬러 올라가며 관련 선언을 다 모아 놓은 것이니 참고하시길... 결론은 SendMessage 의 Param 은 둘다 32-bit unsigned integer 다.
무슨 에러가 났네 어쩌내 해대서 더 찾아봤더니... VCL 의 메세지 처리 프로시저의 매개변수인 TMessage 의 Param 들은 32-bit signed integer 형이다.
-2147483648..2147483647 signed 32-bit 0..4294967295 unsigned 32-bit
2147483647 이상의 값은 TMessage 로 받아보면 음수가 되는 것이다. 그 상황은 아마 signed 와 unsigned 를 비교해 놓고 안되네 어쩌네 한 것이겠지... 답답하다.
SendMessage 는 32비트의 자료를 안전하게 전송해 줬는데 자료 이용을 잘 못하고... 이 글을 보는 이들은 이런 실수 하지마시길...
피해가려면 VCL 의 메세지 맵을 쓰지 말고 CALLBACK 프로시저를 하나 만들어서 Sub-Classing 하세요. 직접 unsigned 형으로 받으면... 그래도 실수할 수 없겠지. ㅋ
// SendMessage WINUSERAPI LRESULT WINAPI SendMessageA(IN HWND hWnd, IN UINT Msg, IN WPARAM wParam, IN LPARAM lParam); WINUSERAPI LRESULT WINAPI SendMessageW(IN HWND hWnd, IN UINT Msg, IN WPARAM wParam, IN LPARAM lParam); #ifdef UNICODE #define SendMessage SendMessageW #else #define SendMessage SendMessageA #endif // !UNICODE
// TMessage typedef unsigned short Word; // 0..65535
#pragma pack(push, 1) struct TMessage { unsigned Msg; union { struct { Word WParamLo; Word WParamHi; Word LParamLo; Word LParamHi; Word ResultLo; Word ResultHi; }; struct { int WParam; int LParam; int Result; };
}; }; #pragma pack(pop)
// Define Cardinal 32-bit unsigned integer unsigned int typedef long [int]; When used to modify an int, it doubles the number of bytes available to store the integer value. 32-bit integer.
// SendMessage function SendMessage; external user32 name 'SendMessageA'; function SendMessageA; external user32 name 'SendMessageA'; function SendMessageW; external user32 name 'SendMessageW';
컴포넌트 제작시에 ComponentEditor, PropertyEditor 를 만들어 주게되면 런타임 패키지(Editor 를 제외한 순수 컴포넌트 모음), 디자인 패키지(Editor 모음) 로 나눠 주어야한다. 그렇지 않으면 Proxies.dcu(Delphi), Proxies.obj(C++Builder) 를 달라고 떼쓴다.
그런데 대충 연습 코딩중인데 열심히 해놓고 확인하려할 때 저 에러를 만나면 귀찮아진다. 그래서 Proxies 유닛을 포함시켜다 놓고 해버렸다. Delphi 7 의 경우 Proxies.pas 를 포함시키면 된다. 이걸 C++Builder 에 포함시켰더니 끝끝내 Proxies.obj 를 달라길래 cpp 로 변환해 놨다.