win 0.1.2 → 0.1.9
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.
- data/VERSION +1 -1
- data/lib/win/dde.rb +338 -12
- data/lib/win/gui/input.rb +1 -1
- data/lib/win/gui/message.rb +95 -10
- data/lib/win/gui/window.rb +2 -3
- data/lib/win/library.rb +1 -1
- data/spec/spec_helper.rb +19 -8
- data/spec/win/dde_spec.rb +171 -7
- data/spec/win/gui/message_spec.rb +2 -0
- data/win.gemspec +2 -2
- metadata +2 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.9
|
data/lib/win/dde.rb
CHANGED
@@ -10,15 +10,53 @@ module Win
|
|
10
10
|
# Windows ANSI codepage:
|
11
11
|
CP_WINANSI = 1004
|
12
12
|
|
13
|
-
#
|
13
|
+
# DDE name service afCmd commands used by DdeNameService function:
|
14
|
+
|
15
|
+
# Registers the service name.
|
16
|
+
|
14
17
|
DNS_REGISTER = 1
|
18
|
+
# Unregisters the service name. If the hsz1 parameter is 0L, ALL service names registered by the server will be
|
19
|
+
# unregistered.
|
15
20
|
DNS_UNREGISTER = 2
|
21
|
+
# Turns on service name initiation filtering. The filter prevents a server from receiving
|
22
|
+
# XTYP_CONNECT transactions for service names it has not registered. This is the default
|
23
|
+
# setting for this filter. If a server application does not register any service names,
|
24
|
+
# the application cannot receive XTYP_WILDCONNECT transactions.
|
25
|
+
DNS_FILTERON = 4
|
26
|
+
# Turns off service name initiation filtering. If this flag is specified, the server
|
27
|
+
# receives an XTYP_CONNECT transaction whenever another DDE application calls the
|
28
|
+
# DdeConnect function, regardless of the service name.
|
29
|
+
DNS_FILTEROFF = 8
|
16
30
|
|
31
|
+
# Transaction types:
|
32
|
+
|
33
|
+
# A client uses the XTYP_CONNECT transaction to establish a conversation. A DDE server callback function,
|
34
|
+
# DdeCallback, receives this transaction when a client specifies a service name that the server supports
|
35
|
+
# (and a topic name that is not NULL) in a call to the DdeConnect function.
|
17
36
|
XTYP_CONNECT = 0x60
|
18
37
|
XTYP_DISCONNECT = 0xC0
|
38
|
+
|
39
|
+
# A client uses the XTYP_POKE transaction to send unsolicited data to the server. DDE server callback function,
|
40
|
+
# DdeCallback, receives this transaction when a client specifies XTYP_POKE in the DdeClientTransaction function.
|
19
41
|
XTYP_POKE = 0x90
|
20
42
|
XTYP_ERROR = 0x00
|
21
43
|
|
44
|
+
# Transaction confirmations:
|
45
|
+
|
46
|
+
# Transaction confirmation
|
47
|
+
DDE_FACK = 0x8000
|
48
|
+
# Server is too busy to process transaction
|
49
|
+
DDE_FBUSY = 0x4000
|
50
|
+
DDE_FDEFERUPD = 0x4000
|
51
|
+
DDE_FACKREQ = 0x8000
|
52
|
+
DDE_FRELEASE = 0x2000
|
53
|
+
DDE_FREQUESTED = 0x1000
|
54
|
+
DDE_FAPPSTATUS = 0x00ff
|
55
|
+
# Transaction rejected
|
56
|
+
DDE_FNOTPROCESSED = 0
|
57
|
+
|
58
|
+
# DdeInitialize afCmd flaggs:
|
59
|
+
|
22
60
|
# Registers the application as a standard (nonmonitoring) DDEML application.
|
23
61
|
APPCLASS_STANDARD = 0
|
24
62
|
# Makes it possible for the application to monitor DDE activity in the system.
|
@@ -87,14 +125,41 @@ module Win
|
|
87
125
|
MF_CONV = 0x40000000
|
88
126
|
# ?
|
89
127
|
MF_MASK = 0xFF000000
|
128
|
+
|
129
|
+
# Error codes:
|
130
|
+
|
90
131
|
# Returned if DDE Init successful
|
91
132
|
DMLERR_NO_ERROR = 0x00
|
92
|
-
#
|
133
|
+
# An application initialized as APPCLASS_MONITOR has attempted to perform a Dynamic Data Exchange (DDE) transaction,
|
134
|
+
# or an application initialized as APPCMD_CLIENTONLY has attempted to perform server transactions.
|
93
135
|
DMLERR_DLL_USAGE = 0x4004
|
94
|
-
#
|
136
|
+
# DMLERR_INVALIDPARAMETER A parameter failed to be validated by the DDEML. Some of the possible causes follow:
|
137
|
+
# - The application used a data handle initialized with a different item name handle than was required by the
|
138
|
+
# transaction.
|
139
|
+
# - The application used a data handle that was initialized with a different clipboard data format than was
|
140
|
+
# required by the transaction.
|
141
|
+
# - The application used a client-side conversation handle with a server-side function or vice versa.
|
142
|
+
# - The application used a freed data handle or string handle.
|
143
|
+
# - More than one instance of the application used the same object.
|
95
144
|
DMLERR_INVALIDPARAMETER = 0x4006
|
96
|
-
#
|
145
|
+
# DMLERR_SYS_ERROR An internal error has occurred in the DDEML.
|
97
146
|
DMLERR_SYS_ERROR = 0x400f
|
147
|
+
# DMLERR_ADVACKTIMEOUT A request for a synchronous advise transaction has timed out.
|
148
|
+
# DMLERR_BUSY The response to the transaction caused the DDE_FBUSY flag to be set.
|
149
|
+
# DMLERR_DATAACKTIMEOUT A request for a synchronous data transaction has timed out.
|
150
|
+
# DMLERR_DLL_NOT_INITIALIZED A DDEML function was called without first calling the DdeInitialize function, or an invalid instance identifier was passed to a DDEML function.
|
151
|
+
# DMLERR_DLL_USAGE
|
152
|
+
# DMLERR_EXECACKTIMEOUT A request for a synchronous execute transaction has timed out.
|
153
|
+
# DMLERR_LOW_MEMORY A DDEML application has created a prolonged race condition (in which the server application outruns the client), causing large amounts of memory to be consumed.
|
154
|
+
# DMLERR_MEMORY_ERROR A memory allocation has failed.
|
155
|
+
# DMLERR_NO_CONV_ESTABLISHED A client's attempt to establish a conversation has failed.
|
156
|
+
# DMLERR_NOTPROCESSED A transaction has failed.
|
157
|
+
# DMLERR_POKEACKTIMEOUT A request for a synchronous poke transaction has timed out.
|
158
|
+
# DMLERR_POSTMSG_FAILED An internal call to the PostMessage function has failed.
|
159
|
+
# DMLERR_REENTRANCY An application instance with a synchronous transaction already in progress attempted to initiate another synchronous transaction, or the DdeEnableCallback function was called from within a DDEML callback function.
|
160
|
+
# DMLERR_SERVER_DIED A server-side transaction was attempted on a conversation terminated by the client, or the server terminated before completing a transaction.
|
161
|
+
# DMLERR_UNADVACKTIMEOUT A request to end an advise transaction has timed out.
|
162
|
+
# DMLERR_UNFOUND_QUEUE_ID An invalid transaction identifier was passed to a DDEML function. Once the application has returned from an XTYP_XACT_COMPLETE callback, the transaction identifier for that callback function is no longer valid.
|
98
163
|
|
99
164
|
##
|
100
165
|
# The RegisterClipboardFormat function registers a new clipboard format.
|
@@ -116,7 +181,7 @@ module Win
|
|
116
181
|
# form of an HGLOBAL value.
|
117
182
|
#
|
118
183
|
# :call-seq:
|
119
|
-
# register_clipboard_format( format_name )
|
184
|
+
# format_id = register_clipboard_format( format_name )
|
120
185
|
#
|
121
186
|
function :RegisterClipboardFormat, [:pointer], :uint, zeronil: true
|
122
187
|
|
@@ -135,7 +200,22 @@ module Win
|
|
135
200
|
# - XCLASS_BOOL - A DDE callback function should return TRUE or FALSE when it finishes processing a
|
136
201
|
# transaction that belongs to this class. The XCLASS_BOOL class consists of the following types:
|
137
202
|
# - XTYP_ADVSTART
|
138
|
-
# - XTYP_CONNECT
|
203
|
+
# - *XTYP_CONNECT*: A client uses the XTYP_CONNECT transaction to establish a conversation.
|
204
|
+
# hsz1:: Handle to the topic name.
|
205
|
+
# hsz2:: Handle to the service name.
|
206
|
+
# dwData1:: Pointer to a CONVCONTEXT structure that contains context information for the conversation.
|
207
|
+
# If the client is not a Dynamic Data Exchange Management Library (DDEML) application,
|
208
|
+
# this parameter is 0.
|
209
|
+
# dwData2:: Specifies whether the client is the same application instance as the server. If the
|
210
|
+
# parameter is 1, the client is the same instance. If the parameter is 0, the client
|
211
|
+
# is a different instance.
|
212
|
+
# *Returns*:: A server callback function should return TRUE to allow the client to establish a
|
213
|
+
# conversation on the specified service name and topic name pair, or the function
|
214
|
+
# should return FALSE to deny the conversation. If the callback function returns TRUE
|
215
|
+
# and a conversation is successfully established, the system passes the conversation
|
216
|
+
# handle to the server by issuing an XTYP_CONNECT_CONFIRM transaction to the server's
|
217
|
+
# callback function (unless the server specified the CBF_SKIP_CONNECT_CONFIRMS flag
|
218
|
+
# in the DdeInitialize function).
|
139
219
|
# - XCLASS_DATA - A DDE callback function should return a DDE handle, the CBR_BLOCK return code, or
|
140
220
|
# NULL when it finishes processing a transaction that belongs to this class. The XCLASS_DATA
|
141
221
|
# transaction class consists of the following types:
|
@@ -147,7 +227,15 @@ module Win
|
|
147
227
|
# class consists of the following types:
|
148
228
|
# - XTYP_ADVDATA
|
149
229
|
# - XTYP_EXECUTE
|
150
|
-
# - XTYP_POKE
|
230
|
+
# - *XTYP_POKE*: A client uses the XTYP_POKE transaction to send unsolicited data to the server.
|
231
|
+
# uFmt:: Specifies the format of the data sent from the server.
|
232
|
+
# hconv:: Handle to the conversation.
|
233
|
+
# hsz1:: Handle to the topic name.
|
234
|
+
# hsz2:: Handle to the item name.
|
235
|
+
# hdata:: Handle to the data that the client is sending to the server.
|
236
|
+
# *Returns*:: A server callback function should return the DDE_FACK flag if it processes this
|
237
|
+
# transaction, the DDE_FBUSY flag if it is too busy to process this transaction,
|
238
|
+
# or the DDE_FNOTPROCESSED flag if it rejects this transaction.
|
151
239
|
# - XCLASS_NOTIFICATION - The transaction types that belong to this class are for notification purposes
|
152
240
|
# only. The return value from the callback function is ignored. The XCLASS_NOTIFICATION transaction
|
153
241
|
# class consists of the following types:
|
@@ -217,6 +305,11 @@ module Win
|
|
217
305
|
# - DMLERR_INVALIDPARAMETER
|
218
306
|
# - DMLERR_SYS_ERROR
|
219
307
|
# ---
|
308
|
+
# <b> Enhanced API accepts only 2 parameters (get rid of reserved hsz2):
|
309
|
+
# instance_id:: (optional) Application instance identifier. At initialization, this parameter should be 0, nil
|
310
|
+
# or omitted altogether. If it is nonzero/non-nil, reinitialization of the DDEML is implied.
|
311
|
+
# cmd(afCmd):: obligatory set of flags
|
312
|
+
# ---
|
220
313
|
# *Remarks*:
|
221
314
|
# - An application that uses multiple instances of the DDEML must not pass DDEML objects between instances.
|
222
315
|
# - A DDE monitoring application should not attempt to perform DDE operations (establish conversations,
|
@@ -231,19 +324,38 @@ module Win
|
|
231
324
|
# value for the iCodePage member of the CONVCONTEXT structure (CP_WINANSI or CP_WINUNICODE).
|
232
325
|
#
|
233
326
|
# :call-seq:
|
234
|
-
# instance_id, status = dde_initialize( instance_id = 0, cmd )
|
327
|
+
# instance_id, status = dde_initialize( [instance_id = 0], cmd )
|
235
328
|
# {|type, format, hconv, hsz1, hsz2, hdata, data1, data2| your dde_callback block}
|
236
329
|
#
|
237
|
-
function :DdeInitialize, [:pointer, :DdeCallback, :
|
330
|
+
function :DdeInitialize, [:pointer, :DdeCallback, :uint32, :uint32], :uint,
|
238
331
|
&->(api, old_id=0, cmd, &block){
|
239
332
|
raise ArgumentError, 'No callback block' unless block
|
240
|
-
|
241
|
-
id.write_long(old_id)
|
333
|
+
old_id = 0 unless old_id
|
334
|
+
id = FFI::MemoryPointer.new(:long).write_long(old_id)
|
242
335
|
status = api.call(id, block, cmd, 0)
|
243
336
|
id = status == 0 ? id.read_long() : nil
|
244
337
|
[id, status] }
|
245
338
|
# weird lambda literal instead of block is needed because RDoc goes crazy if block is attached to meta-definition
|
246
339
|
|
340
|
+
##
|
341
|
+
# The DdeUninitialize function frees all Dynamic Data Exchange Management Library (DDEML) resources associated
|
342
|
+
# with the calling application.
|
343
|
+
#
|
344
|
+
# [*Syntax*] BOOL DdeUninitialize( DWORD idInst);
|
345
|
+
#
|
346
|
+
# idInst:: [in] Specifies the application instance identifier obtained by a previous call to the DdeInitialize.
|
347
|
+
# *Returns*:: If the function succeeds, the return value is nonzero.
|
348
|
+
# If the function fails, the return value is zero.
|
349
|
+
# ---
|
350
|
+
# *Remarks*
|
351
|
+
# DdeUninitialize terminates any conversations currently open for the application.
|
352
|
+
#
|
353
|
+
# :call-seq:
|
354
|
+
# success = dde_uninitialize( instance_id )
|
355
|
+
#
|
356
|
+
function :DdeUninitialize, [:uint32], :int, boolean: true
|
357
|
+
|
358
|
+
|
247
359
|
##
|
248
360
|
# The DdeCreateStringHandle function creates a handle that identifies the specified string.
|
249
361
|
# A Dynamic Data Exchange (DDE) client or server application can pass the string handle as a
|
@@ -265,6 +377,8 @@ module Win
|
|
265
377
|
# The DdeGetLastError function can be used to get the error code, which can be one of the
|
266
378
|
# following values: DMLERR_NO_ERROR, DMLERR_INVALIDPARAMETER, DMLERR_SYS_ERROR
|
267
379
|
# ---
|
380
|
+
# <b> Enhanced (snake_case) API makes code_page param optional and returns *nil* if handle creation fails. </b>
|
381
|
+
# ---
|
268
382
|
# *Remarks*: The value of a string handle is not related to the case of the string it identifies.
|
269
383
|
# When an application either creates a string handle or receives one in the callback function
|
270
384
|
# and then uses the DdeKeepStringHandle function to keep it, the application must free that string
|
@@ -274,7 +388,219 @@ module Win
|
|
274
388
|
# :call-seq:
|
275
389
|
# string_handle = dde_create_string_handle( instance_id, string, code_page_id )
|
276
390
|
#
|
277
|
-
function :DdeCreateStringHandle, [:
|
391
|
+
function :DdeCreateStringHandle, [:uint32, :pointer, :int], :ulong, zeronil: true,
|
392
|
+
&->(api, instance_id, string, code_page=CP_WINANSI){ api.call(instance_id, string, code_page) }
|
393
|
+
|
394
|
+
##
|
395
|
+
# The DdeFreeStringHandle function frees a string handle in the calling application.
|
396
|
+
#
|
397
|
+
# [*Syntax*] BOOL DdeFreeStringHandle( DWORD idInst, HSZ hsz );
|
398
|
+
#
|
399
|
+
# idInst:: [in] Specifies the application instance identifier obtained by a previous call to the DdeInitialize.
|
400
|
+
# hsz:: [in, out] Handle to the string handle to be freed. This handle must have been created by a previous call
|
401
|
+
# to the DdeCreateStringHandle function.
|
402
|
+
# *Returns*:: If the function succeeds, the return value is nonzero. If the function fails, it is zero.
|
403
|
+
# ---
|
404
|
+
# <b> Enhanced snake_case API returns boolean true/false as a success indicator. </b>
|
405
|
+
# ---
|
406
|
+
# *Remarks*:
|
407
|
+
# An application can free string handles it creates with DdeCreateStringHandle but should not free those that
|
408
|
+
# the system passed to the application's Dynamic Data Exchange (DDE) callback function or those returned in the
|
409
|
+
# CONVINFO structure by the DdeQueryConvInfo function.
|
410
|
+
#
|
411
|
+
# :call-seq:
|
412
|
+
# success = dde_free_string_handle( instance_id, string_handle )
|
413
|
+
#
|
414
|
+
function :DdeFreeStringHandle, [:uint32, :ulong], :int, boolean: true
|
415
|
+
|
416
|
+
##
|
417
|
+
# The DdeQueryString function copies text associated with a string handle into a buffer.
|
418
|
+
#
|
419
|
+
# [*Syntax*] DWORD DdeQueryString( DWORD idInst, HSZ hsz, LPTSTR psz, DWORD cchMax, int iCodePage);
|
420
|
+
#
|
421
|
+
# idInst:: [in] Specifies the application instance identifier obtained by a previous call to the DdeInitialize.
|
422
|
+
# hsz:: [in] Handle to the string to copy. This handle must have been created by a previous call to the
|
423
|
+
# DdeCreateStringHandle function.
|
424
|
+
# psz:: [in, out] Pointer to a buffer that receives the string. To obtain the length of the string, this parameter
|
425
|
+
# should be set to NULL.
|
426
|
+
# cchMax:: [in] Specifies the length, in TCHARs, of the buffer pointed to by the psz parameter. For the ANSI
|
427
|
+
# version of the function, this is the number of bytes; for the Unicode version, this is the number of
|
428
|
+
# characters. If the string is longer than ( cchMax– 1), it will be truncated. If the psz parameter is
|
429
|
+
# set to NULL, this parameter is ignored.
|
430
|
+
# iCodePage:: [in] Code page used to render the string. This value should be either CP_WINANSI or CP_WINUNICODE.
|
431
|
+
#
|
432
|
+
# *Returns*:: If the psz parameter specified a valid pointer, the return value is the length, in TCHARs, of the
|
433
|
+
# returned text (not including the terminating null character). If the psz parameter specified a NULL
|
434
|
+
# pointer, the return value is the length of the text associated with the hsz parameter (not including
|
435
|
+
# the terminating null character). If an error occurs, the return value is 0L.
|
436
|
+
# ---
|
437
|
+
# <b> Enhanced (snake_case) API makes all args optional except for first (dde instance id), and returns nil if
|
438
|
+
# the function was unsuccessful.</b>
|
439
|
+
# ---
|
440
|
+
# *Remarks*
|
441
|
+
# - The string returned in the buffer is always null-terminated. If the string is longer than ( cchMax– 1),
|
442
|
+
# only the first ( cchMax– 1) characters of the string are copied.
|
443
|
+
# - If the psz parameter is NULL, the DdeQueryString function obtains the length, in bytes, of the string
|
444
|
+
# associated with the string handle. The length does not include the terminating null character.
|
445
|
+
#
|
446
|
+
# :call-seq:
|
447
|
+
# string = dde_query_string( instance_id, handle, [code_page = CP_WINANSI ] )
|
448
|
+
#
|
449
|
+
function :DdeQueryString, [:uint32, :ulong, :pointer, :uint32, :int], :uint32,
|
450
|
+
&->(api, instance_id, handle, code_page = CP_WINANSI){
|
451
|
+
buffer = FFI::MemoryPointer.new :char, 1024
|
452
|
+
num_chars = api.call(instance_id, handle, buffer, buffer.size, code_page)
|
453
|
+
num_chars == 0 ? nil : buffer.get_bytes(0, num_chars) }
|
454
|
+
|
455
|
+
##
|
456
|
+
# The DdeNameService function registers or unregisters the service names a Dynamic Data Exchange (DDE) server
|
457
|
+
# supports. This function causes the system to send XTYP_REGISTER or XTYP_UNREGISTER transactions to other running
|
458
|
+
# Dynamic Data Exchange Management Library (DDEML) client applications.
|
459
|
+
#
|
460
|
+
# [*Syntax*] HDDEDATA DdeNameService( DWORD idInst, UINT hsz1, UINT hsz2, UINT afCmd );
|
461
|
+
#
|
462
|
+
# idInst:: [in] Specifies the application instance identifier obtained by a previous call to the DdeInitialize.
|
463
|
+
# hsz1:: [in] Handle to the string that specifies the service name the server is registering or unregistering.
|
464
|
+
# An application that is unregistering all of its service names should set this parameter to 0L.
|
465
|
+
# hsz2:: Reserved; should be set to 0L.
|
466
|
+
# afCmd:: [in] Specifies the service name options. This parameter can be one of the following values.
|
467
|
+
# DNS_REGISTER:: Registers the service name.
|
468
|
+
# DNS_UNREGISTER:: Unregisters the service name. If the hsz1 parameter is 0L,
|
469
|
+
# all service names registered by the server will be unregistered.
|
470
|
+
# DNS_FILTERON:: Turns on service name initiation filtering. The filter prevents a server from receiving
|
471
|
+
# XTYP_CONNECT transactions for service names it has not registered. This is the default
|
472
|
+
# setting for this filter. If a server application does not register any service names,
|
473
|
+
# the application cannot receive XTYP_WILDCONNECT transactions.
|
474
|
+
# DNS_FILTEROFF:: Turns off service name initiation filtering. If this flag is specified, the server
|
475
|
+
# receives an XTYP_CONNECT transaction whenever another DDE application calls the
|
476
|
+
# DdeConnect function, regardless of the service name.
|
477
|
+
# *Returns*:: If the function succeeds, it returns nonzero (*true* in snake_case method). For CamelCase, that
|
478
|
+
# value is not really HDDEDATA value, but merely a Boolean indicator of success. The function is
|
479
|
+
# typed HDDEDATA to allow for future expansion of the function and more sophisticated returns.
|
480
|
+
# If the function fails, the return value is 0L (*false* in snake_case method). The DdeGetLastError
|
481
|
+
# function can be used to get the error code, which can be one of the following:
|
482
|
+
# - DMLERR_DLL_NOT_INITIALIZED
|
483
|
+
# - DMLERR_DLL_USAGE
|
484
|
+
# - DMLERR_INVALIDPARAMETER
|
485
|
+
# - DMLERR_NO_ERROR
|
486
|
+
# ---
|
487
|
+
# <b> Enhanced API accepts only 3 parameters (get rid of reserved hsz2) and returns boolean true/false. </b>
|
488
|
+
# ---
|
489
|
+
# *Remarks*:
|
490
|
+
# The service name identified by the hsz1 parameter should be a base name (that is, the name should contain no
|
491
|
+
# instance-specific information). The system generates an instance-specific name and sends it along with the
|
492
|
+
# base name during the XTYP_REGISTER and XTYP_UNREGISTER transactions. The receiving applications can then
|
493
|
+
# connect to the specific application instance.
|
494
|
+
#
|
495
|
+
# :call-seq:
|
496
|
+
# success = dde_name_service( instance_id, string_handle, cmd )
|
497
|
+
#
|
498
|
+
function :DdeNameService, [:uint32, :ulong, :ulong, :uint], :ulong,
|
499
|
+
&->(api, id, string_handle, cmd){ api.call(id, string_handle, 0, cmd) != 0 }
|
500
|
+
# weird lambda literal instead of block is needed because RDoc goes crazy if block is attached to meta-definition
|
501
|
+
|
502
|
+
##
|
503
|
+
# The DdeGetData function copies data from the specified Dynamic Data Exchange (DDE) object to the specified
|
504
|
+
# local buffer.
|
505
|
+
#
|
506
|
+
# [*Syntax*] DWORD DdeGetData( HDDEDATA hData, LPBYTE pDst, DWORD cbMax, DWORD cbOff );
|
507
|
+
#
|
508
|
+
# hData:: [in] Handle to the DDE object that contains the data to copy.
|
509
|
+
# pDst:: [out] Pointer to the buffer that receives the data. If this parameter is NULL, the DdeGetData
|
510
|
+
# function returns the amount of data, in bytes, that would be copied to the buffer.
|
511
|
+
# cbMax:: [in] Specifies the maximum amount of data, in bytes, to copy to the buffer pointed to by the pDst
|
512
|
+
# parameter. Typically, this parameter specifies the length of the buffer pointed to by pDst.
|
513
|
+
# cbOff:: [in] Specifies an offset within the DDE object. Data is copied from the object beginning at this offset.
|
514
|
+
#
|
515
|
+
# *Returns*:: If the pDst parameter points to a buffer, return value is the size, in bytes, of the memory object
|
516
|
+
# associated with the data handle or the size specified in the cbMax parameter, whichever is lower.
|
517
|
+
# If the pDst parameter is NULL, the return value is the size, in bytes, of the memory object
|
518
|
+
# associated with the data handle.
|
519
|
+
# The DdeGetLastError function can be used to get the error code, which can be one of the following:
|
520
|
+
# - DMLERR_DLL_NOT_INITIALIZED
|
521
|
+
# - DMLERR_INVALIDPARAMETER
|
522
|
+
# - DMLERR_NO_ERROR
|
523
|
+
# ---
|
524
|
+
# <b> Enhanced (snake_case) API accepts only data handle, and optionally max and offset (no need to pre-allocate
|
525
|
+
# buffer). It returns buffer with copied DDE data (FFI::MemoryPointer) or nil for failure. DDE data length is
|
526
|
+
# determined internally, no need to call function twice (first time with nil buffer just to determine length).</b>
|
527
|
+
# ---
|
528
|
+
#
|
529
|
+
# :call-seq:
|
530
|
+
# buffer, success = dde_get_data( data_handle, [max = infinite, offset = 0] )
|
531
|
+
#
|
532
|
+
function :DdeGetData, [:ulong, :pointer, :uint32, :uint32], :uint,
|
533
|
+
&->(api, data_handle, max=1073741823, offset=0){ # max is maximum DWORD Fixnum
|
534
|
+
length = api.call(data_handle, nil, 0, 0) # determining data set length
|
535
|
+
if length != 0
|
536
|
+
copy_length = length < max ? length : max
|
537
|
+
buffer = FFI::MemoryPointer.new(:char, offset + copy_length)
|
538
|
+
length = api.call(data_handle, buffer, copy_length, offset)
|
539
|
+
end
|
540
|
+
length != 0 ? buffer: nil }
|
541
|
+
# weird lambda literal instead of block is needed because RDoc goes crazy if block is attached to meta-definition
|
542
|
+
|
543
|
+
##
|
544
|
+
# DdeConnect function establishes a conversation with a server application that supports the specified service
|
545
|
+
# name and topic name pair. If more than one such server exists, the system selects only one.
|
546
|
+
#
|
547
|
+
# [*Syntax*] HCONV DdeConnect( DWORD idInst, HSZ hszService, HSZ hszTopic, PCONVCONTEXT pCC );
|
548
|
+
#
|
549
|
+
# idInst:: [in] Specifies the application instance identifier obtained by a previous call to the DdeInitialize.
|
550
|
+
# hszService:: [in] Handle to the string that specifies the service name of the server application with which
|
551
|
+
# a conversation is to be established. This handle must have been created by a previous call to
|
552
|
+
# the DdeCreateStringHandle function. If this parameter is 0L, a conversation is established with
|
553
|
+
# any available server.
|
554
|
+
# hszTopic:: [in] Handle to the string that specifies the name of the topic on which a conversation is to be
|
555
|
+
# established. This handle must have been created by a previous call to DdeCreateStringHandle.
|
556
|
+
# If this parameter is 0L, a conversation on any topic supported by the selected server is established.
|
557
|
+
# pCC:: [in] Pointer to the CONVCONTEXT structure that contains conversation context information. If this
|
558
|
+
# parameter is NULL, the server receives the default CONVCONTEXT structure during the XTYP_CONNECT
|
559
|
+
# or XTYP_WILDCONNECT transaction.
|
560
|
+
# *Returns*:: If the function succeeds, the return value is the handle to the established conversation.
|
561
|
+
# If the function fails, the return value is 0L. The DdeGetLastError function can be used to get
|
562
|
+
# the error code, which can be one of the following values:
|
563
|
+
# - DMLERR_DLL_NOT_INITIALIZED
|
564
|
+
# - DMLERR_INVALIDPARAMETER
|
565
|
+
# - DMLERR_NO_CONV_ESTABLISHED
|
566
|
+
# - DMLERR_NO_ERROR
|
567
|
+
# ---
|
568
|
+
# <b> Enhanced (snake_case) API makes all args optional except for first (dde instance id), and returns nil if
|
569
|
+
# the function was unsuccessful.</b>
|
570
|
+
# ---
|
571
|
+
# *Remarks*
|
572
|
+
# - The client application cannot make assumptions regarding the server selected. If an instance-specific name
|
573
|
+
# is specified in the hszService parameter, a conversation is established with only the specified instance.
|
574
|
+
# Instance-specific service names are passed to an application's Dynamic Data Exchange (DDE) callback function
|
575
|
+
# during the XTYP_REGISTER and XTYP_UNREGISTER transactions.
|
576
|
+
# - All members of the default CONVCONTEXT structure are set to zero except cb, which specifies the size of the
|
577
|
+
# structure, and iCodePage, which specifies CP_WINANSI (the default code page) or CP_WINUNICODE, depending on
|
578
|
+
# whether the ANSI or Unicode version of the DdeInitialize function was called by the client application.
|
579
|
+
#
|
580
|
+
# :call-seq:
|
581
|
+
# conversation_handle = dde_connect( instance_id, [service = nil, topic = nil, context = nil] )
|
582
|
+
#
|
583
|
+
function :DdeConnect, [:uint32, :ulong, :ulong, :pointer], :ulong, zeronil: true,
|
584
|
+
&->(api, instance_id, service = nil, topic = nil, context = nil){
|
585
|
+
api.call(instance_id, service, topic, context) }
|
586
|
+
|
587
|
+
##
|
588
|
+
# The DdeGetLastError function retrieves the most recent error code set by the failure of a Dynamic Data Exchange
|
589
|
+
# Management Library (DDEML) function and resets the error code to DMLERR_NO_ERROR.
|
590
|
+
#
|
591
|
+
# [*Syntax*] UINT DdeGetLastError( DWORD idInst );
|
592
|
+
#
|
593
|
+
# idInst:: [in] Specifies the application instance identifier obtained by a previous call to the DdeInitialize.
|
594
|
+
#
|
595
|
+
# *Returns*:: If the function succeeds, the return value is the last error code, which can be one of the following:
|
596
|
+
# DMLERR_ADVACKTIMEOUT, DMLERR_EXECACKTIMEOUT, DMLERR_INVALIDPARAMETER, DMLERR_LOW_MEMORY, DMLERR_MEMORY_ERROR,
|
597
|
+
# DMLERR_NO_CONV_ESTABLISHED, DMLERR_NOTPROCESSED, DMLERR_POKEACKTIMEOUT, DMLERR_POSTMSG_FAILED, DMLERR_REENTRANCY,
|
598
|
+
# DMLERR_SERVER_DIED, DMLERR_SYS_ERROR, DMLERR_UNADVACKTIMEOUT, DMLERR_UNFOUND_QUEUE_ID
|
599
|
+
#
|
600
|
+
# :call-seq:
|
601
|
+
# string = dde_get_last_error( instance_id )
|
602
|
+
#
|
603
|
+
function :DdeGetLastError, [:uint32], :int, zeronil: true
|
278
604
|
|
279
605
|
end
|
280
606
|
end
|
data/lib/win/gui/input.rb
CHANGED
@@ -251,7 +251,7 @@ module Win
|
|
251
251
|
# Y:: [in] Specifies the new y-coordinate of the cursor, in screen coordinates.
|
252
252
|
#
|
253
253
|
# *Returns*:: Nonzero(*true*) if successful or zero(*false*) otherwise. To get extended error information,
|
254
|
-
#
|
254
|
+
# call GetLastError. Enhanced to return true/false instead of nonzero/zero
|
255
255
|
# ---
|
256
256
|
# *Remarks*: The cursor is a shared resource. A window should move the cursor only when the cursor is in the
|
257
257
|
# window's client area. The calling process must have WINSTA_WRITEATTRIBUTES access to the window station.
|
data/lib/win/gui/message.rb
CHANGED
@@ -235,7 +235,7 @@ module Win
|
|
235
235
|
# App-specific (non-reserved) messages above this one (WM_App+1, etc...)
|
236
236
|
WM_APP = 0x8000
|
237
237
|
|
238
|
-
# Sys Commands:
|
238
|
+
# Sys Commands:
|
239
239
|
|
240
240
|
#
|
241
241
|
SC_SIZE = 0xF000
|
@@ -259,26 +259,67 @@ module Win
|
|
259
259
|
SC_MONITORPOWER = 0xF170
|
260
260
|
SC_CONTEXTHELP = 0xF180
|
261
261
|
|
262
|
+
##
|
262
263
|
function :BroadcastSystemMessage, 'LPIIL', 'L'
|
264
|
+
|
265
|
+
##
|
263
266
|
function :DefWindowProc, 'LLLL', 'L'
|
267
|
+
|
268
|
+
##
|
264
269
|
function :DispatchMessage, 'P', 'L'
|
270
|
+
|
271
|
+
##
|
265
272
|
function :GetInputState, 'V', 'B'
|
273
|
+
|
274
|
+
##
|
266
275
|
function :GetMessage, 'PLII', 'B'
|
276
|
+
|
277
|
+
##
|
267
278
|
function :GetMessageExtraInfo, 'V', 'L'
|
279
|
+
|
280
|
+
##
|
268
281
|
function :GetMessagePos, 'V', 'L'
|
282
|
+
|
283
|
+
##
|
269
284
|
function :GetMessageTime, 'V', 'L'
|
285
|
+
|
286
|
+
##
|
270
287
|
function :GetQueueStatus, 'I', 'L'
|
288
|
+
|
289
|
+
##
|
271
290
|
function :InSendMessage, 'V', 'B'
|
291
|
+
|
292
|
+
##
|
272
293
|
function :InSendMessageEx, 'L', 'L'
|
294
|
+
|
295
|
+
##
|
273
296
|
function :PeekMessage, 'PLIII', 'B'
|
297
|
+
|
298
|
+
##
|
274
299
|
function :PostQuitMessage, 'I', 'V'
|
300
|
+
|
301
|
+
##
|
275
302
|
function :PostThreadMessage, 'LILL', 'B'
|
303
|
+
|
304
|
+
##
|
276
305
|
function :RegisterWindowMessage, 'P', 'I'
|
306
|
+
|
307
|
+
##
|
277
308
|
function :ReplyMessage, 'L', 'B'
|
309
|
+
|
310
|
+
##
|
278
311
|
function :SendMessageTimeout, 'LILLIIP', 'L'
|
312
|
+
|
313
|
+
##
|
279
314
|
function :SendNotifyMessage, 'LILLIIP', 'L'
|
315
|
+
|
316
|
+
##
|
280
317
|
function :SetMessageExtraInfo, 'L', 'L'
|
318
|
+
|
319
|
+
##
|
281
320
|
function :TranslateMessage, 'P', 'B'
|
321
|
+
|
322
|
+
##
|
282
323
|
function :WaitMessage, 'V', 'B'
|
283
324
|
|
284
325
|
##
|
@@ -296,7 +337,7 @@ module Win
|
|
296
337
|
# lResult:: [in] Specifies the result of the message processing. This value depends on the message.
|
297
338
|
#
|
298
339
|
# :call-seq:
|
299
|
-
# SendAsyncProc callback block: {|handle, msg,
|
340
|
+
# SendAsyncProc callback block: {|handle, msg, data, l_result| your callbackcode }
|
300
341
|
#
|
301
342
|
callback :SendAsyncProc, [:long, :uint, :ulong, :ulong, :long], :void
|
302
343
|
|
@@ -334,7 +375,11 @@ module Win
|
|
334
375
|
# - The callback function is called only when the thread that called SendMessageCallback also calls GetMessage,
|
335
376
|
# PeekMessage, or WaitMessage.
|
336
377
|
#
|
337
|
-
|
378
|
+
# :call-seq:
|
379
|
+
# success = send_message_callback(handle, msg, w_param, l_param, data)
|
380
|
+
# {|handle, msg, data, l_result| callback code }
|
381
|
+
#
|
382
|
+
function :SendMessageCallback, [:long, :uint, :uint, :long, :SendAsyncProc, :ulong], :int, boolean: true
|
338
383
|
|
339
384
|
##
|
340
385
|
# The PostMessage function places (posts) a message in the message queue associated with the thread that
|
@@ -343,14 +388,14 @@ module Win
|
|
343
388
|
#
|
344
389
|
# [*Syntax*] BOOL PostMessage( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
|
345
390
|
#
|
346
|
-
#
|
391
|
+
# hWnd:: [in] Handle to the window whose window procedure will receive the message. If this parameter is
|
347
392
|
# HWND_BROADCAST, the message is sent to all top-level windows in the system, including disabled or
|
348
393
|
# invisible unowned windows, overlapped windows, and pop-up windows; but the message is not posted to
|
349
394
|
# child windows. If it is NULL, the function behaves like a call to PostThreadMessage()
|
350
395
|
# with the dwThreadId parameter set to the identifier of the current thread.
|
351
|
-
#
|
352
|
-
#
|
353
|
-
#
|
396
|
+
# Msg:: [in] Specifies the message to be posted.
|
397
|
+
# wParam:: [in] Specifies additional message-specific information.
|
398
|
+
# lParam:: [in] Specifies additional message-specific information.
|
354
399
|
#
|
355
400
|
# *Returns*:: Nonzero if the function succeeds, zero if it fails. For extended error info, call GetLastError.
|
356
401
|
# ---
|
@@ -371,10 +416,50 @@ module Win
|
|
371
416
|
#:call-seq:
|
372
417
|
# success = post_message(handle, msg, w_param, l_param)
|
373
418
|
#
|
374
|
-
function :PostMessage, [:ulong, :uint, :long, :uint], :
|
375
|
-
|
376
|
-
function :SendMessage, 'LLLP', 'L'
|
419
|
+
function :PostMessage, [:ulong, :uint, :long, :uint], :int, boolean: true
|
377
420
|
|
421
|
+
##
|
422
|
+
# The SendMessage function sends the specified message to a window or windows. It calls the window procedure for
|
423
|
+
# the specified window and does not return until the window procedure has processed the message.
|
424
|
+
#
|
425
|
+
# To send a message and return immediately, use the SendMessageCallback or SendNotifyMessage function. To post a
|
426
|
+
# message to a thread's message queue and return immediately, use the PostMessage or PostThreadMessage function.
|
427
|
+
#
|
428
|
+
#
|
429
|
+
# [*Syntax*] LRESULT SendMessage( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam );
|
430
|
+
#
|
431
|
+
# hWnd:: [in] Handle to the window whose window procedure will receive the message. If this parameter is
|
432
|
+
# HWND_BROADCAST, the message is sent to all top-level windows in the system, including disabled or
|
433
|
+
# invisible unowned windows, overlapped windows, and pop-up windows; but the message is not sent to
|
434
|
+
# child windows.
|
435
|
+
# Microsoft Windows Vista and later. Message sending is subject to User Interface Privilege Isolation
|
436
|
+
# (UIPI). The thread of a process can send messages only to message queues of threads in processes of
|
437
|
+
# lesser or equal integrity level.
|
438
|
+
# Msg:: [in] Specifies the message to be sent.
|
439
|
+
# wParam:: [in] Specifies additional message-specific information.
|
440
|
+
# lParam:: [in/out?] Specifies additional message-specific information.
|
441
|
+
#
|
442
|
+
# *Return*:: The return value specifies the result of the message processing; it depends on the message sent.
|
443
|
+
# ---
|
444
|
+
# *Remarks*:
|
445
|
+
# - Microsoft Windows Vista and later. When a message is blocked by UIPI the last error, retrieved with
|
446
|
+
# GetLastError, is set to 5 (access denied).
|
447
|
+
# - Applications that need to communicate using HWND_BROADCAST should use the RegisterWindowMessage function
|
448
|
+
# to obtain a unique message for inter-application communication.
|
449
|
+
# - The system only does marshalling for system messages (those in the range 0 to (WM_USER-1)). To send other
|
450
|
+
# messages (those >= WM_USER) to another process, you must do custom marshalling.
|
451
|
+
# - If the specified window was created by the calling thread, the window procedure is called immediately as
|
452
|
+
# a subroutine. If the specified window was created by a different thread, the system switches to that thread
|
453
|
+
# and calls the appropriate window procedure. Messages sent between threads are processed only when the
|
454
|
+
# receiving thread executes message retrieval code. The sending thread is blocked until the receiving thread
|
455
|
+
# processes the message. However, the sending thread will process incoming nonqueued messages while waiting
|
456
|
+
# for its message to be processed. To prevent this, use SendMessageTimeout with SMTO_BLOCK set. For more
|
457
|
+
# information on nonqueued messages, see Nonqueued Messages.
|
458
|
+
#
|
459
|
+
#:call-seq:
|
460
|
+
# send_message(handle, msg, w_param, l_param)
|
461
|
+
#
|
462
|
+
function :SendMessage, [:ulong, :uint, :long, :pointer], :int # LPARAM different from PostMessage!
|
378
463
|
|
379
464
|
end
|
380
465
|
end
|
data/lib/win/gui/window.rb
CHANGED
@@ -394,8 +394,7 @@ module Win
|
|
394
394
|
function :GetWindowThreadProcessId, [:ulong, :pointer], :long,
|
395
395
|
&->(api, *args) {
|
396
396
|
namespace.enforce_count( args, api.prototype, -1)
|
397
|
-
process = FFI::MemoryPointer.new(:long)
|
398
|
-
process.write_long(1)
|
397
|
+
process = FFI::MemoryPointer.new(:long).write_long(1)
|
399
398
|
thread = api.call(args.first, process)
|
400
399
|
thread == 0 ? [nil, nil] : [thread, process.read_long()] }
|
401
400
|
# weird lambda literal instead of normal block is needed because current version of RDoc
|
@@ -429,7 +428,7 @@ module Win
|
|
429
428
|
&->(api, *args) {
|
430
429
|
namespace.enforce_count( args, api.prototype, -1)
|
431
430
|
rect = FFI::MemoryPointer.new(:long, 4)
|
432
|
-
rect.write_array_of_long([0, 0, 0, 0])
|
431
|
+
#rect.write_array_of_long([0, 0, 0, 0])
|
433
432
|
res = api.call args.first, rect
|
434
433
|
res == 0 ? [nil, nil, nil, nil] : rect.read_array_of_long(4) }
|
435
434
|
# weird lambda literal instead of normal block is needed because current version of RDoc
|
data/lib/win/library.rb
CHANGED
@@ -75,7 +75,7 @@ module Win
|
|
75
75
|
c: :char, # 8-bit character (byte)
|
76
76
|
# :int8 – 8-bit signed integer
|
77
77
|
# :uint8 – 8-bit unsigned integer
|
78
|
-
S: :ushort, # – 16-bit unsigned integer (
|
78
|
+
S: :ushort, # – 16-bit unsigned integer (Win32/API: S used for string params)
|
79
79
|
s: :short, # – 16-bit signed integer
|
80
80
|
# :uint16 – 16-bit unsigned integer
|
81
81
|
# :int16 – 16-bit signed integer
|
data/spec/spec_helper.rb
CHANGED
@@ -12,17 +12,21 @@ module ClassMacros
|
|
12
12
|
# wrapper for it method that extracts description from example source code, such as:
|
13
13
|
# spec { use{ function(arg1 = 4, arg2 = 'string') }}
|
14
14
|
def spec &block
|
15
|
-
|
16
|
-
|
17
|
-
else
|
18
|
-
it description_from(*block.source_location), &block
|
19
|
-
end
|
15
|
+
it description_from(caller[0]), &block # it description_from(*block.source_location), &block
|
16
|
+
#do lambda(&block).should_not raise_error end
|
20
17
|
end
|
21
18
|
|
22
|
-
# reads description line from source file and drops external brackets
|
23
|
-
|
19
|
+
# reads description line from source file and drops external brackets like its{}, use{}
|
20
|
+
# accepts as arguments either file name and line or call stack member (caller[0])
|
21
|
+
def description_from(*args)
|
22
|
+
case args.size
|
23
|
+
when 1
|
24
|
+
file, line = args.first.scan(/\A(.*?):(\d+)/).first
|
25
|
+
when 2
|
26
|
+
file, line = args
|
27
|
+
end
|
24
28
|
File.open(file) do |f|
|
25
|
-
f.lines.to_a[line-1].gsub( /(spec.*?{)|(use.*?{)|}/, '' ).strip
|
29
|
+
f.lines.to_a[line.to_i-1].gsub( /(spec.*?{)|(use.*?{)|}/, '' ).strip
|
26
30
|
end
|
27
31
|
end
|
28
32
|
end
|
@@ -32,6 +36,7 @@ module InstanceMacros
|
|
32
36
|
def use
|
33
37
|
lambda{yield}.should_not raise_error
|
34
38
|
end
|
39
|
+
|
35
40
|
def any_block
|
36
41
|
lambda{|*args| args}
|
37
42
|
end
|
@@ -40,6 +45,12 @@ end
|
|
40
45
|
Spec::Runner.configure do |config|
|
41
46
|
config.extend(ClassMacros)
|
42
47
|
config.include(InstanceMacros)
|
48
|
+
|
49
|
+
class << Spec::ExampleGroup
|
50
|
+
# def spoc &block
|
51
|
+
# it description_from(caller[0]), &block
|
52
|
+
# end
|
53
|
+
end
|
43
54
|
end
|
44
55
|
|
45
56
|
module WinTest
|
data/spec/win/dde_spec.rb
CHANGED
@@ -13,6 +13,14 @@ module WinDDETest
|
|
13
13
|
->{}
|
14
14
|
end
|
15
15
|
|
16
|
+
def zero_id
|
17
|
+
FFI::MemoryPointer.new(:long).write_long(0)
|
18
|
+
end
|
19
|
+
|
20
|
+
def buffer
|
21
|
+
FFI::MemoryPointer.new(:char, 1024)
|
22
|
+
end
|
23
|
+
|
16
24
|
describe Win::DDE, ' contains a set of pre-defined Windows API functions' do
|
17
25
|
describe 'register_clipboard_format' do
|
18
26
|
spec{ use{ RegisterClipboardFormat(format_name = "XlTable") }}
|
@@ -36,10 +44,25 @@ module WinDDETest
|
|
36
44
|
end
|
37
45
|
|
38
46
|
describe 'dde_initialize' do
|
39
|
-
spec{ use{ status = DdeInitialize(
|
40
|
-
spec{ use{ id, status = dde_initialize(
|
47
|
+
spec{ use{ status = DdeInitialize( zero_id, dde_callback, dde_cmd, unused = 0)}}
|
48
|
+
spec{ use{ id, status = dde_initialize( instance_id = 0, dde_cmd) do|*args|
|
49
|
+
end }}
|
50
|
+
|
51
|
+
it 'with zero instance_id, returns integer id and DMLERR_NO_ERROR if initialization successful' do
|
52
|
+
id, status = dde_initialize(0, APPCLASS_STANDARD) {|*args| }
|
53
|
+
id.should be_an Integer
|
54
|
+
id.should_not == 0
|
55
|
+
status.should == DMLERR_NO_ERROR
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'with nil instance_id, returns integer id and DMLERR_NO_ERROR if initialization successful' do
|
59
|
+
id, status = dde_initialize(nil, APPCLASS_STANDARD) {|*args| }
|
60
|
+
id.should be_an Integer
|
61
|
+
id.should_not == 0
|
62
|
+
status.should == DMLERR_NO_ERROR
|
63
|
+
end
|
41
64
|
|
42
|
-
it 'returns integer id and
|
65
|
+
it 'with omitted instance_id, returns integer id and DMLERR_NO_ERROR if initialization successful' do
|
43
66
|
id, status = dde_initialize(APPCLASS_STANDARD) {|*args| }
|
44
67
|
id.should be_an Integer
|
45
68
|
id.should_not == 0
|
@@ -58,12 +81,153 @@ module WinDDETest
|
|
58
81
|
status.should == DMLERR_NO_ERROR
|
59
82
|
new_id.should == id
|
60
83
|
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'after initialization:' do
|
87
|
+
before(:each) {@instance_id, status = dde_initialize(APPCLASS_STANDARD) {|*args| }}
|
88
|
+
after(:each) {dde_uninitialize(@instance_id)}
|
89
|
+
|
90
|
+
describe '#dde_uninitialize' do
|
91
|
+
|
92
|
+
spec{ use{ status = DdeUninitialize( @instance_id ) }}
|
93
|
+
spec{ use{ id, status = dde_uninitialize( @instance_id) }}
|
94
|
+
|
95
|
+
it 'returns true if uninitialization successful' do
|
96
|
+
res = dde_uninitialize(@instance_id)
|
97
|
+
res.should == true
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'returns false if initialization unsuccessful' do
|
101
|
+
res = dde_uninitialize(12345)
|
102
|
+
res.should == false
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe '#dde_create_string_handle' do
|
107
|
+
spec{ use{ string_handle = DdeCreateStringHandle(instance_id=0, string='Any String', code_page_id=CP_WINANSI) }}
|
108
|
+
spec{ use{ string_handle = dde_create_string_handle(instance_id=0, string='Any String', code_page_id=CP_WINANSI)}}
|
109
|
+
|
110
|
+
it 'returns nonzero Integer handle to a string (passable to other DDEML functions)' do
|
111
|
+
string_handle = dde_create_string_handle(@instance_id, 'My String', CP_WINANSI)
|
112
|
+
string_handle.should be_an Integer
|
113
|
+
string_handle.should_not == 0
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'creates handle even if code_page is omitted' do
|
117
|
+
string_handle = dde_create_string_handle(@instance_id, 'My String')
|
118
|
+
string_handle.should be_an Integer
|
119
|
+
string_handle.should_not == 0
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'creating two handles for the SAME string (inside one instance) USUALLY returns same handle' do
|
123
|
+
string_handle1 = dde_create_string_handle(@instance_id, 'My String')
|
124
|
+
10.times do
|
125
|
+
string_handle2 = dde_create_string_handle(@instance_id, 'My String')
|
126
|
+
string_handle1.should == string_handle2
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'returns nil if unable to register handle to a string' do
|
131
|
+
string_handle = dde_create_string_handle(@instance_id, "", CP_WINANSI)
|
132
|
+
string_handle.should == nil
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
context "with dde string handle to 'My String':" do
|
138
|
+
before(:each) {@string_handle = dde_create_string_handle(@instance_id, 'My String', CP_WINANSI)}
|
139
|
+
after(:each) {dde_free_string_handle(@instance_id, @string_handle)}
|
140
|
+
|
141
|
+
describe '#dde_query_string' do
|
142
|
+
|
143
|
+
spec{ use{ string = DdeQueryString(@instance_id, @string_handle, buffer, buffer.size, code_page=CP_WINANSI)}}
|
144
|
+
spec{ use{ string = dde_query_string(@instance_id, @string_handle, code_page=CP_WINANSI )}}
|
145
|
+
|
146
|
+
it 'retrieves string that given string handle refers to' do
|
147
|
+
string = dde_query_string(@instance_id, @string_handle)
|
148
|
+
string.should == 'My String'
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'retrieves string even if code_page is omitted' do
|
152
|
+
string = dde_query_string(@instance_id, @string_handle)
|
153
|
+
string.should == 'My String'
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'returns nil attempting to retrieve invalid handle' do
|
157
|
+
string = dde_query_string(@instance_id, 12345)
|
158
|
+
string.should == nil
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
describe '#dde_free_string_handle' do
|
163
|
+
|
164
|
+
spec{ use{ success = DdeFreeStringHandle( @instance_id, @string_handle)}}
|
165
|
+
spec{ use{ success = dde_free_string_handle( @instance_id, @string_handle )}}
|
166
|
+
|
167
|
+
it 'returns true when freeing string handle registered with DDEML' do
|
168
|
+
res = dde_free_string_handle(@instance_id, @string_handle)
|
169
|
+
res.should == true
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'returns false attempting to free unregistered handle' do
|
173
|
+
res = dde_free_string_handle(@instance_id, 12345)
|
174
|
+
res.should == false
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
describe '#dde_name_service' do
|
179
|
+
spec{ use{ success = dde_name_service(@instance_id, @string_handle, cmd=DNS_UNREGISTER ) }}
|
180
|
+
spec{ use{ success = DdeNameService(@instance_id, @string_handle, reserved=0, cmd=DNS_UNREGISTER) }}
|
181
|
+
|
182
|
+
it 'registers or unregisters the service names that DDE server supports' do
|
183
|
+
|
184
|
+
success = dde_name_service( @instance_id, @string_handle, DNS_REGISTER )
|
185
|
+
success.should == true
|
186
|
+
|
187
|
+
success = dde_name_service( @instance_id, @string_handle, DNS_UNREGISTER )
|
188
|
+
success.should == true
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
describe '#dde_get_last_error' do
|
193
|
+
spec{ use{ error_code = DdeGetLastError( @instance_id) }}
|
194
|
+
spec{ use{ error_code = dde_get_last_error( @instance_id) }}
|
195
|
+
|
196
|
+
it 'original API returns DMLERR_NO_ERROR if there is no last DDE error for given app instance' do
|
197
|
+
DdeGetLastError( @instance_id).should == DMLERR_NO_ERROR
|
198
|
+
end
|
199
|
+
|
200
|
+
it 'snake_case API returns nil if there is no last DDE error for given app instance' do
|
201
|
+
dde_get_last_error( @instance_id).should == nil
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'returns error code of last DDE error for given app instance' do
|
205
|
+
dde_name_service( @instance_id, 1234, DNS_REGISTER )
|
206
|
+
dde_get_last_error( @instance_id).should == DMLERR_INVALIDPARAMETER
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
describe '#dde_get_data' do
|
213
|
+
spec{ use{ buffer, success = dde_get_data( data_handle = 123, max = 1073741823, offset = 0) }}
|
214
|
+
spec{ use{ length = DdeGetData( data_handle = 123, nil, 0, 0) }} # returns dde data set length
|
215
|
+
spec{ use{ length = DdeGetData( data_handle = 123, FFI::MemoryPointer.new(:char, 1024), max = 1024, offset = 0) }}
|
216
|
+
|
217
|
+
it 'original API returns 0 if trying to address invalid dde data handle' do
|
218
|
+
DdeGetData( data_handle = 123, nil, 0, 0).should == 0
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'snake_case API returns nil if trying to address invalid dde data handle' do
|
222
|
+
dde_get_data( data_handle = 123, 3741823, 0).should == nil
|
223
|
+
end
|
61
224
|
|
62
|
-
it 'returns nil if not able to initialize' do
|
63
|
-
pending
|
64
|
-
register_clipboard_format("").should == nil
|
65
225
|
end
|
226
|
+
|
227
|
+
describe '#dde_connect' do
|
228
|
+
it 'connects to existing DDE server'
|
229
|
+
end
|
230
|
+
|
66
231
|
end
|
67
232
|
end
|
68
233
|
end
|
69
|
-
|
@@ -10,6 +10,7 @@ module WinGuiMessageTest
|
|
10
10
|
describe Win::Gui::Message do
|
11
11
|
|
12
12
|
describe '#post_message' do
|
13
|
+
spec{ use{ success = PostMessage(handle = 0, msg = 0, w_param = 0, l_param = 0) }}
|
13
14
|
spec{ use{ success = post_message(handle = 0, msg = 0, w_param = 0, l_param = 0) }}
|
14
15
|
|
15
16
|
it 'places (posts) a message in the message queue associated with the thread that created the specified window'
|
@@ -17,6 +18,7 @@ module WinGuiMessageTest
|
|
17
18
|
end
|
18
19
|
|
19
20
|
describe '#send_message' do
|
21
|
+
spec{ use{ success = SendMessage(handle = 0, msg = 0, w_param = 1024, l_param = "\x0"*1024) }}
|
20
22
|
spec{ use{ success = send_message(handle = 0, msg = 0, w_param = 1024, l_param = "\x0"*1024) }}
|
21
23
|
# handle (L) - Handle to the window whose window procedure is to receive the message. The following values have special meanings.
|
22
24
|
# HWND_BROADCAST - The message is posted to all top-level windows in the system, including disabled or invisible unowned windows,
|
data/win.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{win}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.9"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["arvicco"]
|
12
|
-
s.date = %q{2010-02-
|
12
|
+
s.date = %q{2010-02-19}
|
13
13
|
s.description = %q{Rubyesque interfaces and wrappers for Windows API functions pre-defined using FFI }
|
14
14
|
s.email = %q{arvitallian@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: win
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- arvicco
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-02-
|
12
|
+
date: 2010-02-19 00:00:00 +03:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|