VCL의 pravate, protected 멤버 접근하기
프로그램을 하다가 보면 종종 pravate 또는 protected멤버에 접근하고 싶을때가 있다.
private멤버에 접근하므로 빙~~ 돌아가야 할 코딩이 간단히 해결되는 경우가 있기 때문이다.
잘쓰면 유용하지만 잘못쓰면 위험할수도 있죠
델마당에 양병규님이 올린 자료와 댓글,
그리고 이곳 볼포 tip게시판의 김태선님과 박지훈님의 글들을 모아서 정리해본다.
방법1. 해당 Class를 상속받아 public으로 재 선언한다.
김태선님이 소개해준 방법으로 아래 링크에
TPanel의 protected 멤버인 Canvas를 public으로 쓰는 방법이 소개되어있다.
http://cbuilder.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_tip&no=546
class TCanvasPanel : public TPanel
{
public:
__property Canvas;
};
방법2. C++Builder사용자에게만 해당하는것으로 *.hpp파일을 열어서 해당 멤버를 public으로 재선언 해버린다.
이 방법은 박지훈.임프님께서 소재해준 방법입니다.
확실하고 편리하지만 위험할수도 있다.
http://cbuilder.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_tip&no=21
방법3. 델마당 양병규님이 소개해준 방법으로
class 의 특정 public멤버로 부터 접근하고자 한는 private의 멤버의 offset 값을 계산해서
포인터연산을 통해 접근하는 방식.
Screen의 FForms에 접근하여 특정 폼을 list에서 빼버리는 팁
http://www.delmadang.com/community/bbs_view.asp?bbsNo=3&bbsCat=0&st=&keyword=&indx=398161&keyword1=&keyword2=
procedure RemoveFromScreen(Form: TForm);
var
P: Pointer;
begin
P := @Screen.Cursor;
Inc( PChar(P), SizeOf( Pointer ) * 2 );
TList( P^ ).Remove( Form );
Inc( PChar(P), SizeOf( Pointer ) * 1 );
TList( P^ ).Remove( Form );
end;
근데 위 내용중 Screen.Cursor의 주소에 접근하는 과정에서
C++Builder에서는 에러가 난다.
int * pCur=(int *)&Screen->Cursor; //이와같이 할경우...
TCursor *pCur2=(TCursor *)&Screen->Cursor; //또는...
에러메세지 : E2027 Must take address of a memory location
C++Builder 에서
&Screen->Cursor 가져오는데 error가 난다면 Screen 객체 처음부터 offfset을 계산해서 할수 있다.
void __fastcall TForm1::Button4Click(TObject *Sender)
{
int *iScr=(int *)Screen;
TList* FForms=(TList *)(*(iScr+19));
for(int i=0;iCount;i++)
{
ShowMessage(((TForm *)FForms->Items[i])->ClassName());
}
}
//---------------------------------------------------------------------------
C++Builder 6.0에서는
Screen과 Screen->FForms의 offset이 0x4C 즉 76Byte 이다. ( 19*4 =76 )
C++Builder 2007에서도 괜찮음
offset을 이용한 방식은 vcl이 아니라도 여러방면에서 매우 유용한다.
방법4. 붕어빵 클래스를 만드는데. 접근을 원하는 멤버르 public으로 해서 ..만들어
객체를 cast해서 접근하는 방식임
( 양병규님글의 댓글에 있었던 내용)
C++Buider로 하면 아래와 같은 방식으로 할수있다.
class TMyScreen : public Classes::TComponent
{
typedef Classes::TComponent inherited;
public:
Classes::TStrings* FFonts;
Classes::TStrings* FImes;
AnsiString FDefaultIme;
HKL FDefaultKbLayout;
int FPixelsPerInch;
Controls::TCursor FCursor;
int FCursorCount;
Classes::TList* FForms;
Classes::TList* FCustomForms;
Classes::TList* FDataModules;
Classes::TList* FMonitors;
TCursorRec *FCursorList;
HICON FDefaultCursor;
};
//---------------------------------------------------------------------------
void __fastcall TForm1::Button5Click(TObject *Sender)
{
TMyScreen *Scr=(TMyScreen *)Screen;
for(int i=0;iFForms->Count;i++)
{
ShowMessage(((TForm *)Scr->FForms->Items[i])->ClassName());
}
}
//---------------------------------------------------------------------------
헤헤.. 잘 쓰면 유용하고
잘못쓰면... 독이될수도..
그럼..