2017-03-11 34 views
3

スレッド内からWM_POWERBROADCAST Windowsメッセージを受信する方法を理解しようとするリソースがたくさんあります。スレッド内でWM_POWERBROADCASTを受け取る方法は?

現在、私はスタンドアロンコンポーネントの内部にAllocateHWnd(WndMethod)を使用しています。標準のVCLフォームアプリケーションで上記コンポーネントのインスタンスを作成すると、すべて正常に動作し、必要に応じて毎回WM_POWERBROADCASTというメッセージが表示されます。

しかし、TThreadの中から非常に同じコンポーネントのインスタンスを作成すると、この特定のWindowsメッセージは受信されません。私はあらゆる種類の他のメッセージを受けています。このメッセージはありません。

解決策を探しているうちに、このメッセージを受け取るためにWindowsサービスがいくつかの追加作業を必要とする方法に関連する多くのリソースが見つかりました。しかし、少なくとも私はまだサービスを利用していません。私はまた、このメッセージを受け取るためにスレッドがメッセージループを持っている必要があり、私はimplemented a thread from another answer hereでしたが、この特定のメッセージを受け取ることはないということを、2人の人が分かりました。

以下は、このメッセージをどのように受け取っているかを示す完全なコンポーネントです。これは、これがVCLアプリケーションのメインスレッド内にある場合、完全に機能します。私は、メインスレッドがこのメッセージを受け取ってスレッドに転送する必要があると推測しています。

TThreadの内部には、WM_POWERBROADCASTというメッセージが表示されるようにするにはどうすればよいですか?私はWM_POWERBROADCASTが投稿されていませんので、これは私が必要なもの、実際にはないと確信しているが、前述のように、他の回答に基づいて

さらに
unit JD.Power.Monitor; 

(* 
    JD Power Monitor 
    by Jerry Dodge 

    Purpose: To monitor the current state of power on the computer, and trigger 
    events when different power related changes occur. 

    Component: TPowerMonitor 
    - Create an instance of TPowerMonitor component 
    - Choose desired power settings to get notified of using Settings property 
    - Implement event handlers for those events you wish to monitor 
    - Component automatically takes care of the rest of the work 
*) 

interface 

uses 
    System.Classes, System.SysUtils, System.Generics.Collections, 
    Winapi.ActiveX, Winapi.Windows, Winapi.Messages; 

