2010-06-01 2 views
3

클래스 내부에서 WinAPI 콜백을 캡슐화하는 우아한 방법에 대해 생각하고 있습니다. 비동기 I/O를 처리하는 클래스를 만들고 있다고 가정합니다. 모든 Windows 콜백은 클래스 메서드가 아닌 stdcall 함수 여야합니다 (예 : ReadFileEx WinAPI 함수에 해당 주소를 전달해야 함). 그래서 메서드 주소를 WinAPI 함수에 대한 콜백 루틴으로 전달할 수는 없습니다.클래스 내에서 WinAPI 콜백을 캡슐화하는 가장 우아한 방법

클래스 내부에이 유형의 기능을 캡슐화하여 클래스에 OnReadCompleted 및 OnWriteCompleted 이벤트가 포함되도록하는 가장 우아한 방법은 무엇입니까? (기본 언어로 Delphi를 사용하지만 C++에서 상황이 같아야합니다. 클래스 메소드는 단순한 메소드와 다르다. 첫 번째 숨겨진 매개 변수는 링크이다. 물론이 클래스는 싱글 톤이 아니며 동시에 많은 앱을 만들 수있다.

이것을 구현하는 좋은 방법은 무엇이라고 생각하십니까?

답변

4

나는 이것이 어떤면에서는 결코 의심스럽지 않지만, IMO, the ea siest는 클래스의 메소드 주소를 프로 시저 주소로 변환하여 winapi로 전달하는 것입니다. 물론, 해킹이지만 VCL은 classes.MakeObjectInstance과 동일합니다 (특정 구문에만 해당).이 종류의 구현 및 상황을 처리하기위한보다 많은 OO 방법에 대해서는 source의 경우 this question을 참조하십시오.

+0

이 접근법이 (먼 미래에 64 비트 델파이 버전에서 작동하는지 궁금해합니다. (Proc 호출은 64에서 매우 다릅니다). 나는 정말로 그것을 의심한다. 그러나 지금 말할 방법이 없습니다. – ChristianWimmer

2

정적 인 키워드를 사용할 수 있습니다. 그러나 새로운 Delphi 버전에서만 사용 가능합니다. 이처럼

:

여기
type 
    TMyThread = class 
    private 
    // ... 

    class function ThreadProc(Param: Pointer): DWord; stdcall; static; // <- WinAPI call back 

    function Execute: DWord; // <- actual callback 
    public 
    constructor Create; 
    // ... 
    end; 

{ TMyThread } 

constructor TMyThread.Create; 
begin 
    // ... 
    FHandle := CreateThread(nil, 0, @ThreadProc, Self, 0, FID); 
end; 

class function TMyThread.ThreadProc(Param: Pointer): DWord; 
begin 
    Result := TMyThread(Param).Execute; 
end; 

function TMyThread.Execute: DWord; 
begin 
    MessageBox(0, 'Hello from thread', 'Information', MB_OK or MB_ICONINFORMATION); 
    Result := 0; 
end; 

:에 ThreadProc는 WinAPI를 콜백 루틴입니다. 그것은 Self를 통과 할 수있는 커스텀 아규먼트를 필요로합니다. 인스턴스 구성원을 액세스 할 수 없습니다. 그래서 실제 콜백 (Execute)을위한 래퍼이며, 클래스의 일부이며 해당 필드와 메소드에 액세스 할 수 있습니다.

+0

콜백 (Execute)이 WinAPI 콜백을 필요로하는 바이너리 서명과 동일한 바이너리 서명을 가질 수 있도록 보장한다면 래퍼 (ThreadProc)를 제거 할 수도 있습니다. 위의 예제에서 Execute에 "stdcall"을 추가하고 ThreadProc을 완전히 제거하여 @Execute를 CreateThread에 전달할 수 있습니다. 그러나 그것은 위험한 길입니다. – Alex

+0

고맙겠 습니다만, 제 수업은 싱글 톤이 아니며 응용 프로그램에이 클래스의 인스턴스가 많이있을 수 있습니다. 그래서, 정적 메서드 솔루션이 좋지 않습니다. 내가 어딘가에 저장할 수있는 경우가 아니면 콜백에 전달 된 것에 따라 메서드 포인터 목록을 호출해야합니다. –

+0

@FractalizeR 음 ... 왜 단 하나의 인스턴스 만 만들 수 있다고 생각합니까? 원하는 인스턴스를 원하는만큼 사용할 수 있습니다. 나의 예를 더주의 깊게 연구하십시오. 정확한 인스턴스가 저장됩니다. – Alex

관련 문제