win 0.1.27 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+