type 
    TPowerSetting = (psACDCPowerSource, psBatteryPercentage, 
    psConsoleDisplayState, psGlobalUserPresence, psIdleBackgroundTask, 
    psMonitorPower, psPowerSaving, psPowerSchemePersonality, 
    psSessionDisplayStatus, psSessionUserPresence, psSystemAwayMode); 
    TPowerSettings = set of TPowerSetting; 

    TPowerSource = (poAC, poDC, poHot); 

    TPowerDisplayState = (pdOff, pdOn, pdDimmed); 

    TPowerUserPresence = (puPresent = 0, puInactive = 2); 

    TPowerSavingStatus = (psSaverOff, psSaverOn); 

    TPowerAwayMode = (paExiting, paEntering); 

    TPowerPersonality = (ppHighPerformance, ppPowerSaver, ppAutomatic); 

    TPowerMonitorSettingHandles = array[TPowerSetting] of HPOWERNOTIFY; 

    TPowerQueryEndSessionEvent = procedure(Sender: TObject; var EndSession: Boolean) of object; 

    TPowerEndSessionEvent = procedure(Sender: TObject) of object; 

    TPowerSettingSourceChangeEvent = procedure(Sender: TObject; 
    const Src: TPowerSource) of object; 

    TPowerSettingBatteryPercentEvent = procedure(Sender: TObject; 
    const Perc: Single) of object; 

    TPowerSettingDisplayStateEvent = procedure(Sender: TObject; 
    const State: TPowerDisplayState) of object; 

    TPowerSettingUserPresenceEvent = procedure(Sender: TObject; 
    const Presence: TPowerUserPresence) of object; 

    TPowerSettingSavingEvent = procedure(Sender: TObject; 
    const Status: TPowerSavingStatus) of object; 

    TPowerAwayModeEvent = procedure(Sender: TObject; 
    const Mode: TPowerAwayMode) of object; 

    TPowerPersonalityEvent = procedure(Sender: TObject; 
    const Personality: TPowerPersonality) of object; 

    TPowerMonitor = class(TComponent) 
    private 
    FHandle: HWND; 
    FSettingHandles: TPowerMonitorSettingHandles; 
    FSettings: TPowerSettings; 
    FBatteryPresent: Boolean; 
    FOnQueryEndSession: TPowerQueryEndSessionEvent; 
    FOnEndSession: TPowerEndSessionEvent; 
    FOnPowerStatusChange: TNotifyEvent; 
    FOnResumeAutomatic: TNotifyEvent; 
    FOnResumeSuspend: TNotifyEvent; 
    FOnSuspend: TNotifyEvent; 
    FOnSourceChange: TPowerSettingSourceChangeEvent; 
    FOnBatteryPercent: TPowerSettingBatteryPercentEvent; 
    FOnConsoleDisplayState: TPowerSettingDisplayStateEvent; 
    FOnGlobalUserPresence: TPowerSettingUserPresenceEvent; 
    FOnIdleBackgroundTask: TNotifyEvent; 
    FOnMonitorPower: TPowerSettingDisplayStateEvent; 
    FOnPowerSavingStatus: TPowerSettingSavingEvent; 
    FOnSessionDisplayState: TPowerSettingDisplayStateEvent; 
    FOnSessionUserPresence: TPowerSettingUserPresenceEvent; 
    FOnAwayMode: TPowerAwayModeEvent; 
    FOnPersonality: TPowerPersonalityEvent; 
    procedure UnregisterSettings; 
    procedure RegisterSettings; 
    procedure SetSettings(const Value: TPowerSettings); 
    protected 
    procedure HandlePowerSetting(const Val: PPowerBroadcastSetting); 
    procedure WndMethod(var Msg: TMessage); 
    public 
    constructor Create(AOwner: TComponent); override; 
    destructor Destroy; override; 
    published 
    property Settings: TPowerSettings read FSettings write SetSettings; 
    property OnQueryEndSession: TPowerQueryEndSessionEvent 
     read FOnQueryEndSession write FOnQueryEndSession; 
    property OnEndSession: TPowerEndSessionEvent 
     read FOnEndSession write FOnEndSession; 
    property OnPowerStatusChange: TNotifyEvent 
     read FOnPowerStatusChange write FOnPowerStatusChange; 
    property OnResumeAutomatic: TNotifyEvent 
     read FOnResumeAutomatic write FOnResumeAutomatic; 
    property OnResumeSuspend: TNotifyEvent 
     read FOnResumeSuspend write FOnResumeSuspend; 
    property OnSuspend: TNotifyEvent 
     read FOnSuspend write FOnSuspend; 
    property OnSourceChange: TPowerSettingSourceChangeEvent 
     read FOnSourceChange write FOnSourceChange; 
    property OnBatteryPercent: TPowerSettingBatteryPercentEvent 
     read FOnBatteryPercent write FOnBatteryPercent; 
    property OnConsoleDisplayState: TPowerSettingDisplayStateEvent 
     read FOnConsoleDisplayState write FOnConsoleDisplayState; 
    property OnGlobalUserPresence: TPowerSettingUserPresenceEvent 
     read FOnGlobalUserPresence write FOnGlobalUserPresence; 
    property OnIdleBackgroundTask: TNotifyEvent 
     read FOnIdleBackgroundTask write FOnIdleBackgroundTask; 
    property OnMonitorPower: TPowerSettingDisplayStateEvent 
     read FOnMonitorPower write FOnMonitorPower; 
    property OnPowerSavingStatus: TPowerSettingSavingEvent 
     read FOnPowerSavingStatus write FOnPowerSavingStatus; 
    property OnSessionDisplayState: TPowerSettingDisplayStateEvent 
     read FOnSessionDisplayState write FOnSessionDisplayState; 
    property OnSessionUserPresence: TPowerSettingUserPresenceEvent 
     read FOnSessionUserPresence write FOnSessionUserPresence; 
    property OnAwayMode: TPowerAwayModeEvent 
     read FOnAwayMode write FOnAwayMode; 
    property OnPersonality: TPowerPersonalityEvent 
     read FOnPersonality write FOnPersonality; 
    end; 

implementation 

{ TPowerMonitor } 

constructor TPowerMonitor.Create(AOwner: TComponent); 
begin 
    inherited; 
    FBatteryPresent:= False; 
    FHandle := AllocateHWnd(WndMethod); 
end; 

