win 0.1.27 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,679 +1,679 @@
1
- require 'win/library'
2
- require 'win/gui/message' # needed because some convenience methods work via PostMessage
3
-
4
- module Win
5
- module GUI
6
- # Contains constants and Win32API functions related to window manipulation
7
- #
8
- module Window
9
- include Win::Library
10
-
11
- # ShowWindow constants:
12
-
13
- # Hides the window and activates another window.
14
- SW_HIDE = 0
15
- # Same as SW_SHOWNORMAL
16
- SW_NORMAL = 1
17
- # Activates and displays a window. If the window is minimized or maximized, the system restores it to its
18
- # original size and position. An application should specify this flag when displaying the window for the first time.
19
- SW_SHOWNORMAL = 1
20
- # Activates the window and displays it as a minimized window.
21
- SW_SHOWMINIMIZED = 2
22
- # Activates the window and displays it as a maximized window.
23
- SW_SHOWMAXIMIZED = 3
24
- # Activates the window and displays it as a maximized window.
25
- SW_MAXIMIZE = 3
26
- # Displays a window in its most recent size and position. Similar to SW_SHOWNORMAL, but the window is not activated.
27
- SW_SHOWNOACTIVATE = 4
28
- # Activates the window and displays it in its current size and position.
29
- SW_SHOW = 5
30
- # Minimizes the specified window, activates the next top-level window in the Z order.
31
- SW_MINIMIZE = 6
32
- # Displays the window as a minimized window. Similar to SW_SHOWMINIMIZED, except the window is not activated.
33
- SW_SHOWMINNOACTIVE= 7
34
- # Displays the window in its current size and position. Similar to SW_SHOW, except the window is not activated.
35
- SW_SHOWNA = 8
36
- # Activates and displays the window. If the window is minimized or maximized, the system restores it to its original
37
- # size and position. An application should specify this flag when restoring a minimized window.
38
- SW_RESTORE = 9
39
- # Sets the show state based on the SW_ value specified in the STARTUPINFO structure passed to the CreateProcess
40
- # function by the program that started the application.
41
- SW_SHOWDEFAULT = 10
42
- # Windows 2000/XP: Minimizes a window, even if the thread that owns the window is not responding. Only use this
43
- # flag when minimizing windows from a different thread.
44
- SW_FORCEMINIMIZE = 11
45
-
46
- class << self
47
- # Def_block that calls API function expecting EnumWindowsProc callback (EnumWindows, EnumChildWindows, ...).
48
- # Default callback pushes all passed handles into Array that is returned if Enum function call was successful.
49
- # If runtime block is given it is called after the end of default callback (handle Array is still being
50
- # collected and returned by the method). If Enum... function call fails, method returns nil, otherwise
51
- # an Array of all window handles passed into callback.
52
- #
53
- def return_enum #:nodoc:
54
- lambda do |api, *args, &block|
55
- args.push 0 if args.size == api.prototype.size - 2 # If value is missing, it defaults to 0
56
- handles = []
57
-
58
- # Insert callback proc into appropriate place of args Array
59
- args[api.prototype.find_index(:EnumWindowsProc), 0] =
60
- proc do |handle, message|
61
- handles << handle
62
- block ? block[handle, message] : true
63
- end
64
- handles if api.call *args
65
- end
66
- end
67
-
68
- # Helper method that creates def_block returning (possibly encoded) string as a result of
69
- # api function call or nil if zero characters was returned by api call
70
- #
71
- def return_string( encode = nil ) #:nodoc:
72
- lambda do |api, *args|
73
- namespace.enforce_count( args, api.prototype, -2)
74
- buffer = FFI::MemoryPointer.new :char, 1024
75
- args += [buffer, buffer.size]
76
- num_chars = api.call(*args)
77
- return nil if num_chars == 0
78
- if encode
79
- string = buffer.get_bytes(0, num_chars*2)
80
- string = string.force_encoding('utf-16LE').encode(encode)
81
- else
82
- string = buffer.get_bytes(0, num_chars)
83
- end
84
- string.rstrip
85
- end
86
- end
87
-
88
- private :return_enum, :return_string
89
- end
90
-
91
- # Windows GUI API definitions:
92
-
93
- ##
94
- # The IsWindow function determines whether the specified window handle identifies an existing window.
95
- # [*Syntax*] BOOL IsWindow( HWND hWnd );
96
- #
97
- # hWnd:: [in] Handle to the window to test.
98
- #
99
- # *Returns*:: If the window handle identifies an existing window, the return value is (*true*).
100
- # If the window handle does not identify an existing window, the return value is (*false*).
101
- # ---
102
- # *remarks*:
103
- # A thread should not use IsWindow for a window that it did not create because the window
104
- # could be destroyed after this function was called. Further, because window handles are
105
- # recycled the handle could even point to a different window.
106
- #
107
- # :call-seq:
108
- # window?( win_handle )
109
- #
110
- function :IsWindow, [:HWND], :int, boolean: true
111
-
112
- ##
113
- # The IsWindowVisible function retrieves the visibility state of the specified window.
114
- # [*Syntax*] BOOL IsWindowVisible( HWND hWnd );
115
- #
116
- # hWnd:: [in] Handle to the window to test.
117
- #
118
- # *Returns*:: If the specified window, its parent window, its parent's parent window, and so forth,
119
- # have the WS_VISIBLE style set, return value is *true*. Because the return value specifies
120
- # whether the window has the WS_VISIBLE style, it may be true even if the window is totally
121
- # obscured by other windows.
122
- # ---
123
- # *Remarks*:
124
- # - The visibility state of a window is indicated by the WS_VISIBLE style bit. When WS_VISIBLE is set,
125
- # the window is displayed and subsequent drawing into it is displayed as long as the window has the
126
- # WS_VISIBLE style.
127
- # - Any drawing to a window with the WS_VISIBLE style will not be displayed if the window is obscured
128
- # by other windows or is clipped by its parent window.
129
- #
130
- # :call-seq:
131
- # [window_]visible?( win_handle )
132
- #
133
- function :IsWindowVisible, [:HWND], :int, boolean: true, aliases: :visible?
134
-
135
- ##
136
- # Tests whether the specified window is maximized.
137
- # [*Syntax*] BOOL IsZoomed( HWND hWnd );
138
- #
139
- # hWnd:: [in] Handle to the window to test.
140
- #
141
- # *Returns*:: If the window is zoomed (maximized), the return value is *true*.
142
- # If the window is not zoomed (maximized), the return value is *false*.
143
- #
144
- # :call-seq:
145
- # zoomed?( win_handle ), maximized?( win_handle )
146
- #
147
- function :IsZoomed, [:HWND], :int, boolean: true, aliases: :maximized?
148
-
149
- ##
150
- # Tests whether the specified window is minimized.
151
- # [*Syntax*] BOOL IsIconic( HWND hWnd );
152
- #
153
- # hWnd:: [in] Handle to the window to test.
154
- #
155
- # *Returns*:: If the window is iconic (minimized), the return value is *true*.
156
- # If the window is not iconic (minimized), the return value is *false*.
157
- #
158
- # :call-seq:
159
- # iconic?( win_handle ), minimized?( win_handle )
160
- #
161
- function :IsIconic, [:HWND], :int, boolean: true, aliases: :minimized?
162
-
163
- ##
164
- # Tests whether a window is a child (or descendant) window of a specified parent window.
165
- # A child window is the direct descendant of a specified parent window if that parent window
166
- # is in the chain of parent windows; the chain of parent windows leads from the original overlapped
167
- # or pop-up window to the child window.
168
- #
169
- # [*Syntax*] BOOL IsChild( HWND hWndParent, HWND hWnd);
170
- #
171
- # hWndParent:: [in] Handle to the parent window.
172
- # hWnd:: [in] Handle to the window to be tested.
173
- #
174
- # *Returns*:: If the window is a child or descendant window of the specified parent window,
175
- # the return value is *true*. If the window is not a child or descendant window of
176
- # the specified parent window, the return value is *false*.
177
- # :call-seq:
178
- # child?( win_handle )
179
- #
180
- function :IsChild, [:HWND, :HWND], :int, boolean: true
181
-
182
- ##
183
- # The FindWindow function retrieves a handle to the top-level window whose class name and window name
184
- # match the specified strings. This function does not search child windows. This function does not
185
- # perform a case-sensitive search.
186
- #
187
- # To search child windows, beginning with a specified child window, use the FindWindowEx function.
188
- #
189
- # [*Syntax*] HWND FindWindow( LPCTSTR lpClassName, LPCTSTR lpWindowName );
190
- #
191
- # lpClassName:: [in] Pointer to a null-terminated string that specifies the class name or a class
192
- # atom created by a previous call to the RegisterClass or RegisterClassEx function.
193
- # The atom must be in the low-order word of lpClassName; the high-order word must be zero.
194
- # If lpClassName points to a string, it specifies the window class name. The class name
195
- # can be any name registered with RegisterClass or RegisterClassEx, or any of the
196
- # predefined control-class names.
197
- # If lpClassName is NULL, it finds any window whose title matches the lpWindowName parameter.
198
- # lpWindowName:: [in] Pointer to a null-terminated string that specifies the window name (the window's title).
199
- # If this parameter is NULL, all window names match.
200
- # *Returns*:: If the function succeeds, the return value is a handle to the window that has the specified
201
- # class name and window name. If the function fails, the return value is *nil*.
202
- # To get extended error information, call GetLastError.
203
- # ---
204
- # *Remarks*:
205
- # - If the lpWindowName parameter is not NULL, FindWindow calls the GetWindowText function to retrieve
206
- # the window name for comparison. For a description of a potential problem that can arise, see the
207
- # Remarks for GetWindowText.
208
- # - To check if the Microsoft IntelliType version 1.x software is running, call FindWindow as follows:
209
- # find_window("MSITPro::EventQueue", nil)
210
- # - To check if the IntelliType version 2.0 software is running, call FindWindow as follows:
211
- # find_window("Type32_Main_Window", nil)
212
- # If the IntelliType software is running, it sends WM_APPCOMMAND messages to the application.
213
- # Otherwise the application must install a hook to receive WM_APPCOMMAND messages.
214
- #
215
- # :call-seq:
216
- # win_handle = find_window( class_name, win_name )
217
- #
218
- function :FindWindow, [:pointer, :pointer], :HWND, zeronil: true
219
-
220
- ##
221
- # Unicode version of FindWindow (strings must be encoded as utf-16LE AND terminate with "\x00\x00")
222
- #
223
- # :call-seq:
224
- # win_handle = find_window_w( class_name, win_name )
225
- #
226
- function :FindWindowW, [:pointer, :pointer], :HWND, zeronil: true
227
-
228
- ##
229
- # The FindWindowEx function retrieves a handle to a window whose class name and window name match the specified
230
- # strings. The function searches child windows, beginning with the one following the specified child window.
231
- # This function does not perform a case-sensitive search.
232
- #
233
- # [*Syntax*] HWND FindWindowEx( HWND hwndParent, HWND hwndChildAfter, LPCTSTR lpszClass, LPCTSTR lpszWindow );
234
- #
235
- # hwndParent:: [in] Handle to the parent window whose child windows are to be searched.
236
- # If hwndParent is NULL, the function uses the desktop window as the parent window.
237
- # The function searches among windows that are child windows of the desktop.
238
- # Microsoft Windows 2000 and Windows XP: If hwndParent is HWND_MESSAGE, the function
239
- # searches all message-only windows.
240
- # hwndChildAfter:: [in] Handle to a child window. The search begins with the next child window in the Z order.
241
- # The child window must be a direct child window of hwndParent, not just a descendant window.
242
- # If hwndChildAfter is NULL, the search begins with the first child window of hwndParent.
243
- # Note that if both hwndParent and hwndChildAfter are NULL, the function searches all
244
- # top-level and message-only windows.
245
- # lpszClass:: [in] Pointer to a null-terminated string that specifies the class name or a class atom created
246
- # by a previous call to the RegisterClass or RegisterClassEx function. The atom must be placed in
247
- # the low-order word of lpszClass; the high-order word must be zero.
248
- # If lpszClass is a string, it specifies the window class name. The class name can be any name
249
- # registered with RegisterClass or RegisterClassEx, or any of the predefined control-class names,
250
- # or it can be MAKEINTATOM(0x800). In this latter case, 0x8000 is the atom for a menu class. For
251
- # more information, see the Remarks section of this topic.
252
- # lpszWindow:: [in] Pointer to a null-terminated string that specifies the window name (the window's title).
253
- # If this parameter is NULL, all window names match.
254
- #
255
- # *Returns*:: If the function succeeds, the return value is a handle to the window that has the specified
256
- # class and window names. If the function fails, the return value is NULL. For extended error info,
257
- # call GetLastError.
258
- # ---
259
- # *Remarks*:
260
- # - If the lpszWindow parameter is not NULL, FindWindowEx calls the GetWindowText function to retrieve the window name for comparison. For a description of a potential problem that can arise, see the Remarks section of GetWindowText.
261
- # - An application can call this function in the following way.
262
- # find_window_ex( nil, nil, MAKEINTATOM(0x8000), nil )
263
- # 0x8000 is the atom for a menu class. When an application calls this function, the function checks whether
264
- # a context menu is being displayed that the application created.
265
- #
266
- # :call-seq:
267
- # win_handle = find_window_ex( win_handle, after_child, class_name, win_name )
268
- #
269
- function :FindWindowEx, [:HWND, :HWND, :pointer, :pointer], :HWND, zeronil: true
270
-
271
- ##
272
- # GetWindowText returns the text of the specified window's title bar (if it has one).
273
- # If the specified window is a control, the text of the control is copied. However, GetWindowText
274
- # cannot retrieve the text of a control in another application.
275
- #
276
- # [*Syntax*] int GetWindowText( HWND hWnd, LPTSTR lpString, int nMaxCount );
277
- #
278
- # *Original* Parameters:
279
- # hWnd:: Handle to the window and, indirectly, the class to which the window belongs.
280
- # lpString:: Long Pointer to the buffer that is to receive the text string.
281
- # nMaxCount:: Specifies the length, in TCHAR, of the buffer pointed to by the text parameter.
282
- # The class name string is truncated if it is longer than the buffer and is always null-terminated.
283
- # *Original* Return:: Length, in characters, of the copied string, not including the terminating null
284
- # character (if success). Zero indicates that the window has no title bar or text,
285
- # if the title bar is empty, or if the window or control handle is invalid.
286
- # For extended error information, call GetLastError.
287
- # ---
288
- # Enhanced API requires only win_handle and returns rstripped text
289
- #
290
- # *Enhanced* Parameters:
291
- # win_handle:: Handle to the window and, indirectly, the class to which the window belongs.
292
- # *Returns*:: Window title bar text or nil. If the window has no title bar or text, if the title bar
293
- # is empty, or if the window or control handle is invalid, the return value is *NIL*.
294
- # To get extended error information, call GetLastError.
295
- # ---
296
- # *Remarks*: This function CANNOT retrieve the text of an edit control in ANOTHER app.
297
- # - If the target window is owned by the current process, GetWindowText causes a WM_GETTEXT message to
298
- # be sent to the specified window or control. If the target window is owned by another process and has
299
- # a caption, GetWindowText retrieves the window caption text. If the window does not have a caption,
300
- # the return value is a null string. This allows to call GetWindowText without becoming unresponsive
301
- # if the target window owner process is not responding. However, if the unresponsive target window
302
- # belongs to the calling app, GetWindowText will cause the calling app to become unresponsive.
303
- # - To retrieve the text of a control in another process, send a WM_GETTEXT message directly instead
304
- # of calling GetWindowText.
305
- #
306
- #:call-seq:
307
- # text = [get_]window_text( win_handle )
308
- #
309
- function :GetWindowText, [:HWND, :pointer, :int], :int, &return_string
310
-
311
- ##
312
- # GetWindowTextW is a Unicode version of GetWindowText (returns rstripped utf-8 string)
313
- # API improved to require only win_handle and return rstripped string
314
- #
315
- #:call-seq:
316
- # text = [get_]window_text_w( win_handle )
317
- #
318
- function :GetWindowTextW, [:HWND, :pointer, :int], :int, &return_string('utf-8')
319
-
320
- ##
321
- # GetClassName retrieves the name of the class to which the specified window belongs.
322
- # [*Syntax*] int GetClassName( HWND hWnd, LPTSTR lpClassName, int nMaxCount );
323
- # *Original* Parameters:
324
- # hWnd:: [in] Handle to the window and, indirectly, the class to which the window belongs.
325
- # lpClassName:: [out] Pointer to the buffer that is to receive the class name string.
326
- # nMaxCount:: [in] Specifies the length, in TCHAR, of the buffer pointed to by the lpClassName parameter.
327
- # The class name string is truncated if it is longer than the buffer and is always null-terminated.
328
- # *Original* Return:: Length, in characters, of the copied string, not including the terminating null character,
329
- # indicates success. Zero indicates that the window has no title bar or text, if the title
330
- # bar is empty, or if the window or control handle is invalid.
331
- # ---
332
- # API improved to require only win_handle and return rstripped string
333
- #
334
- # *Enhanced* Parameters:
335
- # win_handle:: Handle to the window and, indirectly, the class to which the window belongs.
336
- # *Returns*:: Name of the class or *nil* if function fails. For extended error information, call GetLastError.
337
- #
338
- #:call-seq:
339
- # text = [get_]class_name( win_handle )
340
- #
341
- function :GetClassName, [:HWND, :pointer, :int], :int, &return_string
342
-
343
- ##
344
- # GetClassNameW is a Unicode version of GetClassName (returns rstripped utf-8 string)
345
- # API improved to require only win_handle and return rstripped string
346
- #
347
- #:call-seq:
348
- # text = [get_]class_name_w( win_handle )
349
- #
350
- function :GetClassNameW, [:HWND, :pointer, :int], :int, &return_string('utf-8')
351
-
352
- ##
353
- # ShowWindow shows and hides windows (sets the specified window's show state).
354
- #
355
- # [*Syntax*] BOOL ShowWindow( HWND hWnd, int nCmdShow);
356
- #
357
- # hWnd:: Handle to the window.
358
- # nCmdShow:: Specifies how the window is to be shown. This parameter is ignored the first time an
359
- # application calls ShowWindow, if the program that launched the application provides a
360
- # STARTUPINFO structure. Otherwise, the first time ShowWindow is called, the value should
361
- # be the value obtained by the WinMain function in its nCmdShow parameter. In subsequent
362
- # calls, cmd may be:
363
- # SW_HIDE, SW_MAXIMIZE, SW_MINIMIZE, SW_SHOW, SW_SHOWMAXIMIZED, SW_SHOWMINIMIZED, SW_SHOWMINNOACTIVE,
364
- # SW_SHOWNA, SW_SHOWNOACTIVATE, SW_SHOWNORMAL, SW_RESTORE, SW_SHOWDEFAULT, SW_FORCEMINIMIZE
365
- #
366
- # *Returns*:: *True* if the window was PREVIOUSLY visible, otherwise *false*
367
- #
368
- #:call-seq:
369
- # was_visible = show_window( win_handle, cmd )
370
- #
371
- function :ShowWindow, [:HWND, :int], :int, boolean: true,
372
- &->(api, handle, cmd=SW_SHOW) { api.call handle, cmd }
373
-
374
- ##
375
- # The CloseWindow function minimizes (but does not destroy) the specified window.
376
- #
377
- # [*Syntax*]: BOOL CloseWindow( HWND hWnd );
378
- #
379
- # hWnd:: [in] Handle to the window to be minimized.
380
- #
381
- # *Returns*:: If the function succeeds, the return value is nonzero (*true* in snake_case method). If the function
382
- # fails, the return value is zero (*false). To get extended error information, call GetLastError.
383
- # ---
384
- # *Remarks*:
385
- # To destroy a window, an application must use the DestroyWindow function.
386
- #
387
- function :CloseWindow, [:HWND], :int, boolean: true
388
-
389
- ##
390
- # DestroyWindow function destroys the specified window. The function sends WM_DESTROY and WM_NCDESTROY messages
391
- # to the window to deactivate it and remove the keyboard focus from it. The function also destroys the window's
392
- # menu, flushes the thread message queue, destroys timers, removes clipboard ownership, and breaks the clipboard
393
- # viewer chain (if the window is at the top of the viewer chain).
394
- #
395
- # If the specified window is a parent or owner window, DestroyWindow automatically destroys the associated child
396
- # or owned windows when it destroys the parent or owner window. The function first destroys child or owned
397
- # windows, and then it destroys the parent or owner window.
398
- #
399
- # DestroyWindow also destroys modeless dialog boxes created by the CreateDialog function.
400
- #
401
- # [*Syntax*]: BOOL DestroyWindow( HWND hWnd );
402
- #
403
- # hWnd:: [in] Handle to the window to be destroyed.
404
- #
405
- # *Returns*:: If the function succeeds, the return value is nonzero (snake_case method: *true*). If the function
406
- # fails, the return value is zero (*false*). To get extended error information, call GetLastError.
407
- # ---
408
- # *Remarks*:
409
- # A thread <b>cannot use DestroyWindow to destroy a window created by a different thread.</b> Use a convenience
410
- # method destroy_unowned_window instead (it relies on
411
- # If the window being destroyed is a child window that does not have the WS_EX_NOPARENTNOTIFY style, a
412
- # WM_PARENTNOTIFY message is sent to the parent.
413
- #
414
- function :DestroyWindow, [:HWND], :int, boolean: true
415
-
416
- ##
417
- # GetWindowThreadProcessId retrieves the identifier of the thread that created the specified window
418
- # and, optionally, the identifier of the process that created the window.
419
- #
420
- # [*Syntax*] DWORD GetWindowThreadProcessId( HWND hWnd, LPDWORD lpdwProcessId );
421
- #
422
- # *Original* Parameters:
423
- # hWnd:: [in] Handle to the window.
424
- # lpdwProcessId:: [out] Pointer to a variable that receives the process identifier. If this parameter
425
- # is not NULL, GetWindowThreadProcessId copies the identifier of the process to the
426
- # variable; otherwise, it does not.
427
- # *Original* Return:: The identifier of the thread that created the window.
428
- # ---
429
- # API improved to accept window handle as a single arg and return a pair of [thread, process] ids
430
- #
431
- # *New* Parameters:
432
- # handle:: Handle to the window.
433
- # *Returns*: Pair of identifiers of the thread and process_id that created the window.
434
- #
435
- #:call-seq:
436
- # thread, process_id = [get_]window_tread_process_id( win_handle )
437
- #
438
- function :GetWindowThreadProcessId, [:HWND, :pointer], :long,
439
- &->(api, handle) {
440
- process = FFI::MemoryPointer.new(:long).write_long(1)
441
- thread = api.call(handle, process)
442
- thread == 0 ? [nil, nil] : [thread, process.read_long()] }
443
- # weird lambda literal instead of normal block is needed because current version of RDoc
444
- # goes crazy if block is attached to meta-definition
445
-
446
- ##
447
- # GetWindowRect retrieves the dimensions of the specified window bounding rectangle.
448
- # Dimensions are given relative to the upper-left corner of the screen.
449
- #
450
- # [*Syntax*] BOOL GetWindowRect( HWND hWnd, LPRECT lpRect );
451
- #
452
- # *Original* Parameters:
453
- # hWnd:: [in] Handle to the window.
454
- # lpRect:: [out] Pointer to a structure that receives the screen coordinates of the upper-left and
455
- # lower-right corners of the window.
456
- # *Original* Return:: Nonzero indicates success. Zero indicates failure. For error info, call GetLastError.
457
- # ---
458
- # API improved to accept only window handle and return 4-member dimensions array (left, top, right, bottom)
459
- #
460
- # *New* Parameters:
461
- # win_handle:: Handle to the window
462
- # *Returns*:: Array(left, top, right, bottom) - rectangle dimensions
463
- # ---
464
- # *Remarks*: As a convention for the RECT structure, the bottom-right coordinates of the returned rectangle
465
- # are exclusive. In other words, the pixel at (right, bottom) lies immediately outside the rectangle.
466
- #
467
- #:call-seq:
468
- # rect = [get_]window_rect( win_handle )
469
- #
470
- function :GetWindowRect, [:HWND, :pointer], :int,
471
- &->(api, handle) {
472
- rect = FFI::MemoryPointer.new(:long, 4)
473
- #rect.write_array_of_long([0, 0, 0, 0])
474
- res = api.call handle, rect
475
- res == 0 ? [nil, nil, nil, nil] : rect.read_array_of_long(4) }
476
- # weird lambda literal instead of normal block is needed because current version of RDoc
477
- # goes crazy if block is attached to meta-definition
478
-
479
- ##
480
- # EnumWindowsProc is an application-defined callback function that receives top-level window handles
481
- # as a result of a call to the EnumWindows, EnumChildWindows or EnumDesktopWindows function.
482
- #
483
- # [*Syntax*] BOOL CALLBACK EnumWindowsProc( HWND hwnd, LPARAM lParam );
484
- #
485
- # hWnd:: [in] Handle to a top-level window.
486
- # lParam:: [in] Specifies the application-defined value given in EnumWindows or EnumDesktopWindows.
487
- # *Return* *Value*:: To continue enumeration, the callback function must return TRUE;
488
- # to stop enumeration, it must return FALSE.
489
- # ---
490
- # Remarks:
491
- # - An application must register this callback function by passing its address to EnumWindows,
492
- # EnumChildWindows or EnumDesktopWindows.
493
- # - You must ensure that the callback function sets SetLastError if it fails.
494
- #
495
- # :call-seq:
496
- # EnumWindowsProc callback block: {|win_handle, value| your callback code }
497
- #
498
- callback :EnumWindowsProc, [:HWND, :long], :bool
499
-
500
- ##
501
- # The EnumWindows function enumerates all top-level windows on the screen by passing the handle to
502
- # each window, in turn, to an application-defined callback function. EnumWindows continues until
503
- # the last top-level window is enumerated or the callback function returns FALSE.
504
- #
505
- # [*Syntax*] BOOL EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam );
506
- #
507
- # *Original* Parameters:
508
- # lpEnumFunc:: [in] Pointer to an application-defined callback function of EnumWindowsProc type.
509
- # lParam:: [in] Specifies an application-defined value(message) to be passed to the callback function.
510
- # *Original* Return:: Nonzero if the function succeeds, zero if the function fails. GetLastError for error info.
511
- # If callback returns zero, the return value is also zero. In this case, the callback
512
- # function should call SetLastError to obtain a meaningful error code to be returned to
513
- # the caller of EnumWindows.
514
- # ---
515
- # API improved to accept blocks (instead of callback objects) with message as an optional argument
516
- #
517
- # *New* Parameters:
518
- # message:: Specifies an application-defined value(message) to be passed to the callback block.
519
- # attached block:: Serves as an application-defined callback function (see EnumWindowsProc).
520
- # *Returns*:: *True* if the function succeeds, *false* if the function fails. GetLastError for error info.
521
- # If callback returned zero/false, the return value is also false. In this case, the callback
522
- # function should call SetLastError to obtain a meaningful error code to be returned to the
523
- # caller of EnumWindows.
524
- # ---
525
- # *Remarks*: The EnumWindows function does not enumerate child windows, with the exception of a few top-level
526
- # windows owned by the system that have the WS_CHILD style. This function is more reliable than calling
527
- # the GetWindow function in a loop. An application that calls GetWindow to perform this task risks being
528
- # caught in an infinite loop or referencing a handle to a window that has been destroyed.
529
- #
530
- # :call-seq:
531
- # handles = enum_windows( [value=0] ) {|handle, value| your callback procedure }
532
- #
533
- function :EnumWindows, [:EnumWindowsProc, :long], :int8, &return_enum
534
-
535
- ##
536
- # EnumDesktopWindows Function enumerates all top-level windows associated with the specified desktop.
537
- # It passes the handle to each window, in turn, to an application-defined callback function.
538
- #
539
- # [*Syntax*] BOOL WINAPI EnumDesktopWindows( __in_opt HDESK hDesktop, __in WNDENUMPROC lpfn, __in LPARAM lParam);
540
- #
541
- # *Original* Parameters:
542
- # hDesktop:: A handle to the desktop whose top-level windows are to be enumerated. This handle is returned by
543
- # the CreateDesktop, GetThreadDesktop, OpenDesktop, or OpenInputDesktop function, and must have the
544
- # DESKTOP_ENUMERATE access right. For more information, see Desktop Security and Access Rights.
545
- # If this parameter is NULL, the current desktop is used.
546
- # lpfn:: A pointer to an application-defined EnumWindowsProc callback.
547
- # lParam:: An application-defined value to be passed to the callback.
548
- # *Return*:: If the function fails or is unable to perform the enumeration, the return value is zero.
549
- # To get extended error information, call GetLastError. You must ensure that the callback function
550
- # sets SetLastError if it fails.
551
- # ---
552
- # API enhanced to return *true*/*false* instead of nonzero/zero, and message value is optional (defaults to 0).
553
- #
554
- # *Enhanced*12 34 Parameters:
555
- # desktop:: A handle to the desktop whose top-level windows are to be enumerated.
556
- # value:: Specifies an application-defined value(message) to be passed to the callback (default 0).
557
- # attached block:: Serves as an application-defined callback function (see EnumWindowsProc).
558
- # ---
559
- # *Remarks*:
560
- # - Windows Server 2003 and Windows XP/2000: If there are no windows on the desktop, GetLastError returns
561
- # ERROR_INVALID_HANDLE.
562
- # - The EnumDesktopWindows function repeatedly invokes the callback function until the last top-level window
563
- # is enumerated or the callback function returns FALSE.
564
- # ---
565
- # *Requirements*:
566
- # Client Requires Windows Vista, Windows XP, or Windows 2000 Professional.
567
- #
568
- # :call-seq:
569
- # handles = enum_desktop_windows( desktop_handle, [value=0] ) {|handle, value| your callback procedure }
570
- #
571
- function :EnumDesktopWindows, [:ulong, :EnumWindowsProc, :long], :int8, &return_enum
572
-
573
- ##
574
- # The EnumChildWindows function enumerates the child windows that belong to the specified parent window by
575
- # passing the handle of each child window, in turn, to an application-defined callback. EnumChildWindows
576
- # continues until the last child window is enumerated or the callback function returns FALSE.
577
- #
578
- # [*Syntax*] BOOL EnumChildWindows( HWND hWndParent, WNDENUMPROC lpEnumFunc, LPARAM lParam );
579
- #
580
- # *Original* Parameters:
581
- # hWndParent:: [in] Handle to the parent window whose child windows are to be enumerated. If this parameter
582
- # is NULL, this function is equivalent to EnumWindows.
583
- # Windows 95/98/Me: hWndParent cannot be NULL.
584
- # lpEnumFunc:: [in] Pointer to an application-defined callback. For more information, see EnumChildProc.
585
- # lParam:: [in] Specifies an application-defined value to be passed to the callback function.
586
- #
587
- # *Return*:: Not used!
588
- # ---
589
- # API improved to accept blocks (instead of callback objects) and parent handle (value is optional, default 0)
590
- #
591
- # *New* Parameters:
592
- # parent:: Handle to the parent window whose child windows are to be enumerated.
593
- # value:: Specifies an application-defined value(message) to be passed to the callback function.
594
- # attached block:: Serves as an application-defined callback function (see EnumWindowsProc).
595
- # ---
596
- # *Remarks*:
597
- # - If a child window has created child windows of its own, EnumChildWindows enumerates those windows as well.
598
- # - A child window that is moved or repositioned in the Z order during the enumeration process will be properly
599
- # enumerated. The function does not enumerate a child window that is destroyed before being enumerated or that
600
- # is created during the enumeration process.
601
- #
602
- #:call-seq:
603
- # handles = enum_child_windows( parent_handle, [value=0] ) {|handle, value| your callback procedure }
604
- #
605
- function :EnumChildWindows, [:HWND, :EnumWindowsProc, :long], :int8, &return_enum
606
-
607
- ##
608
- # GetForegroundWindow function returns a handle to the foreground window (the window with which the user
609
- # is currently working). The system assigns a slightly higher priority to the thread that creates the
610
- # foreground window than it does to other threads.
611
- #
612
- # [*Syntax*] HWND GetForegroundWindow(VOID);
613
- #
614
- # *Returns*:: The return value is a handle to the foreground window. The foreground window can be NULL in
615
- # certain circumstances, such as when a window is losing activation.
616
- #
617
- #:call-seq:
618
- # win_handle = [get_]foreground_window()
619
- #
620
- function :GetForegroundWindow, [], :HWND, zeronil: true
621
-
622
- ##
623
- # The GetActiveWindow function retrieves the window handle to the active window attached to
624
- # the calling thread's message queue.
625
- #
626
- # [*Syntax*] HWND GetActiveWindow(VOID);
627
- #
628
- # *Returns*:: The return value is the handle to the active window attached to the calling
629
- # thread's message queue. Otherwise, the return value is NULL.
630
- #
631
- # Remarks: To get the handle to the foreground window, you can use GetForegroundWindow.
632
- # To get the window handle to the active window in the message queue for another thread, use GetGUIThreadInfo.
633
- #
634
- #:call-seq:
635
- # win_handle = [get_]active_window()
636
- #
637
- function :GetActiveWindow, [], :HWND, zeronil: true
638
-
639
-
640
- # Convenience wrapper methods:
641
-
642
- ##
643
- # Hides the window and activates another window
644
- #
645
- def hide_window( win_handle )
646
- show_window(win_handle, SW_HIDE)
647
- end
648
-
649
- ##
650
- # Tests if given window handle points to foreground (topmost) window
651
- #
652
- def foreground?( win_handle )
653
- win_handle == foreground_window
654
- end
655
-
656
- ##
657
- # Shuts down the window <b>created by different thread</b> by posting WM_SYSCOMMAND, SC_CLOSE message to it.
658
- # This closely emulates user clicking on X button of the target window. As it would be expected, this
659
- # actually gives the target window chance to close gracefully (it may ask user to save data and stuff).
660
- # I have not found so far how to REALLY destroy window in different thread without it asking user anything.
661
- #
662
- def shut_window( win_handle )
663
- post_message(win_handle, Win::GUI::Message::WM_SYSCOMMAND, Win::GUI::Message::SC_CLOSE, nil)
664
- end
665
-
666
- ##
667
- # Returns text associated with window by sending WM_GETTEXT message to it.
668
- # ---
669
- # *Remarks*: It is *different* from GetWindowText that returns only window title
670
- #
671
- def text( win_handle )
672
- buffer = FFI::MemoryPointer.new :char, 1024
673
- num_chars = send_message win_handle, Win::GUI::Message::WM_GETTEXT, buffer.size, buffer
674
- num_chars == 0 ? nil : buffer.get_bytes(0, num_chars)
675
- end
676
- end
677
- end
678
- end
679
-
1
+ require 'win/library'
2
+ require 'win/gui/message' # needed because some convenience methods work via PostMessage
3
+
4
+ module Win
5
+ module Gui
6
+ # Contains constants and Win32API functions related to window manipulation
7
+ #
8
+ module Window
9
+ include Win::Library
10
+
11
+ # ShowWindow constants:
12
+
13
+ # Hides the window and activates another window.
14
+ SW_HIDE = 0
15
+ # Same as SW_SHOWNORMAL
16
+ SW_NORMAL = 1
17
+ # Activates and displays a window. If the window is minimized or maximized, the system restores it to its
18
+ # original size and position. An application should specify this flag when displaying the window for the first time.
19
+ SW_SHOWNORMAL = 1
20
+ # Activates the window and displays it as a minimized window.
21
+ SW_SHOWMINIMIZED = 2
22
+ # Activates the window and displays it as a maximized window.
23
+ SW_SHOWMAXIMIZED = 3
24
+ # Activates the window and displays it as a maximized window.
25
+ SW_MAXIMIZE = 3
26
+ # Displays a window in its most recent size and position. Similar to SW_SHOWNORMAL, but the window is not activated.
27
+ SW_SHOWNOACTIVATE = 4
28
+ # Activates the window and displays it in its current size and position.
29
+ SW_SHOW = 5
30
+ # Minimizes the specified window, activates the next top-level window in the Z order.
31
+ SW_MINIMIZE = 6
32
+ # Displays the window as a minimized window. Similar to SW_SHOWMINIMIZED, except the window is not activated.
33
+ SW_SHOWMINNOACTIVE= 7
34
+ # Displays the window in its current size and position. Similar to SW_SHOW, except the window is not activated.
35
+ SW_SHOWNA = 8
36
+ # Activates and displays the window. If the window is minimized or maximized, the system restores it to its original
37
+ # size and position. An application should specify this flag when restoring a minimized window.
38
+ SW_RESTORE = 9
39
+ # Sets the show state based on the SW_ value specified in the STARTUPINFO structure passed to the CreateProcess
40
+ # function by the program that started the application.
41
+ SW_SHOWDEFAULT = 10
42
+ # Windows 2000/XP: Minimizes a window, even if the thread that owns the window is not responding. Only use this
43
+ # flag when minimizing windows from a different thread.
44
+ SW_FORCEMINIMIZE = 11
45
+
46
+ class << self
47
+ # Def_block that calls API function expecting EnumWindowsProc callback (EnumWindows, EnumChildWindows, ...).
48
+ # Default callback pushes all passed handles into Array that is returned if Enum function call was successful.
49
+ # If runtime block is given it is called after the end of default callback (handle Array is still being
50
+ # collected and returned by the method). If Enum... function call fails, method returns nil, otherwise
51
+ # an Array of all window handles passed into callback.
52
+ #
53
+ def return_enum #:nodoc:
54
+ lambda do |api, *args, &block|
55
+ args.push 0 if args.size == api.prototype.size - 2 # If value is missing, it defaults to 0
56
+ handles = []
57
+
58
+ # Insert callback proc into appropriate place of args Array
59
+ args[api.prototype.find_index(:EnumWindowsProc), 0] =
60
+ proc do |handle, message|
61
+ handles << handle
62
+ block ? block[handle, message] : true
63
+ end
64
+ handles if api.call *args
65
+ end
66
+ end
67
+
68
+ # Helper method that creates def_block returning (possibly encoded) string as a result of
69
+ # api function call or nil if zero characters was returned by api call
70
+ #
71
+ def return_string( encode = nil ) #:nodoc:
72
+ lambda do |api, *args|
73
+ namespace.enforce_count( args, api.prototype, -2)
74
+ buffer = FFI::MemoryPointer.new :char, 1024
75
+ args += [buffer, buffer.size]
76
+ num_chars = api.call(*args)
77
+ return nil if num_chars == 0
78
+ if encode
79
+ string = buffer.get_bytes(0, num_chars*2)
80
+ string = string.force_encoding('utf-16LE').encode(encode)
81
+ else
82
+ string = buffer.get_bytes(0, num_chars)
83
+ end
84
+ string.rstrip
85
+ end
86
+ end
87
+
88
+ private :return_enum, :return_string
89
+ end
90
+
91
+ # Windows GUI API definitions:
92
+
93
+ ##
94
+ # The IsWindow function determines whether the specified window handle identifies an existing window.
95
+ # [*Syntax*] BOOL IsWindow( HWND hWnd );
96
+ #
97
+ # hWnd:: [in] Handle to the window to test.
98
+ #
99
+ # *Returns*:: If the window handle identifies an existing window, the return value is (*true*).
100
+ # If the window handle does not identify an existing window, the return value is (*false*).
101
+ # ---
102
+ # *remarks*:
103
+ # A thread should not use IsWindow for a window that it did not create because the window
104
+ # could be destroyed after this function was called. Further, because window handles are
105
+ # recycled the handle could even point to a different window.
106
+ #
107
+ # :call-seq:
108
+ # window?( win_handle )
109
+ #
110
+ function :IsWindow, [:HWND], :int, boolean: true
111
+
112
+ ##
113
+ # The IsWindowVisible function retrieves the visibility state of the specified window.
114
+ # [*Syntax*] BOOL IsWindowVisible( HWND hWnd );
115
+ #
116
+ # hWnd:: [in] Handle to the window to test.
117
+ #
118
+ # *Returns*:: If the specified window, its parent window, its parent's parent window, and so forth,
119
+ # have the WS_VISIBLE style set, return value is *true*. Because the return value specifies
120
+ # whether the window has the WS_VISIBLE style, it may be true even if the window is totally
121
+ # obscured by other windows.
122
+ # ---
123
+ # *Remarks*:
124
+ # - The visibility state of a window is indicated by the WS_VISIBLE style bit. When WS_VISIBLE is set,
125
+ # the window is displayed and subsequent drawing into it is displayed as long as the window has the
126
+ # WS_VISIBLE style.
127
+ # - Any drawing to a window with the WS_VISIBLE style will not be displayed if the window is obscured
128
+ # by other windows or is clipped by its parent window.
129
+ #
130
+ # :call-seq:
131
+ # [window_]visible?( win_handle )
132
+ #
133
+ function :IsWindowVisible, [:HWND], :int, boolean: true, aliases: :visible?
134
+
135
+ ##
136
+ # Tests whether the specified window is maximized.
137
+ # [*Syntax*] BOOL IsZoomed( HWND hWnd );
138
+ #
139
+ # hWnd:: [in] Handle to the window to test.
140
+ #
141
+ # *Returns*:: If the window is zoomed (maximized), the return value is *true*.
142
+ # If the window is not zoomed (maximized), the return value is *false*.
143
+ #
144
+ # :call-seq:
145
+ # zoomed?( win_handle ), maximized?( win_handle )
146
+ #
147
+ function :IsZoomed, [:HWND], :int, boolean: true, aliases: :maximized?
148
+
149
+ ##
150
+ # Tests whether the specified window is minimized.
151
+ # [*Syntax*] BOOL IsIconic( HWND hWnd );
152
+ #
153
+ # hWnd:: [in] Handle to the window to test.
154
+ #
155
+ # *Returns*:: If the window is iconic (minimized), the return value is *true*.
156
+ # If the window is not iconic (minimized), the return value is *false*.
157
+ #
158
+ # :call-seq:
159
+ # iconic?( win_handle ), minimized?( win_handle )
160
+ #
161
+ function :IsIconic, [:HWND], :int, boolean: true, aliases: :minimized?
162
+
163
+ ##
164
+ # Tests whether a window is a child (or descendant) window of a specified parent window.
165
+ # A child window is the direct descendant of a specified parent window if that parent window
166
+ # is in the chain of parent windows; the chain of parent windows leads from the original overlapped
167
+ # or pop-up window to the child window.
168
+ #
169
+ # [*Syntax*] BOOL IsChild( HWND hWndParent, HWND hWnd);
170
+ #
171
+ # hWndParent:: [in] Handle to the parent window.
172
+ # hWnd:: [in] Handle to the window to be tested.
173
+ #
174
+ # *Returns*:: If the window is a child or descendant window of the specified parent window,
175
+ # the return value is *true*. If the window is not a child or descendant window of
176
+ # the specified parent window, the return value is *false*.
177
+ # :call-seq:
178
+ # child?( win_handle )
179
+ #
180
+ function :IsChild, [:HWND, :HWND], :int, boolean: true
181
+
182
+ ##
183
+ # The FindWindow function retrieves a handle to the top-level window whose class name and window name
184
+ # match the specified strings. This function does not search child windows. This function does not
185
+ # perform a case-sensitive search.
186
+ #
187
+ # To search child windows, beginning with a specified child window, use the FindWindowEx function.
188
+ #
189
+ # [*Syntax*] HWND FindWindow( LPCTSTR lpClassName, LPCTSTR lpWindowName );
190
+ #
191
+ # lpClassName:: [in] Pointer to a null-terminated string that specifies the class name or a class
192
+ # atom created by a previous call to the RegisterClass or RegisterClassEx function.
193
+ # The atom must be in the low-order word of lpClassName; the high-order word must be zero.
194
+ # If lpClassName points to a string, it specifies the window class name. The class name
195
+ # can be any name registered with RegisterClass or RegisterClassEx, or any of the
196
+ # predefined control-class names.
197
+ # If lpClassName is NULL, it finds any window whose title matches the lpWindowName parameter.
198
+ # lpWindowName:: [in] Pointer to a null-terminated string that specifies the window name (the window's title).
199
+ # If this parameter is NULL, all window names match.
200
+ # *Returns*:: If the function succeeds, the return value is a handle to the window that has the specified
201
+ # class name and window name. If the function fails, the return value is *nil*.
202
+ # To get extended error information, call GetLastError.
203
+ # ---
204
+ # *Remarks*:
205
+ # - If the lpWindowName parameter is not NULL, FindWindow calls the GetWindowText function to retrieve
206
+ # the window name for comparison. For a description of a potential problem that can arise, see the
207
+ # Remarks for GetWindowText.
208
+ # - To check if the Microsoft IntelliType version 1.x software is running, call FindWindow as follows:
209
+ # find_window("MSITPro::EventQueue", nil)
210
+ # - To check if the IntelliType version 2.0 software is running, call FindWindow as follows:
211
+ # find_window("Type32_Main_Window", nil)
212
+ # If the IntelliType software is running, it sends WM_APPCOMMAND messages to the application.
213
+ # Otherwise the application must install a hook to receive WM_APPCOMMAND messages.
214
+ #
215
+ # :call-seq:
216
+ # win_handle = find_window( class_name, win_name )
217
+ #
218
+ function :FindWindow, [:pointer, :pointer], :HWND, zeronil: true
219
+
220
+ ##
221
+ # Unicode version of FindWindow (strings must be encoded as utf-16LE AND terminate with "\x00\x00")
222
+ #
223
+ # :call-seq:
224
+ # win_handle = find_window_w( class_name, win_name )
225
+ #
226
+ function :FindWindowW, [:pointer, :pointer], :HWND, zeronil: true
227
+
228
+ ##
229
+ # The FindWindowEx function retrieves a handle to a window whose class name and window name match the specified
230
+ # strings. The function searches child windows, beginning with the one following the specified child window.
231
+ # This function does not perform a case-sensitive search.
232
+ #
233
+ # [*Syntax*] HWND FindWindowEx( HWND hwndParent, HWND hwndChildAfter, LPCTSTR lpszClass, LPCTSTR lpszWindow );
234
+ #
235
+ # hwndParent:: [in] Handle to the parent window whose child windows are to be searched.
236
+ # If hwndParent is NULL, the function uses the desktop window as the parent window.
237
+ # The function searches among windows that are child windows of the desktop.
238
+ # Microsoft Windows 2000 and Windows XP: If hwndParent is HWND_MESSAGE, the function
239
+ # searches all message-only windows.
240
+ # hwndChildAfter:: [in] Handle to a child window. The search begins with the next child window in the Z order.
241
+ # The child window must be a direct child window of hwndParent, not just a descendant window.
242
+ # If hwndChildAfter is NULL, the search begins with the first child window of hwndParent.
243
+ # Note that if both hwndParent and hwndChildAfter are NULL, the function searches all
244
+ # top-level and message-only windows.
245
+ # lpszClass:: [in] Pointer to a null-terminated string that specifies the class name or a class atom created
246
+ # by a previous call to the RegisterClass or RegisterClassEx function. The atom must be placed in
247
+ # the low-order word of lpszClass; the high-order word must be zero.
248
+ # If lpszClass is a string, it specifies the window class name. The class name can be any name
249
+ # registered with RegisterClass or RegisterClassEx, or any of the predefined control-class names,
250
+ # or it can be MAKEINTATOM(0x800). In this latter case, 0x8000 is the atom for a menu class. For
251
+ # more information, see the Remarks section of this topic.
252
+ # lpszWindow:: [in] Pointer to a null-terminated string that specifies the window name (the window's title).
253
+ # If this parameter is NULL, all window names match.
254
+ #
255
+ # *Returns*:: If the function succeeds, the return value is a handle to the window that has the specified
256
+ # class and window names. If the function fails, the return value is NULL. For extended error info,
257
+ # call GetLastError.
258
+ # ---
259
+ # *Remarks*:
260
+ # - If the lpszWindow parameter is not NULL, FindWindowEx calls the GetWindowText function to retrieve the window name for comparison. For a description of a potential problem that can arise, see the Remarks section of GetWindowText.
261
+ # - An application can call this function in the following way.
262
+ # find_window_ex( nil, nil, MAKEINTATOM(0x8000), nil )
263
+ # 0x8000 is the atom for a menu class. When an application calls this function, the function checks whether
264
+ # a context menu is being displayed that the application created.
265
+ #
266
+ # :call-seq:
267
+ # win_handle = find_window_ex( win_handle, after_child, class_name, win_name )
268
+ #
269
+ function :FindWindowEx, [:HWND, :HWND, :pointer, :pointer], :HWND, zeronil: true
270
+
271
+ ##
272
+ # GetWindowText returns the text of the specified window's title bar (if it has one).
273
+ # If the specified window is a control, the text of the control is copied. However, GetWindowText
274
+ # cannot retrieve the text of a control in another application.
275
+ #
276
+ # [*Syntax*] int GetWindowText( HWND hWnd, LPTSTR lpString, int nMaxCount );
277
+ #
278
+ # *Original* Parameters:
279
+ # hWnd:: Handle to the window and, indirectly, the class to which the window belongs.
280
+ # lpString:: Long Pointer to the buffer that is to receive the text string.
281
+ # nMaxCount:: Specifies the length, in TCHAR, of the buffer pointed to by the text parameter.
282
+ # The class name string is truncated if it is longer than the buffer and is always null-terminated.
283
+ # *Original* Return:: Length, in characters, of the copied string, not including the terminating null
284
+ # character (if success). Zero indicates that the window has no title bar or text,
285
+ # if the title bar is empty, or if the window or control handle is invalid.
286
+ # For extended error information, call GetLastError.
287
+ # ---
288
+ # Enhanced API requires only win_handle and returns rstripped text
289
+ #
290
+ # *Enhanced* Parameters:
291
+ # win_handle:: Handle to the window and, indirectly, the class to which the window belongs.
292
+ # *Returns*:: Window title bar text or nil. If the window has no title bar or text, if the title bar
293
+ # is empty, or if the window or control handle is invalid, the return value is *NIL*.
294
+ # To get extended error information, call GetLastError.
295
+ # ---
296
+ # *Remarks*: This function CANNOT retrieve the text of an edit control in ANOTHER app.
297
+ # - If the target window is owned by the current process, GetWindowText causes a WM_GETTEXT message to
298
+ # be sent to the specified window or control. If the target window is owned by another process and has
299
+ # a caption, GetWindowText retrieves the window caption text. If the window does not have a caption,
300
+ # the return value is a null string. This allows to call GetWindowText without becoming unresponsive
301
+ # if the target window owner process is not responding. However, if the unresponsive target window
302
+ # belongs to the calling app, GetWindowText will cause the calling app to become unresponsive.
303
+ # - To retrieve the text of a control in another process, send a WM_GETTEXT message directly instead
304
+ # of calling GetWindowText.
305
+ #
306
+ #:call-seq:
307
+ # text = [get_]window_text( win_handle )
308
+ #
309
+ function :GetWindowText, [:HWND, :pointer, :int], :int, &return_string
310
+
311
+ ##
312
+ # GetWindowTextW is a Unicode version of GetWindowText (returns rstripped utf-8 string)
313
+ # API improved to require only win_handle and return rstripped string
314
+ #
315
+ #:call-seq:
316
+ # text = [get_]window_text_w( win_handle )
317
+ #
318
+ function :GetWindowTextW, [:HWND, :pointer, :int], :int, &return_string('utf-8')
319
+
320
+ ##
321
+ # GetClassName retrieves the name of the class to which the specified window belongs.
322
+ # [*Syntax*] int GetClassName( HWND hWnd, LPTSTR lpClassName, int nMaxCount );
323
+ # *Original* Parameters:
324
+ # hWnd:: [in] Handle to the window and, indirectly, the class to which the window belongs.
325
+ # lpClassName:: [out] Pointer to the buffer that is to receive the class name string.
326
+ # nMaxCount:: [in] Specifies the length, in TCHAR, of the buffer pointed to by the lpClassName parameter.
327
+ # The class name string is truncated if it is longer than the buffer and is always null-terminated.
328
+ # *Original* Return:: Length, in characters, of the copied string, not including the terminating null character,
329
+ # indicates success. Zero indicates that the window has no title bar or text, if the title
330
+ # bar is empty, or if the window or control handle is invalid.
331
+ # ---
332
+ # API improved to require only win_handle and return rstripped string
333
+ #
334
+ # *Enhanced* Parameters:
335
+ # win_handle:: Handle to the window and, indirectly, the class to which the window belongs.
336
+ # *Returns*:: Name of the class or *nil* if function fails. For extended error information, call GetLastError.
337
+ #
338
+ #:call-seq:
339
+ # text = [get_]class_name( win_handle )
340
+ #
341
+ function :GetClassName, [:HWND, :pointer, :int], :int, &return_string
342
+
343
+ ##
344
+ # GetClassNameW is a Unicode version of GetClassName (returns rstripped utf-8 string)
345
+ # API improved to require only win_handle and return rstripped string
346
+ #
347
+ #:call-seq:
348
+ # text = [get_]class_name_w( win_handle )
349
+ #
350
+ function :GetClassNameW, [:HWND, :pointer, :int], :int, &return_string('utf-8')
351
+
352
+ ##
353
+ # ShowWindow shows and hides windows (sets the specified window's show state).
354
+ #
355
+ # [*Syntax*] BOOL ShowWindow( HWND hWnd, int nCmdShow);
356
+ #
357
+ # hWnd:: Handle to the window.
358
+ # nCmdShow:: Specifies how the window is to be shown. This parameter is ignored the first time an
359
+ # application calls ShowWindow, if the program that launched the application provides a
360
+ # STARTUPINFO structure. Otherwise, the first time ShowWindow is called, the value should
361
+ # be the value obtained by the WinMain function in its nCmdShow parameter. In subsequent
362
+ # calls, cmd may be:
363
+ # SW_HIDE, SW_MAXIMIZE, SW_MINIMIZE, SW_SHOW, SW_SHOWMAXIMIZED, SW_SHOWMINIMIZED, SW_SHOWMINNOACTIVE,
364
+ # SW_SHOWNA, SW_SHOWNOACTIVATE, SW_SHOWNORMAL, SW_RESTORE, SW_SHOWDEFAULT, SW_FORCEMINIMIZE
365
+ #
366
+ # *Returns*:: *True* if the window was PREVIOUSLY visible, otherwise *false*
367
+ #
368
+ #:call-seq:
369
+ # was_visible = show_window( win_handle, cmd )
370
+ #
371
+ function :ShowWindow, [:HWND, :int], :int, boolean: true,
372
+ &->(api, handle, cmd=SW_SHOW) { api.call handle, cmd }
373
+
374
+ ##
375
+ # The CloseWindow function minimizes (but does not destroy) the specified window.
376
+ #
377
+ # [*Syntax*]: BOOL CloseWindow( HWND hWnd );
378
+ #
379
+ # hWnd:: [in] Handle to the window to be minimized.
380
+ #
381
+ # *Returns*:: If the function succeeds, the return value is nonzero (*true* in snake_case method). If the function
382
+ # fails, the return value is zero (*false). To get extended error information, call GetLastError.
383
+ # ---
384
+ # *Remarks*:
385
+ # To destroy a window, an application must use the DestroyWindow function.
386
+ #
387
+ function :CloseWindow, [:HWND], :int, boolean: true
388
+
389
+ ##
390
+ # DestroyWindow function destroys the specified window. The function sends WM_DESTROY and WM_NCDESTROY messages
391
+ # to the window to deactivate it and remove the keyboard focus from it. The function also destroys the window's
392
+ # menu, flushes the thread message queue, destroys timers, removes clipboard ownership, and breaks the clipboard
393
+ # viewer chain (if the window is at the top of the viewer chain).
394
+ #
395
+ # If the specified window is a parent or owner window, DestroyWindow automatically destroys the associated child
396
+ # or owned windows when it destroys the parent or owner window. The function first destroys child or owned
397
+ # windows, and then it destroys the parent or owner window.
398
+ #
399
+ # DestroyWindow also destroys modeless dialog boxes created by the CreateDialog function.
400
+ #
401
+ # [*Syntax*]: BOOL DestroyWindow( HWND hWnd );
402
+ #
403
+ # hWnd:: [in] Handle to the window to be destroyed.
404
+ #
405
+ # *Returns*:: If the function succeeds, the return value is nonzero (snake_case method: *true*). If the function
406
+ # fails, the return value is zero (*false*). To get extended error information, call GetLastError.
407
+ # ---
408
+ # *Remarks*:
409
+ # A thread <b>cannot use DestroyWindow to destroy a window created by a different thread.</b> Use a convenience
410
+ # method destroy_unowned_window instead (it relies on
411
+ # If the window being destroyed is a child window that does not have the WS_EX_NOPARENTNOTIFY style, a
412
+ # WM_PARENTNOTIFY message is sent to the parent.
413
+ #
414
+ function :DestroyWindow, [:HWND], :int, boolean: true
415
+
416
+ ##
417
+ # GetWindowThreadProcessId retrieves the identifier of the thread that created the specified window
418
+ # and, optionally, the identifier of the process that created the window.
419
+ #
420
+ # [*Syntax*] DWORD GetWindowThreadProcessId( HWND hWnd, LPDWORD lpdwProcessId );
421
+ #
422
+ # *Original* Parameters:
423
+ # hWnd:: [in] Handle to the window.
424
+ # lpdwProcessId:: [out] Pointer to a variable that receives the process identifier. If this parameter
425
+ # is not NULL, GetWindowThreadProcessId copies the identifier of the process to the
426
+ # variable; otherwise, it does not.
427
+ # *Original* Return:: The identifier of the thread that created the window.
428
+ # ---
429
+ # API improved to accept window handle as a single arg and return a pair of [thread, process] ids
430
+ #
431
+ # *New* Parameters:
432
+ # handle:: Handle to the window.
433
+ # *Returns*: Pair of identifiers of the thread and process_id that created the window.
434
+ #
435
+ #:call-seq:
436
+ # thread, process_id = [get_]window_tread_process_id( win_handle )
437
+ #
438
+ function :GetWindowThreadProcessId, [:HWND, :pointer], :long,
439
+ &->(api, handle) {
440
+ process = FFI::MemoryPointer.new(:long).write_long(1)
441
+ thread = api.call(handle, process)
442
+ thread == 0 ? [nil, nil] : [thread, process.read_long()] }
443
+ # weird lambda literal instead of normal block is needed because current version of RDoc
444
+ # goes crazy if block is attached to meta-definition
445
+
446
+ ##
447
+ # GetWindowRect retrieves the dimensions of the specified window bounding rectangle.
448
+ # Dimensions are given relative to the upper-left corner of the screen.
449
+ #
450
+ # [*Syntax*] BOOL GetWindowRect( HWND hWnd, LPRECT lpRect );
451
+ #
452
+ # *Original* Parameters:
453
+ # hWnd:: [in] Handle to the window.
454
+ # lpRect:: [out] Pointer to a structure that receives the screen coordinates of the upper-left and
455
+ # lower-right corners of the window.
456
+ # *Original* Return:: Nonzero indicates success. Zero indicates failure. For error info, call GetLastError.
457
+ # ---
458
+ # API improved to accept only window handle and return 4-member dimensions array (left, top, right, bottom)
459
+ #
460
+ # *New* Parameters:
461
+ # win_handle:: Handle to the window
462
+ # *Returns*:: Array(left, top, right, bottom) - rectangle dimensions
463
+ # ---
464
+ # *Remarks*: As a convention for the RECT structure, the bottom-right coordinates of the returned rectangle
465
+ # are exclusive. In other words, the pixel at (right, bottom) lies immediately outside the rectangle.
466
+ #
467
+ #:call-seq:
468
+ # rect = [get_]window_rect( win_handle )
469
+ #
470
+ function :GetWindowRect, [:HWND, :pointer], :int,
471
+ &->(api, handle) {
472
+ rect = FFI::MemoryPointer.new(:long, 4)
473
+ #rect.write_array_of_long([0, 0, 0, 0])
474
+ res = api.call handle, rect
475
+ res == 0 ? [nil, nil, nil, nil] : rect.read_array_of_long(4) }
476
+ # weird lambda literal instead of normal block is needed because current version of RDoc
477
+ # goes crazy if block is attached to meta-definition
478
+
479
+ ##
480
+ # EnumWindowsProc is an application-defined callback function that receives top-level window handles
481
+ # as a result of a call to the EnumWindows, EnumChildWindows or EnumDesktopWindows function.
482
+ #
483
+ # [*Syntax*] BOOL CALLBACK EnumWindowsProc( HWND hwnd, LPARAM lParam );
484
+ #
485
+ # hWnd:: [in] Handle to a top-level window.
486
+ # lParam:: [in] Specifies the application-defined value given in EnumWindows or EnumDesktopWindows.
487
+ # *Return* *Value*:: To continue enumeration, the callback function must return TRUE;
488
+ # to stop enumeration, it must return FALSE.
489
+ # ---
490
+ # Remarks:
491
+ # - An application must register this callback function by passing its address to EnumWindows,
492
+ # EnumChildWindows or EnumDesktopWindows.
493
+ # - You must ensure that the callback function sets SetLastError if it fails.
494
+ #
495
+ # :call-seq:
496
+ # EnumWindowsProc callback block: {|win_handle, value| your callback code }
497
+ #
498
+ callback :EnumWindowsProc, [:HWND, :long], :bool
499
+
500
+ ##
501
+ # The EnumWindows function enumerates all top-level windows on the screen by passing the handle to
502
+ # each window, in turn, to an application-defined callback function. EnumWindows continues until
503
+ # the last top-level window is enumerated or the callback function returns FALSE.
504
+ #
505
+ # [*Syntax*] BOOL EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam );
506
+ #
507
+ # *Original* Parameters:
508
+ # lpEnumFunc:: [in] Pointer to an application-defined callback function of EnumWindowsProc type.
509
+ # lParam:: [in] Specifies an application-defined value(message) to be passed to the callback function.
510
+ # *Original* Return:: Nonzero if the function succeeds, zero if the function fails. GetLastError for error info.
511
+ # If callback returns zero, the return value is also zero. In this case, the callback
512
+ # function should call SetLastError to obtain a meaningful error code to be returned to
513
+ # the caller of EnumWindows.
514
+ # ---
515
+ # API improved to accept blocks (instead of callback objects) with message as an optional argument
516
+ #
517
+ # *New* Parameters:
518
+ # message:: Specifies an application-defined value(message) to be passed to the callback block.
519
+ # attached block:: Serves as an application-defined callback function (see EnumWindowsProc).
520
+ # *Returns*:: *True* if the function succeeds, *false* if the function fails. GetLastError for error info.
521
+ # If callback returned zero/false, the return value is also false. In this case, the callback
522
+ # function should call SetLastError to obtain a meaningful error code to be returned to the
523
+ # caller of EnumWindows.
524
+ # ---
525
+ # *Remarks*: The EnumWindows function does not enumerate child windows, with the exception of a few top-level
526
+ # windows owned by the system that have the WS_CHILD style. This function is more reliable than calling
527
+ # the GetWindow function in a loop. An application that calls GetWindow to perform this task risks being
528
+ # caught in an infinite loop or referencing a handle to a window that has been destroyed.
529
+ #
530
+ # :call-seq:
531
+ # handles = enum_windows( [value=0] ) {|handle, value| your callback procedure }
532
+ #
533
+ function :EnumWindows, [:EnumWindowsProc, :long], :int8, &return_enum
534
+
535
+ ##
536
+ # EnumDesktopWindows Function enumerates all top-level windows associated with the specified desktop.
537
+ # It passes the handle to each window, in turn, to an application-defined callback function.
538
+ #
539
+ # [*Syntax*] BOOL WINAPI EnumDesktopWindows( __in_opt HDESK hDesktop, __in WNDENUMPROC lpfn, __in LPARAM lParam);
540
+ #
541
+ # *Original* Parameters:
542
+ # hDesktop:: A handle to the desktop whose top-level windows are to be enumerated. This handle is returned by
543
+ # the CreateDesktop, GetThreadDesktop, OpenDesktop, or OpenInputDesktop function, and must have the
544
+ # DESKTOP_ENUMERATE access right. For more information, see Desktop Security and Access Rights.
545
+ # If this parameter is NULL, the current desktop is used.
546
+ # lpfn:: A pointer to an application-defined EnumWindowsProc callback.
547
+ # lParam:: An application-defined value to be passed to the callback.
548
+ # *Return*:: If the function fails or is unable to perform the enumeration, the return value is zero.
549
+ # To get extended error information, call GetLastError. You must ensure that the callback function
550
+ # sets SetLastError if it fails.
551
+ # ---
552
+ # API enhanced to return *true*/*false* instead of nonzero/zero, and message value is optional (defaults to 0).
553
+ #
554
+ # *Enhanced*12 34 Parameters:
555
+ # desktop:: A handle to the desktop whose top-level windows are to be enumerated.
556
+ # value:: Specifies an application-defined value(message) to be passed to the callback (default 0).
557
+ # attached block:: Serves as an application-defined callback function (see EnumWindowsProc).
558
+ # ---
559
+ # *Remarks*:
560
+ # - Windows Server 2003 and Windows XP/2000: If there are no windows on the desktop, GetLastError returns
561
+ # ERROR_INVALID_HANDLE.
562
+ # - The EnumDesktopWindows function repeatedly invokes the callback function until the last top-level window
563
+ # is enumerated or the callback function returns FALSE.
564
+ # ---
565
+ # *Requirements*:
566
+ # Client Requires Windows Vista, Windows XP, or Windows 2000 Professional.
567
+ #
568
+ # :call-seq:
569
+ # handles = enum_desktop_windows( desktop_handle, [value=0] ) {|handle, value| your callback procedure }
570
+ #
571
+ function :EnumDesktopWindows, [:ulong, :EnumWindowsProc, :long], :int8, &return_enum
572
+
573
+ ##
574
+ # The EnumChildWindows function enumerates the child windows that belong to the specified parent window by
575
+ # passing the handle of each child window, in turn, to an application-defined callback. EnumChildWindows
576
+ # continues until the last child window is enumerated or the callback function returns FALSE.
577
+ #
578
+ # [*Syntax*] BOOL EnumChildWindows( HWND hWndParent, WNDENUMPROC lpEnumFunc, LPARAM lParam );
579
+ #
580
+ # *Original* Parameters:
581
+ # hWndParent:: [in] Handle to the parent window whose child windows are to be enumerated. If this parameter
582
+ # is NULL, this function is equivalent to EnumWindows.
583
+ # Windows 95/98/Me: hWndParent cannot be NULL.
584
+ # lpEnumFunc:: [in] Pointer to an application-defined callback. For more information, see EnumChildProc.
585
+ # lParam:: [in] Specifies an application-defined value to be passed to the callback function.
586
+ #
587
+ # *Return*:: Not used!
588
+ # ---
589
+ # API improved to accept blocks (instead of callback objects) and parent handle (value is optional, default 0)
590
+ #
591
+ # *New* Parameters:
592
+ # parent:: Handle to the parent window whose child windows are to be enumerated.
593
+ # value:: Specifies an application-defined value(message) to be passed to the callback function.
594
+ # attached block:: Serves as an application-defined callback function (see EnumWindowsProc).
595
+ # ---
596
+ # *Remarks*:
597
+ # - If a child window has created child windows of its own, EnumChildWindows enumerates those windows as well.
598
+ # - A child window that is moved or repositioned in the Z order during the enumeration process will be properly
599
+ # enumerated. The function does not enumerate a child window that is destroyed before being enumerated or that
600
+ # is created during the enumeration process.
601
+ #
602
+ #:call-seq:
603
+ # handles = enum_child_windows( parent_handle, [value=0] ) {|handle, value| your callback procedure }
604
+ #
605
+ function :EnumChildWindows, [:HWND, :EnumWindowsProc, :long], :int8, &return_enum
606
+
607
+ ##
608
+ # GetForegroundWindow function returns a handle to the foreground window (the window with which the user
609
+ # is currently working). The system assigns a slightly higher priority to the thread that creates the
610
+ # foreground window than it does to other threads.
611
+ #
612
+ # [*Syntax*] HWND GetForegroundWindow(VOID);
613
+ #
614
+ # *Returns*:: The return value is a handle to the foreground window. The foreground window can be NULL in
615
+ # certain circumstances, such as when a window is losing activation.
616
+ #
617
+ #:call-seq:
618
+ # win_handle = [get_]foreground_window()
619
+ #
620
+ function :GetForegroundWindow, [], :HWND, zeronil: true
621
+
622
+ ##
623
+ # The GetActiveWindow function retrieves the window handle to the active window attached to
624
+ # the calling thread's message queue.
625
+ #
626
+ # [*Syntax*] HWND GetActiveWindow(VOID);
627
+ #
628
+ # *Returns*:: The return value is the handle to the active window attached to the calling
629
+ # thread's message queue. Otherwise, the return value is NULL.
630
+ #
631
+ # Remarks: To get the handle to the foreground window, you can use GetForegroundWindow.
632
+ # To get the window handle to the active window in the message queue for another thread, use GetGuiThreadInfo.
633
+ #
634
+ #:call-seq:
635
+ # win_handle = [get_]active_window()
636
+ #
637
+ function :GetActiveWindow, [], :HWND, zeronil: true
638
+
639
+
640
+ # Convenience wrapper methods:
641
+
642
+ ##
643
+ # Hides the window and activates another window
644
+ #
645
+ def hide_window( win_handle )
646
+ show_window(win_handle, SW_HIDE)
647
+ end
648
+
649
+ ##
650
+ # Tests if given window handle points to foreground (topmost) window
651
+ #
652
+ def foreground?( win_handle )
653
+ win_handle == foreground_window
654
+ end
655
+
656
+ ##
657
+ # Shuts down the window <b>created by different thread</b> by posting WM_SYSCOMMAND, SC_CLOSE message to it.
658
+ # This closely emulates user clicking on X button of the target window. As it would be expected, this
659
+ # actually gives the target window chance to close gracefully (it may ask user to save data and stuff).
660
+ # I have not found so far how to REALLY destroy window in different thread without it asking user anything.
661
+ #
662
+ def shut_window( win_handle )
663
+ post_message(win_handle, Win::Gui::Message::WM_SYSCOMMAND, Win::Gui::Message::SC_CLOSE, nil)
664
+ end
665
+
666
+ ##
667
+ # Returns text associated with window by sending WM_GETTEXT message to it.
668
+ # ---
669
+ # *Remarks*: It is *different* from GetWindowText that returns only window title
670
+ #
671
+ def text( win_handle )
672
+ buffer = FFI::MemoryPointer.new :char, 1024
673
+ num_chars = send_message win_handle, Win::Gui::Message::WM_GETTEXT, buffer.size, buffer
674
+ num_chars == 0 ? nil : buffer.get_bytes(0, num_chars)
675
+ end
676
+ end
677
+ end
678
+ end
679
+