win 0.1.2 → 0.1.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|