destructor TPowerMonitor.Destroy; 
begin 
    UnregisterSettings; 
    DeallocateHWnd(FHandle); 
    inherited; 
end; 

procedure TPowerMonitor.SetSettings(const Value: TPowerSettings); 
begin 
    UnregisterSettings; 
    FSettings := Value; 
    RegisterSettings; 
end; 

procedure TPowerMonitor.WndMethod(var Msg: TMessage); 
var 
    Handled: Boolean; 
begin 
    Handled := True; 
    case Msg.Msg of 
    WM_POWERBROADCAST: begin 
     //TODO: Why is this never received when inside of a thread? 
     case Msg.WParam of 
     PBT_APMPOWERSTATUSCHANGE: begin 
      //Power status has changed. 
      if Assigned(FOnPowerStatusChange) then 
      FOnPowerStatusChange(Self); 
     end; 
     PBT_APMRESUMEAUTOMATIC: begin 
      //Operation is resuming automatically from a low-power state. 
      //This message is sent every time the system resumes. 
      if Assigned(FOnResumeAutomatic) then 
      FOnResumeAutomatic(Self); 
     end; 
     PBT_APMRESUMESUSPEND: begin 
      //Operation is resuming from a low-power state. This message 
      //is sent after PBT_APMRESUMEAUTOMATIC if the resume is triggered 
      //by user input, such as pressing a key. 
      if Assigned(FOnResumeSuspend) then 
      FOnResumeSuspend(Self); 
     end; 
     PBT_APMSUSPEND: begin 
      //System is suspending operation. 
      if Assigned(FOnSuspend) then 
      FOnSuspend(Self); 
     end; 
     PBT_POWERSETTINGCHANGE: begin 
      //A power setting change event has been received. 
      HandlePowerSetting(PPowerBroadcastSetting(Msg.LParam)); 
     end; 
     else begin 

     end; 
     end; 
    end 
    else Handled := False; 
    end; 
    if Handled then 
    Msg.Result := 0 
    else 
    Msg.Result := DefWindowProc(FHandle, Msg.Msg, 
     Msg.WParam, Msg.LParam); 
end; 

procedure TPowerMonitor.HandlePowerSetting(const Val: PPowerBroadcastSetting); 
var 
    Pers: TPowerPersonality; 
    function ValAsDWORD: DWORD; 
    begin 
    Result:= DWORD(Val.Data[0]); 
    end; 
    function ValAsGUID: TGUID; 
    begin 
    Result:= StringToGUID('{00000000-0000-0000-0000-000000000000}'); //Default 
    if SizeOf(TGUID) = Val.DataLength then begin 
     Move(Val.Data, Result, Val.DataLength); 
    end; 
    end; 
    function IsVal(G: String): Boolean; 
    begin 
    Result:= Assigned(Val); 
    if Result then 
     Result:= IsEqualGUID(StringToGUID(G), Val.PowerSetting); 
    end; 
    function IsValGuid(G: String): Boolean; 
    begin 
    Result:= Assigned(Val); 
    if Result then 
     Result:= IsEqualGUID(StringToGUID(G), ValAsGUID); 
    end; 
