2013-07-12 4 views
1

사용자 정의 레코드를 사용하여 포인터 주위에 머리를 가져 와서 레코드 배열을 만든 다음 해당 레코드에 대한 포인터를 만들 수 없습니다. 구체적으로는 각 최상위 창에 대한 레코드를 만드는 것입니다 주어진 클래스 이름으로 처리합니다. 각 윈도우에 대해 하나 이상의 의미가 있습니다. EnumChildWindow을 사용하여 하위 윈도우 핸들을 얻습니다. 각각의 레코드를 만들고 제목이있는 콤보 박스에 전달하고 레코드를 만들고 싶습니다. 해당 항목의 객체이므로 나중에 각 항목을 선택하여 액세스 할 수 있습니다.델파이 포인터, 배열, 핸들

내 문제는 포인터 처리 중입니다. 배열 레코드 중 하나를 추가하는 첫 번째 인스턴스에서 계속 액세스가 거부됩니다. 여기

휴식

Param[Form1.iEnumWin].MainHwnd:= aHwnd; 

는 여기에 지금 사람들이 내가 뭘하려고 오전에 대한 더 나은 이해를 얻을 수 있습니다 사용하고있는 전체 코드입니다. 사람이 올바른 방향으로 (의도 웃기) 날 지점 수없는 경우

implementation 

{$R *.dfm} 
type 
    TMyEnumParam = record 
    sTitle: String; 
    MainHwnd: Hwnd; 
    InTxtHwnd: Hwnd; 
    OutTxtHwnd: Hwnd; 
    NickListHwnd: Hwnd; 
end; 
PMyEnumParam = ^TMyEnumParam; 

type 
ATMyEnumParam = Array[0..9] of PMyEnumParam; 
PATMyEnumParam = ^ATMyEnumParam; 

{ Get the window Title based on Hwnd } 
function GetWindowTitle(HWND: HWND): string; 
begin 
    SetLength(Result, 255); 
    SetLength(Result, GetWindowText(HWND, PChar(Result), 255)); 
end; 

{ Get the Classname based on Hwnd } 
function GetWindowClass(HWND: HWND): string; 
begin 
    SetLength(Result, 255); 
    SetLength(Result, GetClassName(HWND, PChar(Result), 255)); 
end; 

{ EnumChildWidows Callback Add to our records } 
Function EnumChildProc(aHwnd: Hwnd; Param: PMyEnumParam): Boolean; stdcall; 
begin 
    if ((GetDlgCtrlID(aHwnd) = 202) and (isWindowVisible(aHwnd) = True)) then 
     Param.InTxtHwnd:= aHwnd; 

    if ((GetDlgCtrlID(aHwnd) = 203) and (isWindowVisible(aHwnd) = True)) then 
     Param.OutTxtHwnd:= aHwnd; 

    if ((GetDlgCtrlID(aHwnd) = 1789) and (isWindowVisible(aHwnd) = True)) then 
     Param.NickListHwnd:= aHwnd; 

     Result:= True; 
end; 

{ EnumWindow fill our array of records for each window } 
function EnumWindowsProc(aHwnd: HWND; Param: PATMyEnumParam): BOOL; stdcall; 
begin 
    Result := True; 
    if GetWindowClass(aHwnd) = 'DlgGroupChat Window Class' then 
    begin 
    Param[Form1.iEnumWin].MainHwnd:= aHwnd; 
    Param[Form1.iEnumWin].sTitle:= GetWindowTitle(aHwnd); 
    EnumChildWindows(aHwnd, @EnumChildProc, LParam(@Param[Form1.iEnumWin])); 
    Form1.cbbRooms.AddItem(Param[Form1.iEnumWin].sTitle, TObject(Param[form1.iEnumWin])); 
    inc(Form1.iEnumWin); 
    end; 
end; 

{ On change display room Title for each item } 
procedure TForm1.cbbRoomsChange(Sender: TObject); 
var 
    i: Integer; 
    aHwnd: PMyEnumParam; 
begin 
    i := cbbRooms.ItemIndex; 
    if cbbRooms.ItemIndex <> -1 then 
    begin 
    aHwnd:= PMyEnumParam(cbbRooms.Items.Objects[i]); 
    if aHwnd.MainHwnd > 0 then 
    begin 
    ShowMessage(aHwnd.sTitle); 
    end; 
    end; 

