1 package fr.ifremer.quadrige3.ui.swing.desktop.os.win;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 import com.sun.jna.Native;
27 import com.sun.jna.platform.win32.Kernel32;
28 import com.sun.jna.platform.win32.User32;
29 import com.sun.jna.platform.win32.WinDef.*;
30 import com.sun.jna.platform.win32.WinUser.HHOOK;
31 import com.sun.jna.platform.win32.WinUser.HOOKPROC;
32 import com.sun.jna.platform.win32.WinUser.MSG;
33 import fr.ifremer.quadrige3.ui.swing.desktop.DesktopPower;
34 import fr.ifremer.quadrige3.ui.swing.desktop.os.win.handle.CWPSSTRUCT;
35 import fr.ifremer.quadrige3.ui.swing.desktop.os.win.handle.HANDLER_ROUTINE;
36 import fr.ifremer.quadrige3.ui.swing.desktop.os.win.handle.WNDPROC;
37 import fr.ifremer.quadrige3.ui.swing.desktop.os.win.libs.Kernel32Ex;
38 import fr.ifremer.quadrige3.ui.swing.desktop.os.win.wrap.GetLastErrorException;
39 import fr.ifremer.quadrige3.ui.swing.desktop.os.win.wrap.WNDCLASSEXWrap;
40 import org.apache.commons.logging.Log;
41 import org.apache.commons.logging.LogFactory;
42
43 import javax.swing.JFrame;
44 import javax.swing.JOptionPane;
45
46
47
48
49
50 public class WindowsPower extends DesktopPower {
51
52 private static final Log LOG = LogFactory.getLog(WindowsPower.class);
53
54
55 private static final int WM_QUERYENDSESSION = 17;
56
57 private static final int WM_ENDSESSION = 22;
58
59 private static final int WH_CALLWNDPROC = 4;
60
61 public class MessagePump implements Runnable {
62 final Thread t;
63
64 WNDCLASSEXWrap wc;
65 WNDPROC WndProc;
66 HWND hWnd;
67 HINSTANCE hInstance;
68
69 final Object lock = new Object();
70
71 public MessagePump() {
72 t = new Thread(this, WindowsPower.class.getSimpleName());
73 }
74
75 public void start() {
76 synchronized (lock) {
77 t.start();
78 try {
79 lock.wait();
80 } catch (InterruptedException e) {
81 Thread.currentThread().interrupt();
82 }
83 }
84 }
85
86 void create() {
87 WndProc = (hWnd, msg, wParam, lParam) -> {
88 switch (msg) {
89 case WM_ENDSESSION:
90 return new LRESULT(0);
91 case WM_QUERYENDSESSION:
92 JOptionPane.showMessageDialog(null, "exit");
93 callListeners("WM_QUERYENDSESSION callback");
94 return new LRESULT(0);
95 case User32.WM_QUIT:
96 User32.INSTANCE.PostMessage(hWnd, User32.WM_QUIT, null, null);
97 break;
98 }
99
100 return User32.INSTANCE.DefWindowProc(hWnd, msg, wParam, lParam);
101 };
102 hWnd = createWindow();
103 }
104
105
106
107 HWND createWindow() {
108 hInstance = Kernel32.INSTANCE.GetModuleHandle(null);
109
110 wc = new WNDCLASSEXWrap(hInstance, WndProc, WindowsPower.class.getSimpleName());
111
112 HWND hwnd = User32.INSTANCE.CreateWindowEx(0, wc.getClassName().toString(), wc.getName(), User32.WS_OVERLAPPED, 0, 0,
113 0, 0, null, null, hInstance, null);
114
115 if (hwnd == null)
116 throw new GetLastErrorException();
117
118 return hwnd;
119 }
120
121 @Override
122 public void run() {
123 create();
124
125 synchronized (lock) {
126 lock.notifyAll();
127 }
128
129 MSG msg = new MSG();
130
131 while (User32.INSTANCE.GetMessage(msg, null, 0, 0) > 0) {
132 User32.INSTANCE.DispatchMessage(msg);
133 }
134
135 destory();
136 }
137
138 void destory() {
139 if (hWnd != null) {
140 if (!User32.INSTANCE.DestroyWindow(hWnd))
141 throw new GetLastErrorException();
142 hWnd = null;
143 }
144
145 if (wc != null) {
146 wc.close();
147 wc = null;
148 }
149 }
150
151 void close() {
152 User32.INSTANCE.PostQuitMessage(0);
153
154 try {
155 if (!Thread.currentThread().equals(t))
156 t.join();
157 } catch (InterruptedException e) {
158 Thread.currentThread().interrupt();
159 }
160 }
161 }
162
163 private final MessagePump mp = new MessagePump();
164
165 private final HANDLER_ROUTINE hr = dwCtrlType -> {
166
167 if ((dwCtrlType & HANDLER_ROUTINE.CTRL_CLOSE_EVENT) == HANDLER_ROUTINE.CTRL_CLOSE_EVENT) {
168 callListeners("HANDLER_ROUTINE.CTRL_CLOSE_EVENT");
169 }
170 if ((dwCtrlType & HANDLER_ROUTINE.CTRL_LOGOFF_EVENT) == HANDLER_ROUTINE.CTRL_LOGOFF_EVENT) {
171 callListeners("HANDLER_ROUTINE.CTRL_LOGOFF_EVENT");
172 }
173 if ((dwCtrlType & HANDLER_ROUTINE.CTRL_SHUTDOWN_EVENT) == HANDLER_ROUTINE.CTRL_SHUTDOWN_EVENT) {
174 callListeners("HANDLER_ROUTINE.CTRL_SHUTDOWN_EVENT");
175 }
176 return 1;
177 };
178
179 private final HOOKPROC hp = new HOOKPROC() {
180 @SuppressWarnings("unused")
181 public LRESULT callback(int nCode, WPARAM wParam, CWPSSTRUCT hookProcStruct) {
182 switch (hookProcStruct.message) {
183 case WM_QUERYENDSESSION:
184 callListeners("WM_QUERYENDSESSION hook");
185 break;
186 }
187 return new LRESULT();
188 }
189 };
190 private HHOOK hHook;
191 private JFrame f = new JFrame();
192
193
194
195
196 public WindowsPower() {
197 if (!Kernel32Ex.INSTANCE.SetProcessShutdownParameters(0x03FF, 0))
198 throw new GetLastErrorException();
199
200 mp.start();
201
202 if (!Kernel32Ex.INSTANCE.SetConsoleCtrlHandler(hr, true))
203 throw new GetLastErrorException();
204
205 final HWND hwnd = new HWND();
206 f.pack();
207 hwnd.setPointer(Native.getComponentPointer(f));
208
209 int wID = User32.INSTANCE.GetWindowThreadProcessId(hwnd, null);
210 hHook = User32.INSTANCE.SetWindowsHookEx(WH_CALLWNDPROC, hp, null, wID);
211 if (hHook == null)
212 throw new GetLastErrorException();
213 }
214
215
216 @Override
217 public void close() {
218 if (!User32.INSTANCE.UnhookWindowsHookEx(hHook))
219 throw new GetLastErrorException();
220
221 f.dispose();
222 f = null;
223
224 mp.close();
225
226 if (!Kernel32Ex.INSTANCE.SetConsoleCtrlHandler(hr, false))
227 throw new GetLastErrorException();
228 }
229
230
231
232
233
234
235 protected void callListeners(String source) {
236
237 if (LOG.isDebugEnabled()) LOG.debug("call listeners from " + source);
238
239 for (Listener l : listeners) {
240 l.quit();
241 }
242
243 }
244 }