begin 
    if IsVal('{5d3e9a59-e9D5-4b00-a6bd-ff34ff516548}') then begin 
    //GUID_ACDC_POWER_SOURCE 
    if Assigned(FOnSourceChange) then 
     FOnSourceChange(Self, TPowerSource(ValAsDWORD)); 
    end else 
    if IsVal('{a7ad8041-b45a-4cae-87a3-eecbb468a9e1}') then begin 
    //GUID_BATTERY_PERCENTAGE_REMAINING 
    //We assume that if we get this message, that there is a battery connected. 
    //Otherwise if this never occurs, then a battery is not present. 
    //TODO: How to handle if battery is detached and no longer present? 
    FBatteryPresent:= True; 
    if Assigned(FOnBatteryPercent) then 
     FOnBatteryPercent(Self, ValAsDWORD); 
    end else 
    if IsVal('{6fe69556-704a-47a0-8f24-c28d936fda47}') then begin 
    //GUID_CONSOLE_DISPLAY_STATE 
    if Assigned(FOnConsoleDisplayState) then 
     FOnConsoleDisplayState(Self, TPowerDisplayState(ValAsDWORD)); 
    end else 
    if IsVal('{786E8A1D-B427-4344-9207-09E70BDCBEA9}') then begin 
    //GUID_GLOBAL_USER_PRESENCE 
    if Assigned(FOnGlobalUserPresence) then 
     FOnGlobalUserPresence(Self, TPowerUserPresence(ValAsDWORD)); 
    end else 
    if IsVal('{515c31d8-f734-163d-a0fd-11a08c91e8f1}') then begin 
    //GUID_IDLE_BACKGROUND_TASK 
    if Assigned(FOnIdleBackgroundTask) then 
     FOnIdleBackgroundTask(Self); 
    end else 
    if IsVal('{02731015-4510-4526-99e6-e5a17ebd1aea}') then begin 
    //GUID_MONITOR_POWER_ON 
    if Assigned(FOnMonitorPower) then 
     FOnMonitorPower(Self, TPowerDisplayState(ValAsDWORD)); 
    end else 
    if IsVal('{E00958C0-C213-4ACE-AC77-FECCED2EEEA5}') then begin 
    //GUID_POWER_SAVING_STATUS 
    if Assigned(FOnPowerSavingStatus) then 
     FOnPowerSavingStatus(Self, TPowerSavingStatus(ValAsDWORD)); 
    end else 
    if IsVal('{245d8541-3943-4422-b025-13A784F679B7}') then begin 
    //GUID_POWERSCHEME_PERSONALITY 
    if IsValGuid('{8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c}') then begin 
     Pers:= TPowerPersonality.ppHighPerformance; 
    end else 
    if IsValGuid('{a1841308-3541-4fab-bc81-f71556f20b4a}') then begin 
     Pers:= TPowerPersonality.ppPowerSaver; 
    end else 
    if IsValGuid('{381b4222-f694-41f0-9685-ff5bb260df2e}') then begin 
     Pers:= TPowerPersonality.ppAutomatic; 
    end else begin 
     //TODO: Handle unrecognized GUID 
     Pers:= TPowerPersonality.ppAutomatic; 
    end; 
    if Assigned(FOnPersonality) then 
     FOnPersonality(Self, Pers); 
    end else 
    if IsVal('{2B84C20E-AD23-4ddf-93DB-05FFBD7EFCA5}') then begin 
    //GUID_SESSION_DISPLAY_STATUS 
    if Assigned(FOnSessionDisplayState) then 
     FOnSessionDisplayState(Self, TPowerDisplayState(ValAsDWORD)); 
    end else 
    if IsVal('{3C0F4548-C03F-4c4d-B9F2-237EDE686376}') then begin 
    //GUID_SESSION_USER_PRESENCE 
    if Assigned(FOnSessionUserPresence) then 
     FOnSessionUserPresence(Self, TPowerUserPresence(ValAsDWORD)); 
    end else 
    if IsVal('{98a7f580-01f7-48aa-9c0f-44352c29e5C0}') then begin 
    //GUID_SYSTEM_AWAYMODE 
    if Assigned(FOnAwayMode) then 
     FOnAwayMode(Self, TPowerAwayMode(ValAsDWORD)); 
    end else begin 
    //TODO: Handle Unrecognized GUID 
    end; 
end; 

function PowerSettingGUID(const Setting: TPowerSetting): TGUID; 
begin 
    case Setting of 
    psACDCPowerSource: Result:= StringToGUID('{5d3e9a59-e9D5-4b00-a6bd-ff34ff516548}'); 
    psBatteryPercentage: Result:= StringToGUID('{a7ad8041-b45a-4cae-87a3-eecbb468a9e1}'); 
    psConsoleDisplayState: Result:= StringToGUID('{6fe69556-704a-47a0-8f24-c28d936fda47}'); 
    psGlobalUserPresence: Result:= StringToGUID('{786E8A1D-B427-4344-9207-09E70BDCBEA9}'); 
    psIdleBackgroundTask: Result:= StringToGUID('{515c31d8-f734-163d-a0fd-11a08c91e8f1}'); 
    psMonitorPower: Result:= StringToGUID('{02731015-4510-4526-99e6-e5a17ebd1aea}'); 
    psPowerSaving: Result:= StringToGUID('{E00958C0-C213-4ACE-AC77-FECCED2EEEA5}'); 
    psPowerSchemePersonality: Result:= StringToGUID('{245d8541-3943-4422-b025-13A784F679B7}'); 
    psSessionDisplayStatus: Result:= StringToGUID('{2B84C20E-AD23-4ddf-93DB-05FFBD7EFCA5}'); 
    psSessionUserPresence: Result:= StringToGUID('{3C0F4548-C03F-4c4d-B9F2-237EDE686376}'); 
    psSystemAwayMode: Result:= StringToGUID('{98a7f580-01f7-48aa-9c0f-44352c29e5C0}'); 
    end; 