end; 

{ Call EnumWindows and fill our array records } 
procedure TForm1.FormCreate(Sender: TObject); 
var 
arInfo: PATMyEnumParam; 
begin 
    iEnumWin:= 0; 
    EnumWindows(@EnumWindowsProc, LParam(@arInfo)); 
end; 

나는 감사하게 될 것이다.

+0

뻔뻔한 플러그이지만 포인터가 없어지면 http://rvelthuis.de/articles/articles-pointers.html을 읽어보십시오. 데이빗은 이미 당신의 코드에 무엇이 잘못되었는지를 말했습니다. –

답변

4

코드에 많은 문제가 있습니다. 여기가 아닌 완전한 목록은 다음과 같습니다

  1. 당신은 당신은 ^PATMyEnumParam 그런 다음 콜백 PATMyEnumParam로 캐스팅하는 EnumWindows에 합격하여 arrays.2
  2. 에 대한 모든 스토리지를 할당하지 않습니다.
  3. 배열의 길이는 고정되어 있으며 배열에 대한 범위를 벗어난 액세스를 처리하려고 시도하지 않습니다.

하지만 가장 큰 문제는 걸을 수 있기 전에 코드가 실행되고 있다는 것입니다. 완전한 복잡성과 필요한 모든 기능을 갖추고 있습니다. 그러나 EnumWindows 번으로 성공적으로 전화를 걸 수는 없습니다.

가장 큰 조언은 여기에 자세히 나와 있지 않지만 문제 해결의 일반성입니다. 간단한 코드를 작성하는 것으로 시작하십시오. 그것을 이해하다. 그런 다음 그것을 강화하십시오.

그래서, 정맥, 여기 EnumerateWindows에 전화를 만드는 방법입니다 : 모든 까다로운 부분이 이미 알아서하기 때문에

program EnumWindowsDemo_17620346; 

{$APPTYPE CONSOLE} 

uses 
    System.SysUtils, Winapi.Windows, Generics.Collections; 

type 
    TWindowInfo = record 
    Handle: HWND; 
    // expand with more fields in due course 
    end; 

function EnumWindowProc(hwnd: HWND; lParam: LPARAM): BOOL; stdcall; 
var 
    WindowList: TList<TWindowInfo>; 
    WindowInfo: TWindowInfo; 
begin 
    WindowList := TList<TWindowInfo>(lParam); 
    WindowInfo.Handle := hwnd; 
    WindowList.Add(WindowInfo); 
    Result := True; 
end; 

procedure Main; 
var 
    WindowList: TList<TWindowInfo>; 
    WindowInfo: TWindowInfo; 
begin 
    WindowList := TList<TWindowInfo>.Create; 
    try 
    EnumWindows(@EnumWindowProc, LPARAM(WindowList)); 
    for WindowInfo in WindowList do 
     Writeln(WindowInfo.Handle); 
    finally 
    WindowList.Free; 
    end; 
end; 

begin 
    Main; 
    Readln; 
end. 

, 당신은이 개념을 확장 할 수 있습니다 여기에서 시작. 특히 포인터, 캐스팅 및 메모리 관리.

+0

고마워요. 내가하고 싶은 것을 알았습니다. 포인터와 메모리 관리가 실패라고 말했을 때, 저는 정상적으로 이것들을 멀리하고 델파이를 저에게 처리되도록 사용하고 있습니다. hobbyist 프로그래머 나는 메모리를 다룰 때 배울 점이 많다. EnumWindow와 EnumChildWindows를 문제없이 사용하고 매개 변수를 전달하지 않기 때문에 실제 메모리 관리가 필요하지 않다. 다시 한번 감사 드리지만, 이제 TList를 사용하여 레코드를 할당하는 방법을 보게되면 훨씬 더 흥미 롭습니다. – Departure

+0

TList 의 큰 장점은 메모리 할당에 대해 걱정할 필요가 없다는 것입니다. –

+1

David이 맞습니다. 작은 조각을 씹어 서 질식시키지 않아도됩니다 ... –