end; 

procedure TPowerMonitor.RegisterSettings; 
var 
    V: TPowerSetting; 
begin 
    for V := Low(TPowerSetting) to High(TPowerSetting) do begin 
    if V in FSettings then begin 
     FSettingHandles[V]:= RegisterPowerSettingNotification(FHandle, 
     PowerSettingGUID(V), 0); 
    end; 
    end; 
end; 

procedure TPowerMonitor.UnregisterSettings; 
var 
    V: TPowerSetting; 
begin 
    for V := Low(TPowerSetting) to High(TPowerSetting) do begin 
    if V in FSettings then begin 
     UnregisterPowerSettingNotification(FSettingHandles[V]); 
    end; 
    end; 
end; 

end. 

は、ここでは、私だけのスレッドを使用して、このメッセージを捕獲しようとしてる方法ですメッセージ:

unit JD.ThreadTest; 

interface 

uses 
    System.Classes, Winapi.Messages, Winapi.Windows; 

type 
    TDataThread = class(TThread) 
    private 
    FTitle: String; 
    FWnd: HWND; 
    FWndClass: WNDCLASS; 
    procedure HandlePower(AMsg: TMsg); 
    protected 
    procedure Execute; override; 
    procedure DoTerminate; override; 
    public 
    constructor Create(const Title: String); reintroduce; 
    end; 

implementation 

constructor TDataThread.Create(const Title: String); 
begin 
    inherited Create(True); 
    FTitle := Title; 
    with FWndClass do begin 
    Style := 0; 
    lpfnWndProc := @DefWindowProc; 
    cbClsExtra := 0; 
    cbWndExtra := 0; 
    hInstance := HInstance; 
    hIcon := 0; 
    hCursor := LoadCursor(0, IDC_ARROW); 
    hbrBackground := COLOR_WINDOW; 
    lpszMenuName := nil; 
    lpszClassName := PChar(Self.ClassName); 
    end; 
end; 

procedure TDataThread.Execute; 
var 
    Msg: TMsg; 
begin 
    if Winapi.Windows.RegisterClass(FWndClass) = 0 then Exit; 
    FWnd := CreateWindow(FWndClass.lpszClassName, PChar(FTitle), WS_DLGFRAME, 
    0, 0, 698, 517, 0, 0, HInstance, nil); 
    if FWnd = 0 then Exit; 
    while GetMessage(Msg, FWnd, 0, 0) = True do begin 
    if Terminated then Break; 
    case Msg.message of 
     WM_POWERBROADCAST: begin 
     HandlePower(Msg); //Never receives this message 
     end; 
     else begin 
     TranslateMessage(msg); 
     DispatchMessage(msg) 
     end; 
    end; 
    end; 
end; 

procedure TDataThread.HandlePower(AMsg: TMsg); 
begin 

end; 

procedure TDataThread.DoTerminate; 
begin 
    if FWnd <> 0 then DestroyWindow(FWnd); 
    Winapi.Windows.UnregisterClass(PChar(Self.ClassName), FWndClass.hInstance); 
    inherited; 
end; 

end. 

PS:最終目標は、このコンポーネントは、再使用可能にするために、サービスの内部にスポーンされるスレッドの内部にそれを使用すべきです。


EDIT

ただ、いくつかの視点を示すために、ここで私はスリープモードにコンピュータを置くとき、私の結果のスクリーンショットです。左のフォームは、私の100%働いているUIアプリケーションです。ワーカースレッドはありません。 WM_POWERBROADCASTメッセージで多数のメッセージを受信します。右の1つはスレッド内でこのメッセージをキャプチャしようとしている場所です.Remyの答えで以下のコードで更新されています。

enter image description here

明らかに「電源設定は、」特定のメッセージは、私はRegisterPowerSettingNotificationと呼ばれていないため、受信されません - しかし、私はまだそのようPBT_APMSUSPENDとして、かかわらず、このメッセージが表示されますときに、他の例もあります。

unit JD.ThreadTest; 

interface 

uses 
    System.Classes, System.SysUtils, Winapi.Messages, Winapi.Windows; 

type 

    TMessageEvent = procedure(Sender: TObject; Message: TMessage) of object; 

    TDataThread = class(TThread) 
    private 
    FTitle: String; 
    FWnd: HWND; 
    FWndClass: WNDCLASS; 
    FOnMessage: TMessageEvent; 
    FMsg: TMessage; 
    procedure HandleMessage(var Message: TMessage); 
    protected 
    procedure Execute; override; 
    procedure DoTerminate; override; 
    procedure DoOnMessage; 
    public 
    constructor Create(const Title: String); reintroduce; 
    property OnMessage: TMessageEvent read FOnMessage write FOnMessage; 
    end; 

implementation 

function DataThreadWndProc(Wnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; 
var 
    Thread: TDataThread; 
    Message: TMessage; 
begin 
    if Msg = WM_NCCREATE then 
    begin 
    Thread := TDataThread(PCREATESTRUCT(lParam)^.lpCreateParams); 
    SetWindowLongPtr(Wnd, GWLP_USERDATA, LONG_PTR(Thread)); 
    end else 
    Thread := TDataThread(GetWindowLongPtr(Wnd, GWLP_USERDATA)); 

    if Thread <> nil then 
    begin 
    Message.Msg := Msg; 
    Message.WParam := wParam; 
    Message.LParam := lParam; 
    Message.Result := 0; 
    Thread.HandleMessage(Message); 
    Result := Message.Result; 
    end else 
    Result := DefWindowProc(Wnd, Msg, wParam, lParam); 
end; 

constructor TDataThread.Create(const Title: String); 
begin 
    inherited Create(True); 
    FTitle := Title; 
    with FWndClass do 
    begin 
    Style := 0; 
    lpfnWndProc := @DataThreadWndProc; 
    cbClsExtra := 0; 
    cbWndExtra := 0; 
    hInstance := HInstance; 
    hIcon := 0; 
    hCursor := LoadCursor(0, IDC_ARROW); 
    hbrBackground := COLOR_WINDOW; 
    lpszMenuName := nil; 
    lpszClassName := 'TDataThread'; 
    end; 
end; 

procedure TDataThread.Execute; 
var 
    Msg: TMsg; 
begin 
    if Winapi.Windows.RegisterClass(FWndClass) = 0 then Exit; 
    FWnd := CreateWindow(FWndClass.lpszClassName, PChar(FTitle), WS_DLGFRAME, 0, 0, 698, 517, 0, 0, HInstance, Self); 
    if FWnd = 0 then Exit; 
    while GetMessage(Msg, 0, 0, 0) do 
    begin 
    if Terminated then Exit; 
    TranslateMessage(msg); 
    DispatchMessage(msg); 
    end; 
end; 

procedure TDataThread.DoOnMessage; 
begin 
    if Assigned(FOnMessage) then 
    FOnMessage(Self, FMsg); 
end; 

procedure TDataThread.DoTerminate; 
begin 
    if FWnd <> 0 then DestroyWindow(FWnd); 
    Winapi.Windows.UnregisterClass(FWndClass.lpszClassName, HInstance); 
    inherited; 
end; 

procedure TDataThread.HandleMessage(var Message: TMessage); 
begin 
    FMsg:= Message; 
    Synchronize(DoOnMessage); 
    case Message.Msg of 
    WM_POWERBROADCAST: 
    begin 

    end; 
    else 
    Message.Result := DefWindowProc(FWnd, Message.Msg, Message.WParam, Message.LParam); 
    end; 
end; 

end. 
+0

ちょっとしたアイデア:RegisterPowerSettingNotificationを呼び出すときに正しいハンドルを使用していますか?すなわち、 **ウィンドウハンドル**はスレッドハンドルではなくAllocateHwndによって返されますか? –

+0

@OndrejKelle私はこのコンポーネントのためだけに割り当てられた同じハンドルを使用しています。コンポーネントには、ワーカースレッドの内部にあるかどうかは認識されません。 –

+0

MCVEを作成していないため、関連するコードが表示されません。代わりに無関係なコードを表示しました。あなたは今、もっとよく知っておくべきです。メッセージを送信するコードはどこですか?スレッド内のメッセージが確実に送信されるコード。これを読んでください:[mcve] –

答えて

3

WM_POWERBROADCAST投稿メッセージではありませんので、あなたのメッセージループは、それを見ることはありません。そのメッセージを受信するには、ウィンドウプロシージャが必要です。あなたのスレッドコードはウィンドウプロシージャとして直接DefWindowProc()を使用しています。呼び出しをRegisterClass()に変更して、代わりにカスタムプロシージャを登録すると、未処理のメッセージに対してDefWindowProc()が呼び出されます。 GetMessage()というメッセージをウィンドウプロシージャに直接送信し、DispatchMessage()のメッセージをと同じウィンドウプロシージャに送信します。

unit JD.ThreadTest; 

interface 

uses 
    System.Classes, Winapi.Messages, Winapi.Windows; 

type 
    TDataThread = class(TThread) 
    private 
    FTitle: String; 
    FWnd: HWND; 
    FWndClass: WNDCLASS; 
    procedure HandleMessage(var Message: TMessage); 
    protected 
    procedure Execute; override; 
    procedure DoTerminate; override; 
    public 
    constructor Create(const Title: String); reintroduce; 
    end; 

implementation 

function DataThreadWndProc(Wnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; 
var 
    Thread: TDataThread; 
    Message: TMessage; 
begin 
    if Msg = WM_NCCREATE then 
    begin 
    Thread := TDataThread(PCREATESTRUCT(lParam)^.lpCreateParams); 
    SetWindowLongPtr(Wnd, GWLP_USERDATA, LONG_PTR(Thread)); 
    end else 
    Thread := TDataThread(GetWindowLongPtr(Wnd, GWLP_USERDATA)); 

    if Thread <> nil then 
    begin 
    Message.Msg := Msg; 
    Message.WParam := wParam; 
    Message.LParam := lParam; 
    Message.Result := 0; 
    Thread.HandleMessage(Message); 
    Result := Message.Result; 
    end else 
    Result := DefWindowProc(Wnd, Msg, wParam, lParam); 
end; 

constructor TDataThread.Create(const Title: String); 
begin 
    inherited Create(True); 
    FTitle := Title; 
    with FWndClass do 
    begin 
    Style := 0; 
    lpfnWndProc := @DataThreadWndProc; 
    cbClsExtra := 0; 
    cbWndExtra := 0; 
    hInstance := HInstance; 
    hIcon := 0; 
    hCursor := LoadCursor(0, IDC_ARROW); 
    hbrBackground := COLOR_WINDOW; 
    lpszMenuName := nil; 
    lpszClassName := 'TDataThread'; 
    end; 
end; 

procedure TDataThread.Execute; 
var 
    Msg: TMsg; 
begin 
    if Winapi.Windows.RegisterClass(FWndClass) = 0 then Exit; 
    FWnd := CreateWindow(FWndClass.lpszClassName, PChar(FTitle), WS_OVERLAPPED, 0, 0, 0, 0, 0, 0, HInstance, Self); 
    if FWnd = 0 then Exit; 
    while GetMessage(Msg, 0, 0, 0) do 
    begin 
    if Terminated then Exit; 
    TranslateMessage(msg); 
    DispatchMessage(msg); 
    end; 
end; 

procedure TDataThread.DoTerminate; 
begin 
    if FWnd <> 0 then DestroyWindow(FWnd); 
    Winapi.Windows.UnregisterClass(FWndClass.lpszClassName, HInstance); 
    inherited; 
end; 

procedure TDataThread.HandleMessage(var Message: TMessage); 
begin 
    case Message.Msg of 
    WM_POWERBROADCAST: 
    begin 
     // ... 
    end; 
    else 
    Message.Result := DefWindowProc(FWnd, Message.Msg, Message.WParam, Message.LParam); 
    end; 
end; 

end. 
+0

また、PChar(Self.ClassName)の生涯の問題に言及しています。 –

+0

ありがとうございます - これは、 'Message.Result:= DefWindowProc ...'行の '0x005c6115でのアクセス違反:0x00000044の読み込み ' 'Message.Msg'は' 0'です。これは起動時に最初に受け取るメッセージです。 –

+0

AllocateHWndを複製するのではなく、スレッドで使用する方がはるかに簡単です。ここでのRemyのコードの問題は、ウィンドウprocがCreateWindowから呼び出されることです。 WM_NCCREATE IIRCの場合。したがって、ユーザーデータはまだ設定されていません。 AllocateHWndを使用して、bogの標準メッセージループを実行してください。あなたはそれを知っています。 GetMessage、TranslateMessage、DispatchMesage。それでおしまい。これ以上何もない。 –

関連する問題