win 0.1.22 → 0.1.26
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 +375 -55
- data/lib/win/library.rb +4 -3
- data/spec/win/dde_spec.rb +293 -151
- data/win.gemspec +2 -2
- metadata +2 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.26
|
data/lib/win/dde.rb
CHANGED
@@ -26,6 +26,20 @@ module Win
|
|
26
26
|
# DdeConnect function, regardless of the service name.
|
27
27
|
DNS_FILTEROFF = 8
|
28
28
|
|
29
|
+
# Transaction confirmations:
|
30
|
+
|
31
|
+
# Transaction confirmation
|
32
|
+
DDE_FACK = 0x8000
|
33
|
+
# Server is too busy to process transaction
|
34
|
+
DDE_FBUSY = 0x4000
|
35
|
+
DDE_FDEFERUPD = 0x4000
|
36
|
+
DDE_FACKREQ = 0x8000
|
37
|
+
DDE_FRELEASE = 0x2000
|
38
|
+
DDE_FREQUESTED = 0x1000
|
39
|
+
DDE_FAPPSTATUS = 0x00ff
|
40
|
+
# Transaction rejected
|
41
|
+
DDE_FNOTPROCESSED = 0
|
42
|
+
|
29
43
|
# Transaction types:
|
30
44
|
|
31
45
|
XTYPF_NOBLOCK = 0x0002
|
@@ -92,19 +106,6 @@ module Win
|
|
92
106
|
XTYP_SHIFT => 'XTYP_SHIFT'
|
93
107
|
}
|
94
108
|
|
95
|
-
# Transaction confirmations:
|
96
|
-
|
97
|
-
# Transaction confirmation
|
98
|
-
DDE_FACK = 0x8000
|
99
|
-
# Server is too busy to process transaction
|
100
|
-
DDE_FBUSY = 0x4000
|
101
|
-
DDE_FDEFERUPD = 0x4000
|
102
|
-
DDE_FACKREQ = 0x8000
|
103
|
-
DDE_FRELEASE = 0x2000
|
104
|
-
DDE_FREQUESTED = 0x1000
|
105
|
-
DDE_FAPPSTATUS = 0x00ff
|
106
|
-
# Transaction rejected
|
107
|
-
DDE_FNOTPROCESSED = 0
|
108
109
|
|
109
110
|
# DdeInitialize afCmd flaggs:
|
110
111
|
|
@@ -336,6 +337,254 @@ module Win
|
|
336
337
|
# DdeClientTransaction timeout value indicating async transaction
|
337
338
|
TIMEOUT_ASYNC = 0xFFFFFFFF
|
338
339
|
|
340
|
+
# The MONCBSTRUCT structure contains information about the current Dynamic Data Exchange (DDE)
|
341
|
+
# transaction. A DDE debugging application can use this structure when monitoring transactions that the
|
342
|
+
# system passes to the DDE callback functions of other applications.
|
343
|
+
#
|
344
|
+
# [*Typedef*] struct { UINT cb; DWORD dwTime; HANDLE hTask; DWORD dwRet; UINT wType; UINT wFmt; HCONV
|
345
|
+
# hConv; HSZ hsz1; HSZ hsz2; HDDEDATA hData; ULONG_PTR dwData1; ULONG_PTR dwData2;
|
346
|
+
# CONVCONTEXT cc; DWORD cbData; DWORD Data[8] } MONCBSTRUCT;
|
347
|
+
#
|
348
|
+
# cb:: Specifies the structure's size, in bytes.
|
349
|
+
# dwTime:: Specifies the Windows time at which the transaction occurred. Windows time is the number of
|
350
|
+
# milliseconds that have elapsed since the system was booted.
|
351
|
+
# hTask:: Handle to the task (app instance) containing the DDE callback function that received the transaction.
|
352
|
+
# dwRet:: Specifies the value returned by the DDE callback function that processed the transaction.
|
353
|
+
# wType:: Specifies the transaction type.
|
354
|
+
# wFmt:: Specifies the format of the data exchanged (if any) during the transaction.
|
355
|
+
# hConv:: Handle to the conversation in which the transaction took place.
|
356
|
+
# hsz1:: Handle to a string.
|
357
|
+
# hsz2:: Handle to a string.
|
358
|
+
# hData:: Handle to the data exchanged (if any) during the transaction.
|
359
|
+
# dwData1:: Specifies additional data.
|
360
|
+
# dwData2:: Specifies additional data.
|
361
|
+
# cc:: Specifies a CONVCONTEXT structure containing language information used to share data in different languages.
|
362
|
+
# cbData:: Specifies the amount, in bytes, of data being passed with the transaction. This value can be
|
363
|
+
# more than 32 bytes.
|
364
|
+
# Data:: Contains the first 32 bytes of data being passed with the transaction (8 * sizeof(DWORD)).
|
365
|
+
# ---
|
366
|
+
# *Information*:
|
367
|
+
# Header Declared in Ddeml.h, include Windows.h
|
368
|
+
|
369
|
+
class MonCbStruct < FFI::Struct # :nodoc:
|
370
|
+
layout :cb, :uint,
|
371
|
+
:dw_time, :uint32,
|
372
|
+
:h_task, :ulong,
|
373
|
+
:dw_ret, :uint32,
|
374
|
+
:w_type, :uint,
|
375
|
+
:w_fmt, :uint,
|
376
|
+
:h_conv, :ulong,
|
377
|
+
:hsz1, :ulong,
|
378
|
+
:hsz2, :ulong,
|
379
|
+
:h_data, :pointer,
|
380
|
+
:dw_data1, :pointer,
|
381
|
+
:dw_data2, :pointer,
|
382
|
+
:cc, :pointer,
|
383
|
+
:cb_data, :uint32,
|
384
|
+
:data, [:uint32, 8]
|
385
|
+
end
|
386
|
+
|
387
|
+
# The MONCONVSTRUCT structure contains information about a Dynamic Data Exchange (DDE) conversation. A
|
388
|
+
# DDE monitoring application can use this structure to obtain information about a conversation that has
|
389
|
+
# been established or has terminated.
|
390
|
+
#
|
391
|
+
# [*Typedef*] struct { UINT cb; BOOL fConnect; DWORD dwTime; HANDLE hTask; HSZ hszSvc; HSZ hszTopic;
|
392
|
+
# HCONV hConvClient; HCONV hConvServer } MONCONVSTRUCT;
|
393
|
+
#
|
394
|
+
# cb:: Specifies the structure's size, in bytes.
|
395
|
+
# fConnect:: Indicates whether the conversation is currently established. A value of TRUE indicates the
|
396
|
+
# conversation is established; FALSE indicates it is not.
|
397
|
+
# dwTime:: Specifies the Windows time at which the conversation was established or terminated. Windows
|
398
|
+
# time is the number of milliseconds that have elapsed since the system was booted.
|
399
|
+
# hTask:: Handle to a task (application instance) that is a partner in the conversation.
|
400
|
+
# hszSvc:: Handle to the service name on which the conversation is established.
|
401
|
+
# hszTopic:: Handle to the topic name on which the conversation is established.
|
402
|
+
# hConvClient:: Handle to the client conversation.
|
403
|
+
# hConvServer:: Handle to the server conversation.
|
404
|
+
# ---
|
405
|
+
# *Remarks*:
|
406
|
+
#
|
407
|
+
# Because string handles are local to the process, the hszSvc and hszTopic members are global atoms.
|
408
|
+
# Similarly, conversation handles are local to the instance; therefore, the hConvClient and hConvServer
|
409
|
+
# members are window handles.
|
410
|
+
# The hConvClient and hConvServer members of the MONCONVSTRUCT structure do not hold the same value as
|
411
|
+
# would be seen by the applications engaged in the conversation. Instead, they hold a globally unique
|
412
|
+
# pair of values that identify the conversation.
|
413
|
+
# ---
|
414
|
+
# Structure Information:
|
415
|
+
# Header Declared in Ddeml.h, include Windows.h
|
416
|
+
#
|
417
|
+
class MonConvStruct < FFI::Struct # :nodoc:
|
418
|
+
layout :cb, :uint,
|
419
|
+
:f_connect, :uchar,
|
420
|
+
:dw_time, :uint32,
|
421
|
+
:h_task, :ulong,
|
422
|
+
:hsz_svc, :ulong,
|
423
|
+
:hsz_topic, :ulong,
|
424
|
+
:h_conv_client, :ulong,
|
425
|
+
:h_conv_server, :ulong
|
426
|
+
end
|
427
|
+
|
428
|
+
# The MONERRSTRUCT structure contains information about the current Dynamic Data Exchange (DDE) error. A
|
429
|
+
# DDE monitoring application can use this structure to monitor errors returned by DDE Management Library
|
430
|
+
# functions.
|
431
|
+
#
|
432
|
+
# [*Typedef*] struct { UINT cb; UINT wLastError; DWORD dwTime; HANDLE hTask } MONERRSTRUCT;
|
433
|
+
#
|
434
|
+
# cb:: Specifies the structure's size, in bytes.
|
435
|
+
# wLastError:: Specifies the current error.
|
436
|
+
# dwTime:: Specifies the Windows time at which the error occurred. Windows time is the number of
|
437
|
+
# milliseconds that have elapsed since the system was booted.
|
438
|
+
# hTask:: Handle to the task (application instance) that called the DDE function that caused the error.
|
439
|
+
# ---
|
440
|
+
# Structure Information:
|
441
|
+
# Header Declared in Ddeml.h, include Windows.h
|
442
|
+
#
|
443
|
+
class MonErrStruct < FFI::Struct # :nodoc:
|
444
|
+
layout :cb, :uint,
|
445
|
+
:w_last_error, :uint,
|
446
|
+
:dw_time, :uint32,
|
447
|
+
:h_task, :ulong
|
448
|
+
end
|
449
|
+
|
450
|
+
MH_CREATE = 1
|
451
|
+
MH_KEEP = 2
|
452
|
+
MH_DELETE = 3
|
453
|
+
MH_CLEANUP = 4
|
454
|
+
|
455
|
+
# The MONHSZSTRUCT structure contains information about a Dynamic Data Exchange (DDE) string handle. A
|
456
|
+
# DDE monitoring application can use this structure when monitoring the activity of the string manager
|
457
|
+
# component of the DDE Management Library.
|
458
|
+
#
|
459
|
+
# [*Typedef*] struct { UINT cb; BOOL fsAction; DWORD dwTime; HSZ hsz; HANDLE hTask; TCHAR str[1] } MONHSZSTRUCT;
|
460
|
+
#
|
461
|
+
# cb:: Specifies the structure's size, in bytes.
|
462
|
+
# fsAction:: Specifies the action being performed on the string identified by the hsz member.
|
463
|
+
# MH_CLEANUP:: An application is freeing its DDE resources, causing the system to delete string handles
|
464
|
+
# the application had created. (The application called the DdeUninitialize function.)
|
465
|
+
# MH_CREATE:: An application is creating a string handle. (The app called the DdeCreateStringHandle)
|
466
|
+
# MH_DELETE:: An application is deleting a string handle. (The app called the DdeFreeStringHandle)
|
467
|
+
# MH_KEEP:: An application is increasing the usage count of a string handle. (The application called the
|
468
|
+
# DdeKeepStringHandle function.)
|
469
|
+
# dwTime:: Specifies the Windows time at which the action specified by the fsAction member takes place.
|
470
|
+
# Windows time is the number of milliseconds that have elapsed since the system was booted.
|
471
|
+
# hsz:: Handle to the string. Because string handles are local to the process, this member is a global atom.
|
472
|
+
# hTask:: Handle to the task (application instance) performing the action on the string handle.
|
473
|
+
# str:: Pointer to the string identified by the hsz member.
|
474
|
+
# ---
|
475
|
+
# Structure Information
|
476
|
+
# Header Declared in Ddeml.h, include Windows.h
|
477
|
+
#
|
478
|
+
class MonHszStruct < FFI::Struct # :nodoc:
|
479
|
+
layout :cb, :uint,
|
480
|
+
:fs_action, :uchar,
|
481
|
+
:dw_time, :uint32,
|
482
|
+
:hsz, :ulong,
|
483
|
+
:h_task, :ulong,
|
484
|
+
:str, :pointer
|
485
|
+
end
|
486
|
+
|
487
|
+
# The MONLINKSTRUCT structure contains information about a Dynamic Data Exchange (DDE) advise loop. A
|
488
|
+
# DDE monitoring application can use this structure to obtain information about an advise loop that has
|
489
|
+
# started or ended.
|
490
|
+
#
|
491
|
+
# [*Typedef*] struct { UINT cb; DWORD dwTime; HANDLE hTask; BOOL fEstablished; BOOL fNoData; HSZ hszSvc;
|
492
|
+
# HSZ hszTopic; HSZ hszItem; UINT wFmt; BOOL fServer; HCONV hConvServer; HCONV hConvClient }
|
493
|
+
# MONLINKSTRUCT;
|
494
|
+
#
|
495
|
+
# cb:: Specifies the structure's size, in bytes.
|
496
|
+
# dwTime:: Specifies the Windows time at which the advise loop was started or ended. Windows time is the
|
497
|
+
# number of milliseconds that have elapsed since the system was booted.
|
498
|
+
# hTask:: Handle to a task (application instance) that is a partner in the advise loop.
|
499
|
+
# fEstablished:: Indicates whether an advise loop was successfully established. A value of TRUE
|
500
|
+
# indicates an advise loop was established; FALSE indicates it was not.
|
501
|
+
# fNoData:: Indicates whether the XTYPF_NODATA flag is set for the advise loop. A value of TRUE
|
502
|
+
# indicates the flag is set; FALSE indicates it is not.
|
503
|
+
# hszSvc:: Handle to the service name of the server in the advise loop.
|
504
|
+
# hszTopic:: Handle to the topic name on which the advise loop is established.
|
505
|
+
# hszItem:: Handle to the item name that is the subject of the advise loop.
|
506
|
+
# wFmt:: Specifies the format of the data exchanged (if any) during the advise loop.
|
507
|
+
# fServer:: Indicates whether the link notification came from the server. A value of TRUE indicates the
|
508
|
+
# notification came from the server; FALSE indicates otherwise.
|
509
|
+
# hConvServer:: Handle to the server conversation.
|
510
|
+
# hConvClient:: Handle to the client conversation.
|
511
|
+
# ---
|
512
|
+
# *Remarks*:
|
513
|
+
# Because string handles are local to the process, the hszSvc, hszTopic, and hszItem members are global atoms.
|
514
|
+
# The hConvClient and hConvServer members of the MONLINKSTRUCT structure do not hold the same value as
|
515
|
+
# would be seen by the applications engaged in the conversation. Instead, they hold a globally unique
|
516
|
+
# pair of values that identify the conversation.
|
517
|
+
# ---
|
518
|
+
# Structure Information
|
519
|
+
# Header Declared in Ddeml.h, include Windows.h
|
520
|
+
#
|
521
|
+
class MonLinkStruct < FFI::Struct # :nodoc:
|
522
|
+
layout :cb, :uint,
|
523
|
+
:dw_time, :uint32,
|
524
|
+
:h_task, :ulong,
|
525
|
+
:f_established, :uchar,
|
526
|
+
:f_no_data, :uchar,
|
527
|
+
:hsz_svc, :ulong,
|
528
|
+
:hsz_topic, :ulong,
|
529
|
+
:hsz_item, :ulong,
|
530
|
+
:w_fmt, :uint,
|
531
|
+
:f_server, :uchar,
|
532
|
+
:h_conv_server, :ulong,
|
533
|
+
:h_conv_client, :ulong
|
534
|
+
end
|
535
|
+
|
536
|
+
# The MONMSGSTRUCT structure contains information about a Dynamic Data Exchange (DDE) message. A DDE
|
537
|
+
# monitoring application can use this structure to obtain information about a DDE message that was sent
|
538
|
+
# or posted.
|
539
|
+
#
|
540
|
+
# [*Typedef*] struct { UINT cb; HWND hwndTo; DWORD dwTime; HANDLE hTask; UINT wMsg; WPARAM wParam;
|
541
|
+
# LPARAM lParam; DDEML_MSG_HOOK_DATA dmhd } MONMSGSTRUCT;
|
542
|
+
#
|
543
|
+
# cb:: Specifies the structure's size, in bytes.
|
544
|
+
# hwndTo:: Handle to the window that receives the DDE message.
|
545
|
+
# dwTime:: Specifies the Windows time at which the message was sent or posted. Windows time is the
|
546
|
+
# number of milliseconds that have elapsed since the system was booted.
|
547
|
+
# hTask:: Handle to the task (application instance) containing the window that receives the DDE message.
|
548
|
+
# wMsg:: Specifies the identifier of the DDE message.
|
549
|
+
# wParam:: Specifies the wParam parameter of the DDE message.
|
550
|
+
# lParam:: Specifies the lParam parameter of the DDE message.
|
551
|
+
# dmhd:: Specifies a DDEML_MSG_HOOK_DATA structure that contains additional information about the DDE message.
|
552
|
+
# ---
|
553
|
+
# Structure Information
|
554
|
+
# Header Declared in Ddeml.h, include Windows.h
|
555
|
+
#
|
556
|
+
class MonMsgStruct < FFI::Struct # :nodoc:
|
557
|
+
layout :cb, :uint,
|
558
|
+
:hwnd_to, :ulong,
|
559
|
+
:dw_time, :uint32,
|
560
|
+
:h_task, :ulong,
|
561
|
+
:w_msg, :uint,
|
562
|
+
:w_param, :uint,
|
563
|
+
:l_param, :long,
|
564
|
+
:dmhd, :pointer
|
565
|
+
end
|
566
|
+
|
567
|
+
# The DDEML_MSG_HOOK_DATA structure contains information about a Dynamic Data Exchange (DDE) message,
|
568
|
+
# and provides read access to the data referenced by the message. This structure is intended to be used
|
569
|
+
# by a Dynamic Data Exchange Management Library (DDEML) monitoring application.
|
570
|
+
#
|
571
|
+
# [*Typedef*] struct { UINT_PTR uiLo; UINT_PTR uiHi; DWORD cbData; DWORD Data } DDEML_MSG_HOOK_DATA;
|
572
|
+
#
|
573
|
+
# uiLo:: Specifies the unpacked low-order word of the lParam parameter associated with the DDE message.
|
574
|
+
# uiHi:: Specifies the unpacked high-order word of the lParam parameter associated with the DDE message.
|
575
|
+
# cbData:: Specifies the amount, in bytes, of data being passed with the message. This value can be > 32.
|
576
|
+
# Data:: Contains the first 32 bytes of data being passed with the message (8 * sizeof(DWORD)).
|
577
|
+
# ---
|
578
|
+
# Structure Information
|
579
|
+
# Header Declared in Ddeml.h, include Windows.h
|
580
|
+
#
|
581
|
+
class DdemlMsgHookData < FFI::Struct # :nodoc:
|
582
|
+
layout :ui_lo, :uint,
|
583
|
+
:ui_hi, :uint,
|
584
|
+
:cb_data, :uint32,
|
585
|
+
:data, :uint32
|
586
|
+
end
|
587
|
+
|
339
588
|
##
|
340
589
|
# The RegisterClipboardFormat function registers a new clipboard format.
|
341
590
|
# This format can then be used as a valid clipboard format.
|
@@ -675,47 +924,6 @@ module Win
|
|
675
924
|
&->(api, id, string_handle, cmd){ api.call(id, string_handle, 0, cmd) != 0 }
|
676
925
|
# weird lambda literal instead of block is needed because RDoc goes crazy if block is attached to meta-definition
|
677
926
|
|
678
|
-
##
|
679
|
-
# The DdeGetData function copies data from the specified Dynamic Data Exchange (DDE) object to the specified
|
680
|
-
# local buffer.
|
681
|
-
#
|
682
|
-
# [*Syntax*] DWORD DdeGetData( HDDEDATA hData, LPBYTE pDst, DWORD cbMax, DWORD cbOff );
|
683
|
-
#
|
684
|
-
# hData:: [in] Handle to the DDE object that contains the data to copy.
|
685
|
-
# pDst:: [out] Pointer to the buffer that receives the data. If this parameter is NULL, the DdeGetData
|
686
|
-
# function returns the amount of data, in bytes, that would be copied to the buffer.
|
687
|
-
# cbMax:: [in] Specifies the maximum amount of data, in bytes, to copy to the buffer pointed to by the pDst
|
688
|
-
# parameter. Typically, this parameter specifies the length of the buffer pointed to by pDst.
|
689
|
-
# cbOff:: [in] Specifies an offset within the DDE object. Data is copied from the object beginning at this offset.
|
690
|
-
#
|
691
|
-
# *Returns*:: If the pDst parameter points to a buffer, return value is the size, in bytes, of the memory object
|
692
|
-
# associated with the data handle or the size specified in the cbMax parameter, whichever is lower.
|
693
|
-
# If the pDst parameter is NULL, the return value is the size, in bytes, of the memory object
|
694
|
-
# associated with the data handle.
|
695
|
-
# The DdeGetLastError function can be used to get the error code, which can be one of the following:
|
696
|
-
# - DMLERR_DLL_NOT_INITIALIZED
|
697
|
-
# - DMLERR_INVALIDPARAMETER
|
698
|
-
# - DMLERR_NO_ERROR
|
699
|
-
# ---
|
700
|
-
# <b> Enhanced (snake_case) API accepts only data handle, and optionally max and offset (no need to pre-allocate
|
701
|
-
# buffer). It returns buffer with copied DDE data (FFI::MemoryPointer) or nil for failure. DDE data length is
|
702
|
-
# determined internally, no need to call function twice (first time with nil buffer just to determine length).</b>
|
703
|
-
# ---
|
704
|
-
#
|
705
|
-
# :call-seq:
|
706
|
-
# buffer, success = dde_get_data( data_handle, [max = infinite, offset = 0] )
|
707
|
-
#
|
708
|
-
function :DdeGetData, [:ulong, :pointer, :uint32, :uint32], :uint,
|
709
|
-
&->(api, data_handle, max=1073741823, offset=0){ # max is maximum DWORD Fixnum
|
710
|
-
length = api.call(data_handle, nil, 0, 0) # determining data set length
|
711
|
-
if length != 0
|
712
|
-
copy_length = length < max ? length : max
|
713
|
-
buffer = FFI::MemoryPointer.new(:char, offset + copy_length)
|
714
|
-
length = api.call(data_handle, buffer, copy_length, offset)
|
715
|
-
end
|
716
|
-
length != 0 ? buffer: nil }
|
717
|
-
# weird lambda literal instead of block is needed because RDoc goes crazy if block is attached to meta-definition
|
718
|
-
|
719
927
|
##
|
720
928
|
# DdeConnect function establishes a conversation with a server application that supports the specified service
|
721
929
|
# name and topic name pair. If more than one such server exists, the system selects only one.
|
@@ -908,7 +1116,119 @@ module Win
|
|
908
1116
|
# :call-seq:
|
909
1117
|
# data_handle = dde_client_transaction(data_pointer, size, conv, item, format, type, timeout, result)
|
910
1118
|
#
|
911
|
-
function :DdeClientTransaction, [:pointer, :uint32, :ulong, :ulong, :uint, :uint, :uint32, :pointer],
|
1119
|
+
function :DdeClientTransaction, [:pointer, :uint32, :ulong, :ulong, :uint, :uint, :uint32, :pointer],
|
1120
|
+
:HDDEDATA, boolean: true
|
1121
|
+
|
1122
|
+
##
|
1123
|
+
# The DdeGetData function copies data from the specified Dynamic Data Exchange (DDE) object to the specified
|
1124
|
+
# local buffer.
|
1125
|
+
#
|
1126
|
+
# [*Syntax*] DWORD DdeGetData( HDDEDATA hData, LPBYTE pDst, DWORD cbMax, DWORD cbOff );
|
1127
|
+
#
|
1128
|
+
# hData:: [in] Handle to the DDE object that contains the data to copy.
|
1129
|
+
# pDst:: [out] Pointer to the buffer that receives the data. If this parameter is NULL, the DdeGetData
|
1130
|
+
# function returns the amount of data, in bytes, that would be copied to the buffer.
|
1131
|
+
# cbMax:: [in] Specifies the maximum amount of data, in bytes, to copy to the buffer pointed to by the pDst
|
1132
|
+
# parameter. Typically, this parameter specifies the length of the buffer pointed to by pDst.
|
1133
|
+
# cbOff:: [in] Specifies an offset within the DDE object. Data is copied from the object beginning at this offset.
|
1134
|
+
#
|
1135
|
+
# *Returns*:: If the pDst parameter points to a buffer, return value is the size, in bytes, of the memory object
|
1136
|
+
# associated with the data handle or the size specified in the cbMax parameter, whichever is lower.
|
1137
|
+
# If the pDst parameter is NULL, the return value is the size, in bytes, of the memory object
|
1138
|
+
# associated with the data handle.
|
1139
|
+
# The DdeGetLastError function can be used to get the error code, which can be one of the following:
|
1140
|
+
# - DMLERR_DLL_NOT_INITIALIZED
|
1141
|
+
# - DMLERR_INVALIDPARAMETER
|
1142
|
+
# - DMLERR_NO_ERROR
|
1143
|
+
# ---
|
1144
|
+
# <b> Enhanced (snake_case) API accepts data handle, and optionally max and offset (no need to pre-allocate
|
1145
|
+
# buffer). It returns pointer to copied DDE data (FFI::MemoryPointer) and size of copied data in bytes.
|
1146
|
+
# In case of failure, it returns [nil, 0]. This API is the same as for enhanced dde_access_data.
|
1147
|
+
# No need to call function twice (first time with nil buffer just to determine length).</b>
|
1148
|
+
# ---
|
1149
|
+
#
|
1150
|
+
# :call-seq:
|
1151
|
+
# buffer, size = dde_get_data( data_handle, [max = infinite, offset = 0] )
|
1152
|
+
#
|
1153
|
+
function :DdeGetData, [:ulong, :pointer, :uint32, :uint32], :uint,
|
1154
|
+
&->(api, data_handle, max=1073741823, offset=0){ # max is maximum DWORD Fixnum
|
1155
|
+
size = api.call(data_handle, nil, 0, 0) # determining data set length
|
1156
|
+
if size == 0
|
1157
|
+
[nil, 0]
|
1158
|
+
else
|
1159
|
+
copy_size = size < max ? size : max
|
1160
|
+
buffer = FFI::MemoryPointer.new(:char, offset + copy_size)
|
1161
|
+
size = api.call(data_handle, buffer, copy_size, offset)
|
1162
|
+
[buffer, size]
|
1163
|
+
end }
|
1164
|
+
# weird lambda literal instead of block is needed because RDoc goes crazy if block is attached to meta-definition
|
1165
|
+
|
1166
|
+
|
1167
|
+
##
|
1168
|
+
# The DdeAccessData function provides access to the data in the specified Dynamic Data Exchange (DDE)
|
1169
|
+
# object. An application must call the DdeUnaccessData function when it has finished accessing the data
|
1170
|
+
# in the object.
|
1171
|
+
#
|
1172
|
+
# [*Syntax*] LPBYTE DdeAccessData( HDDEDATA hData, LPDWORD pcbDataSize );
|
1173
|
+
#
|
1174
|
+
# hData:: [in] Handle to the DDE object to access.
|
1175
|
+
# pcbDataSize:: [out] Pointer to a variable that receives the size, in bytes, of the DDE object
|
1176
|
+
# identified by the hData parameter. If this parameter is NULL, no size information is
|
1177
|
+
# returned.
|
1178
|
+
#
|
1179
|
+
# *Returns*:: If the function succeeds, the return value is a pointer to the first byte of data in the
|
1180
|
+
# DDE object.
|
1181
|
+
# If the function fails, the return value is NULL.
|
1182
|
+
# The DdeGetLastError function can be used to get the error code, which can be one of the following
|
1183
|
+
# values:
|
1184
|
+
# DMLERR_DLL_NOT_INITIALIZED
|
1185
|
+
# DMLERR_INVALIDPARAMETER
|
1186
|
+
# DMLERR_NO_ERROR
|
1187
|
+
# ---
|
1188
|
+
# *Remarks*:
|
1189
|
+
# If the hData parameter has not been passed to a Dynamic Data Exchange Management Library (DDEML)
|
1190
|
+
# function, an application can use the pointer returned by DdeAccessData for read-write access to the
|
1191
|
+
# DDE object. If hData has already been passed to a DDEML function, the pointer should be used only for
|
1192
|
+
# read access to the memory object.
|
1193
|
+
#
|
1194
|
+
# ---
|
1195
|
+
# <b>Enhanced (snake_case) API accepts DDE data handle and returns FFI::MemoryPointer to raw data and
|
1196
|
+
# size of data set in bytes (same API as enhanced dde_get_data). Returns [nil, 0] in case of failure. </b>
|
1197
|
+
#
|
1198
|
+
# :call-seq:
|
1199
|
+
# data_pointer, size = dde_access_data( data_handle )
|
1200
|
+
#
|
1201
|
+
function :DdeAccessData, [:HDDEDATA, :pointer], :pointer,
|
1202
|
+
&->(api, data_handle){
|
1203
|
+
size_buffer = FFI::MemoryPointer.new(:int16)
|
1204
|
+
buffer = api.call(data_handle, size_buffer)
|
1205
|
+
size = size_buffer.get_int16(0)
|
1206
|
+
size == 0 ? [nil, 0] : [buffer, size] }
|
1207
|
+
# weird lambda literal instead of block is needed because RDoc goes crazy if block is attached to meta-definition
|
1208
|
+
|
1209
|
+
##
|
1210
|
+
# The DdeUnaccessData function unaccesses a Dynamic Data Exchange (DDE) object. An application must call
|
1211
|
+
# this function after it has finished accessing the object.
|
1212
|
+
#
|
1213
|
+
# [*Syntax*] BOOL DdeUnaccessData( HDDEDATA hData );
|
1214
|
+
#
|
1215
|
+
# hData:: [in] Handle to the DDE object.
|
1216
|
+
#
|
1217
|
+
# *Returns*:: If the function succeeds, the return value is nonzero.
|
1218
|
+
# If the function fails, the return value is zero.
|
1219
|
+
# The DdeGetLastError function can be used to get the error code, which can be one of the following
|
1220
|
+
# values:
|
1221
|
+
# DMLERR_DLL_NOT_INITIALIZED
|
1222
|
+
# DMLERR_INVALIDPARAMETER
|
1223
|
+
# DMLERR_NO_ERROR
|
1224
|
+
#
|
1225
|
+
# ---
|
1226
|
+
# <b>Enhanced (snake_case) API returns true/false instead of nonzero/zero: </b>
|
1227
|
+
#
|
1228
|
+
# :call-seq:
|
1229
|
+
# success = dde_unaccess_data(data_handle)
|
1230
|
+
#
|
1231
|
+
function :DdeUnaccessData, [:HDDEDATA], :int8, boolean: true
|
912
1232
|
|
913
1233
|
end
|
914
1234
|
end
|
data/lib/win/library.rb
CHANGED
@@ -328,10 +328,11 @@ module Win
|
|
328
328
|
boolean = options[:boolean]
|
329
329
|
zeronil = options[:zeronil]
|
330
330
|
|
331
|
-
effective_name = effective_names.inject(nil) do |func,
|
331
|
+
effective_name = effective_names.inject(nil) do |func, effective_name|
|
332
332
|
func || begin
|
333
|
-
|
334
|
-
|
333
|
+
# tries to attach basic CamelCase method via FFI
|
334
|
+
attach_function(name, effective_name, params.dup, returns)
|
335
|
+
effective_name
|
335
336
|
rescue FFI::NotFoundError
|
336
337
|
nil
|
337
338
|
end
|
data/spec/win/dde_spec.rb
CHANGED
@@ -6,12 +6,14 @@ module WinDDETest
|
|
6
6
|
include Win::DDE
|
7
7
|
include Win::GUI::Message
|
8
8
|
|
9
|
+
POKE_STRING = "Poke_string\x00\x00"
|
10
|
+
|
9
11
|
def dde_cmd
|
10
12
|
APPCLASS_STANDARD
|
11
13
|
end
|
12
14
|
|
13
15
|
def dde_callback
|
14
|
-
->{}
|
16
|
+
->(*args){}
|
15
17
|
end
|
16
18
|
|
17
19
|
def zero_id
|
@@ -35,8 +37,40 @@ module WinDDETest
|
|
35
37
|
data, data1, data2]
|
36
38
|
end
|
37
39
|
|
40
|
+
def setup_server(&server_block)
|
41
|
+
@client_calls = []
|
42
|
+
@server_calls = []
|
43
|
+
@client_id, st = dde_initialize(APPCLASS_STANDARD) {|*args| @client_calls << extract_values(*args); DDE_FACK}
|
44
|
+
@server_id, st = dde_initialize(APPCLASS_STANDARD,
|
45
|
+
&server_block || proc {|*args| @server_calls << extract_values(*args); DDE_FACK} )
|
46
|
+
@service_handle = dde_create_string_handle(@server_id, 'service 2', CP_WINANSI)
|
47
|
+
@topic_handle = dde_create_string_handle(@server_id, 'topic 2', CP_WINANSI)
|
48
|
+
dde_name_service(@server_id, @service_handle, DNS_REGISTER)
|
49
|
+
end
|
50
|
+
|
51
|
+
def teardown_server
|
52
|
+
if @print
|
53
|
+
p @server_calls, @client_calls
|
54
|
+
p @server_conv
|
55
|
+
p ERRORS[dde_get_last_error(@server_id)]
|
56
|
+
p ERRORS[dde_get_last_error(@client_id)]
|
57
|
+
@print = nil
|
58
|
+
end
|
59
|
+
dde_name_service(@server_id, @service_handle, DNS_UNREGISTER) if @server_id && @service_handle
|
60
|
+
dde_free_string_handle(@server_id, @service_handle) if @server_id && @service_handle
|
61
|
+
dde_free_string_handle(@server_id, @topic_handle) if @server_id && @topic_handle
|
62
|
+
dde_uninitialize(@server_id) if @server_id
|
63
|
+
dde_uninitialize(@client_id) if @client_id
|
64
|
+
if @conv_handle
|
65
|
+
dde_disconnect(@conv_handle)
|
66
|
+
@conv_handle = nil
|
67
|
+
end
|
68
|
+
@data = nil
|
69
|
+
end
|
70
|
+
|
38
71
|
describe Win::DDE, ' contains a set of pre-defined Windows API functions' do
|
39
|
-
|
72
|
+
|
73
|
+
describe '#register_clipboard_format' do
|
40
74
|
spec{ use{ RegisterClipboardFormat(format_name = "XlTable") }}
|
41
75
|
spec{ use{ register_clipboard_format(format_name = "XlTable") }}
|
42
76
|
|
@@ -57,59 +91,58 @@ module WinDDETest
|
|
57
91
|
end
|
58
92
|
end
|
59
93
|
|
60
|
-
describe 'dde_initialize' do
|
61
|
-
after(:each) {dde_uninitialize(@
|
94
|
+
describe '#dde_initialize' do
|
95
|
+
after(:each) {dde_uninitialize(@id) if @id}
|
62
96
|
|
63
|
-
spec{ use{ status = DdeInitialize( zero_id, dde_callback, dde_cmd, unused =
|
64
|
-
spec{ use{ id, status = dde_initialize(
|
65
|
-
end }}
|
97
|
+
spec{ use{ status = DdeInitialize( id = zero_id, dde_callback, dde_cmd, unused=0); @id = id.read_long}}
|
98
|
+
spec{ use{ @id, status = dde_initialize(@id=0, dde_cmd, &dde_callback) }}
|
66
99
|
|
67
100
|
it 'with zero instance_id, returns integer id and DMLERR_NO_ERROR if initialization successful' do
|
68
|
-
@
|
69
|
-
@
|
70
|
-
@
|
101
|
+
@id, status = dde_initialize(0, APPCLASS_STANDARD) {|*args| }
|
102
|
+
@id.should be_an Integer
|
103
|
+
@id.should_not == 0
|
71
104
|
status.should == DMLERR_NO_ERROR
|
72
105
|
end
|
73
106
|
|
74
107
|
it 'with nil instance_id, returns integer id and DMLERR_NO_ERROR if initialization successful' do
|
75
|
-
@
|
76
|
-
@
|
77
|
-
@
|
108
|
+
@id, status = dde_initialize(nil, APPCLASS_STANDARD) {|*args| }
|
109
|
+
@id.should be_an Integer
|
110
|
+
@id.should_not == 0
|
78
111
|
status.should == DMLERR_NO_ERROR
|
79
112
|
end
|
80
113
|
|
81
114
|
it 'with omitted instance_id, returns integer id and DMLERR_NO_ERROR if initialization successful' do
|
82
|
-
@
|
83
|
-
@
|
84
|
-
@
|
115
|
+
@id, status = dde_initialize(APPCLASS_STANDARD) {|*args| }
|
116
|
+
@id.should be_an Integer
|
117
|
+
@id.should_not == 0
|
85
118
|
status.should == DMLERR_NO_ERROR
|
86
119
|
end
|
87
120
|
|
88
121
|
it 'returns error status if initialization unsuccessful' do
|
89
|
-
@
|
122
|
+
@id, status = dde_initialize(12345, APPCLASS_STANDARD) {|*args| }
|
90
123
|
status.should == DMLERR_INVALIDPARAMETER
|
91
|
-
@
|
124
|
+
@id.should == nil
|
92
125
|
end
|
93
126
|
|
94
127
|
it 'is able to reinitialize with correct id' do
|
95
|
-
@
|
96
|
-
new_id, status = dde_initialize(@
|
128
|
+
@id, status = dde_initialize(APPCLASS_STANDARD) {|*args| }
|
129
|
+
new_id, status = dde_initialize(@id, APPCLASS_STANDARD) {|*args| }
|
97
130
|
status.should == DMLERR_NO_ERROR
|
98
|
-
new_id.should == @
|
131
|
+
new_id.should == @id
|
99
132
|
end
|
100
|
-
end
|
133
|
+
end # describe 'dde_initialize'
|
101
134
|
|
102
135
|
context 'after initialization:' do
|
103
|
-
before(:each) {@
|
104
|
-
after(:each) {dde_uninitialize(@
|
136
|
+
before(:each) {@id, status = dde_initialize(APPCLASS_STANDARD) {|*args| }}
|
137
|
+
after(:each) {dde_uninitialize(@id) if @id}
|
105
138
|
|
106
139
|
describe '#dde_uninitialize' do
|
107
140
|
|
108
|
-
spec{ use{ status = DdeUninitialize( @
|
109
|
-
spec{ use{ id, status = dde_uninitialize( @
|
141
|
+
spec{ use{ status = DdeUninitialize( @id ) }}
|
142
|
+
spec{ use{ id, status = dde_uninitialize( @id) }}
|
110
143
|
|
111
144
|
it 'returns true if uninitialization successful' do
|
112
|
-
res = dde_uninitialize(@
|
145
|
+
res = dde_uninitialize(@id)
|
113
146
|
res.should == true
|
114
147
|
end
|
115
148
|
|
@@ -120,129 +153,123 @@ module WinDDETest
|
|
120
153
|
end # describe '#dde_uninitialize'
|
121
154
|
|
122
155
|
describe '#dde_create_string_handle' do
|
123
|
-
after(:each) {dde_free_string_handle(@
|
156
|
+
after(:each) {dde_free_string_handle(@id, @string_handle) if @string_handle}
|
124
157
|
|
125
|
-
spec{ use{ @string_handle = DdeCreateStringHandle(
|
126
|
-
spec{ use{ @string_handle = dde_create_string_handle(
|
158
|
+
spec{ use{ @string_handle = DdeCreateStringHandle(id=0, string_pointer, code_page_id=CP_WINANSI) }}
|
159
|
+
spec{ use{ @string_handle = dde_create_string_handle(id=0, string='Any String', code_page_id=CP_WINANSI)}}
|
127
160
|
|
128
161
|
it 'returns nonzero Integer handle to a string (passable to other DDEML functions)' do
|
129
|
-
@string_handle = dde_create_string_handle(@
|
162
|
+
@string_handle = dde_create_string_handle(@id, 'My String', CP_WINANSI)
|
130
163
|
@string_handle.should be_an Integer
|
131
164
|
@string_handle.should_not == 0
|
132
165
|
end
|
133
166
|
|
134
167
|
it 'creates handle even if code_page is omitted' do
|
135
|
-
@string_handle = dde_create_string_handle(@
|
168
|
+
@string_handle = dde_create_string_handle(@id, 'My String')
|
136
169
|
@string_handle.should be_an Integer
|
137
170
|
@string_handle.should_not == 0
|
138
171
|
end
|
139
172
|
|
140
173
|
it 'creating two handles for the SAME string (inside one instance) USUALLY returns same handle' do
|
141
|
-
@string_handle = dde_create_string_handle(@
|
174
|
+
@string_handle = dde_create_string_handle(@id, 'My String')
|
142
175
|
10.times do
|
143
|
-
string_handle1 = dde_create_string_handle(@
|
176
|
+
string_handle1 = dde_create_string_handle(@id, 'My String')
|
144
177
|
string_handle1.should == @string_handle
|
145
|
-
dde_free_string_handle(@
|
178
|
+
dde_free_string_handle(@id, string_handle1)
|
146
179
|
end
|
147
180
|
end
|
148
181
|
|
149
182
|
it 'created different handles for two different strings ' do
|
150
|
-
@string_handle = dde_create_string_handle(@
|
151
|
-
string_handle1 = dde_create_string_handle(@
|
183
|
+
@string_handle = dde_create_string_handle(@id, 'My String')
|
184
|
+
string_handle1 = dde_create_string_handle(@id, 'My String1')
|
152
185
|
string_handle1.should_not == @string_handle
|
153
|
-
dde_free_string_handle(@
|
186
|
+
dde_free_string_handle(@id, string_handle1)
|
154
187
|
end
|
155
188
|
|
156
189
|
it 'returns nil if unable to register handle to a string' do
|
157
|
-
@string_handle = dde_create_string_handle(@
|
190
|
+
@string_handle = dde_create_string_handle(@id, "", CP_WINANSI)
|
158
191
|
@string_handle.should == nil
|
159
192
|
end
|
160
193
|
end # describe '#dde_create_string_handle'
|
161
194
|
|
162
195
|
context "with dde string handle to 'My String 2'" do
|
163
|
-
before(:each) {@string_handle = dde_create_string_handle(@
|
164
|
-
after(:each) {dde_free_string_handle(@
|
196
|
+
before(:each) {@string_handle = dde_create_string_handle(@id, 'My String 2', CP_WINANSI)}
|
197
|
+
after(:each) {dde_free_string_handle(@id, @string_handle)}
|
165
198
|
|
166
199
|
describe '#dde_query_string' do
|
167
200
|
|
168
|
-
spec{ use{ string = DdeQueryString(@
|
169
|
-
spec{ use{ string = dde_query_string(@
|
201
|
+
spec{ use{ string = DdeQueryString(@id, @string_handle, buffer, buffer.size, code_page=CP_WINANSI)}}
|
202
|
+
spec{ use{ string = dde_query_string(@id, @string_handle, code_page=CP_WINANSI )}}
|
203
|
+
|
204
|
+
it 'retrieves string that given string handle refers to' do
|
205
|
+
num_chars = DdeQueryString(@id, @string_handle, buf = buffer, buf.size, CP_WINANSI)
|
206
|
+
num_chars.should == 11
|
207
|
+
buf.read_string.should == 'My String 2'
|
208
|
+
end
|
170
209
|
|
171
210
|
it 'retrieves string that given string handle refers to' do
|
172
|
-
string = dde_query_string(@
|
211
|
+
string = dde_query_string(@id, @string_handle, CP_WINANSI)
|
173
212
|
string.should == 'My String 2'
|
174
213
|
end
|
175
214
|
|
176
215
|
it 'retrieves string even if code_page is omitted' do
|
177
|
-
string = dde_query_string(@
|
216
|
+
string = dde_query_string(@id, @string_handle)
|
178
217
|
string.should == 'My String 2'
|
179
218
|
end
|
180
219
|
|
181
220
|
it 'returns nil attempting to retrieve invalid handle' do
|
182
|
-
string = dde_query_string(@
|
221
|
+
string = dde_query_string(@id, 12345)
|
183
222
|
string.should == nil
|
184
223
|
end
|
185
224
|
end # describe '#dde_query_string'
|
186
225
|
|
187
226
|
describe '#dde_free_string_handle' do
|
188
227
|
|
189
|
-
spec{ use{ success = DdeFreeStringHandle( @
|
190
|
-
spec{ use{ success = dde_free_string_handle( @
|
228
|
+
spec{ use{ success = DdeFreeStringHandle( @id, @string_handle)}}
|
229
|
+
spec{ use{ success = dde_free_string_handle( @id, @string_handle )}}
|
191
230
|
|
192
231
|
it 'returns true when freeing string handle registered with DDEML' do
|
193
|
-
res = dde_free_string_handle(@
|
232
|
+
res = dde_free_string_handle(@id, @string_handle)
|
194
233
|
res.should == true
|
195
234
|
end
|
196
235
|
|
197
236
|
it 'returns false attempting to free unregistered handle' do
|
198
|
-
res = dde_free_string_handle(@
|
237
|
+
res = dde_free_string_handle(@id, 12345)
|
199
238
|
res.should == false
|
200
239
|
end
|
201
240
|
|
202
|
-
it 'keeps string accessible
|
203
|
-
|
241
|
+
it 'keeps string accessible while references to it still exist' do
|
242
|
+
# creates second handle to 'My String 2'
|
243
|
+
string_handle_1 = dde_create_string_handle(@id, 'My String 2', CP_WINANSI)
|
204
244
|
|
205
|
-
dde_free_string_handle(@
|
245
|
+
dde_free_string_handle(@id, @string_handle)
|
246
|
+
dde_query_string(@id, @string_handle).should == 'My String 2'
|
206
247
|
|
207
|
-
|
208
|
-
|
248
|
+
dde_free_string_handle(@id, string_handle_1)
|
249
|
+
dde_query_string(@id, @string_handle).should == nil
|
209
250
|
end
|
210
251
|
|
211
252
|
it 'makes string inaccessible once its last handle is freed' do
|
212
|
-
dde_free_string_handle(@
|
213
|
-
|
214
|
-
dde_query_string(@instance_id, @string_handle).should == nil
|
253
|
+
dde_free_string_handle(@id, @string_handle)
|
254
|
+
dde_query_string(@id, @string_handle).should == nil
|
215
255
|
end
|
216
256
|
end # describe '#dde_free_string_handle'
|
217
257
|
|
218
|
-
describe '#dde_name_service' do
|
219
|
-
spec{ use{ success = dde_name_service(@instance_id, @string_handle, cmd=DNS_UNREGISTER ) }}
|
220
|
-
spec{ use{ success = DdeNameService(@instance_id, @string_handle, reserved=0, cmd=DNS_UNREGISTER) }}
|
221
|
-
|
222
|
-
it 'registers or unregisters the service names that DDE server supports' do
|
223
|
-
success = dde_name_service( @instance_id, @string_handle, DNS_REGISTER )
|
224
|
-
success.should == true
|
225
|
-
|
226
|
-
success = dde_name_service( @instance_id, @string_handle, DNS_UNREGISTER )
|
227
|
-
success.should == true
|
228
|
-
end
|
229
|
-
end # describe '#dde_name_service'
|
230
|
-
|
231
258
|
describe '#dde_get_last_error' do
|
232
|
-
spec{ use{ error_code = DdeGetLastError(
|
233
|
-
spec{ use{ error_code = dde_get_last_error(
|
259
|
+
spec{ use{ error_code = DdeGetLastError(@id) }}
|
260
|
+
spec{ use{ error_code = dde_get_last_error(@id) }}
|
234
261
|
|
235
262
|
it 'original API returns DMLERR_NO_ERROR if there is no last DDE error for given app instance' do
|
236
|
-
DdeGetLastError(
|
263
|
+
DdeGetLastError(@id).should == DMLERR_NO_ERROR
|
237
264
|
end
|
238
265
|
|
239
266
|
it 'snake_case API returns nil if there is no last DDE error for given app instance' do
|
240
|
-
dde_get_last_error(
|
267
|
+
dde_get_last_error(@id).should == nil
|
241
268
|
end
|
242
269
|
|
243
270
|
it 'returns error code of last DDE error for given app instance' do
|
244
|
-
dde_name_service(
|
245
|
-
dde_get_last_error(
|
271
|
+
dde_name_service(@id, 1234, DNS_REGISTER )
|
272
|
+
dde_get_last_error(@id).should == DMLERR_INVALIDPARAMETER
|
246
273
|
end
|
247
274
|
end # describe '#dde_get_last_error'
|
248
275
|
|
@@ -250,30 +277,23 @@ module WinDDETest
|
|
250
277
|
end # context 'after initialization:'
|
251
278
|
|
252
279
|
context 'with synthetic DDE client/server' do
|
253
|
-
before(:each)
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
280
|
+
before(:each){ setup_server }
|
281
|
+
after(:each) { teardown_server}
|
282
|
+
|
283
|
+
describe '#dde_name_service' do
|
284
|
+
spec{ use{ success = dde_name_service(@server_id, @service_handle, cmd=DNS_UNREGISTER ) }}
|
285
|
+
spec{ use{ success = DdeNameService(@server_id, @service_handle, reserved=0, cmd=DNS_UNREGISTER) }}
|
286
|
+
|
287
|
+
it 'registers or unregisters the service names that DDE server supports' do
|
288
|
+
pending 'Register/Unregister messages don`t show up in @server_calls :('
|
289
|
+
success = dde_name_service(@server_id, @service_handle, DNS_REGISTER )
|
290
|
+
success.should == true
|
291
|
+
success = dde_name_service(@server_id, @service_handle, DNS_UNREGISTER )
|
292
|
+
success.should == true
|
293
|
+
end
|
294
|
+
end # describe '#dde_name_service'
|
267
295
|
|
268
|
-
dde_name_service(@server_id, @service_handle, DNS_UNREGISTER)
|
269
|
-
dde_free_string_handle(@server_id, @service_handle)
|
270
|
-
dde_free_string_handle(@client_id, @topic_handle)
|
271
|
-
dde_uninitialize(@client_id)
|
272
|
-
dde_uninitialize(@server_id)
|
273
|
-
end
|
274
|
-
|
275
296
|
describe '#dde_connect' do
|
276
|
-
after(:each) { dde_disconnect(@conv_handle) if @conv_handle}
|
277
297
|
spec{ use{ @conv_handle = DdeConnect( instance_id=0, service=0, topic=0, context=nil) }}
|
278
298
|
spec{ use{ @conv_handle = dde_connect( instance_id=0, service=0, topic=0, context=nil) }}
|
279
299
|
|
@@ -288,19 +308,12 @@ module WinDDETest
|
|
288
308
|
@server_calls[1][4].should == 'service 2'
|
289
309
|
dde_disconnect(@server_conv).should == true
|
290
310
|
dde_disconnect(@conv_handle).should == true
|
291
|
-
|
292
|
-
p @server_calls, @client_calls, @conv_handle, @server_conv
|
293
|
-
p ERRORS[dde_get_last_error(@server_id)]
|
294
|
-
p ERRORS[dde_get_last_error(@client_id)]
|
295
311
|
end
|
296
|
-
|
297
|
-
it 'connects to existing DDE server (NOT self)' do
|
312
|
+
|
313
|
+
it 'connects to existing DDE server (from @client, NOT self)' do
|
298
314
|
pending 'something is wrong when connecting to separate service instance, uninitialize fails'
|
299
|
-
conv_handle = dde_connect( @client_id, @service_handle, @topic_handle, context=nil)
|
300
|
-
puts conv_handle
|
301
|
-
p @server_calls, @client_calls, @server_conv
|
302
|
-
p dde_disconnect(@server_conv) #conv_handle)
|
303
|
-
# p @server_calls, @client_calls
|
315
|
+
@conv_handle = dde_connect( @client_id, @service_handle, @topic_handle, context=nil)
|
316
|
+
puts @conv_handle
|
304
317
|
end
|
305
318
|
end # describe '#dde_connect'
|
306
319
|
|
@@ -312,67 +325,196 @@ module WinDDETest
|
|
312
325
|
dde_disconnect(12345).should == false
|
313
326
|
end
|
314
327
|
|
315
|
-
it 'disconnects from existing DDE server' do
|
316
|
-
|
328
|
+
it 'disconnects from existing (self) DDE server' do
|
329
|
+
conv_handle = dde_connect( @server_id, @service_handle, @topic_handle, context=nil)
|
330
|
+
dde_disconnect(conv_handle).should == true
|
317
331
|
end
|
318
|
-
end # describe '#dde_disconnect'
|
319
332
|
|
320
|
-
|
321
|
-
|
333
|
+
it 'disconnects from existing (self) DDE server' do
|
334
|
+
pending 'XTYP_DISCONNECT is not received by server callback (since we are disconnecting from self?)'
|
335
|
+
conv_handle = dde_connect( @server_id, @service_handle, @topic_handle, context=nil)
|
336
|
+
dde_disconnect(conv_handle).should == true
|
337
|
+
@server_calls.last[0].should == "XTYP_DISCONNECT"
|
322
338
|
p @server_calls, @client_calls, @server_conv
|
323
339
|
p ERRORS[dde_get_last_error(@server_id)]
|
324
340
|
p ERRORS[dde_get_last_error(@client_id)]
|
325
341
|
end
|
342
|
+
end # describe '#dde_disconnect'
|
343
|
+
end # context 'with synthetic DDE server'
|
326
344
|
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
str = FFI::MemoryPointer.from_string "Poke_string\n\x00\x00"
|
334
|
-
# res = DdeClientTransaction(str, str.size, @conv_handle, @topic_handle, CF_TEXT, XTYP_POKE, 1000, nil)
|
335
|
-
begin
|
336
|
-
get_message() if peek_message()
|
337
|
-
res = DdeClientTransaction(str, str.size, @conv_handle, @topic_handle, 0, XTYP_EXECUTE, 1000, nil)
|
338
|
-
p res
|
339
|
-
rescue => e
|
340
|
-
puts e.backtrace
|
341
|
-
raise e
|
342
|
-
end
|
345
|
+
describe "#dde_client_transaction" do
|
346
|
+
before(:each) do
|
347
|
+
setup_server do |*args|
|
348
|
+
@server_calls << extract_values(*args)
|
349
|
+
@data, size = dde_get_data(args[5]) if args.first == XTYP_POKE || args.first == XTYP_EXECUTE
|
350
|
+
DDE_FACK
|
343
351
|
end
|
352
|
+
end
|
353
|
+
after(:each) { teardown_server}
|
354
|
+
|
355
|
+
spec{ use{ DdeClientTransaction(data=nil, size=0, conv=0, item=0, format=0, type=0, timeout=0, result=nil) }}
|
356
|
+
spec{ use{ dde_client_transaction(data=nil, size=0, conv=0, item=0, format=0, type=0, timeout=0, result=nil) }}
|
357
|
+
|
358
|
+
it "original api is used by CLIENT to begins a data transaction with server" do
|
359
|
+
@conv_handle = dde_connect( @server_id, @service_handle, @topic_handle, context=nil)
|
360
|
+
str = FFI::MemoryPointer.from_string POKE_STRING
|
361
|
+
res = DdeClientTransaction(str, str.size, @conv_handle, @topic_handle, CF_TEXT, XTYP_POKE, 1000, nil)
|
362
|
+
res.should == 1
|
363
|
+
@server_calls.any? {|call| call[0] = 'XTYP_POKE'}.should be_true
|
364
|
+
@data.read_string.should == POKE_STRING.rstrip
|
365
|
+
end
|
366
|
+
|
367
|
+
it "snake_case api begins a data transaction between a client and a server" do
|
368
|
+
str = FFI::MemoryPointer.from_string POKE_STRING
|
369
|
+
@conv_handle = dde_connect( @server_id, @service_handle, @topic_handle, context=nil)
|
370
|
+
res = dde_client_transaction(str, str.size, @conv_handle, @topic_handle, 0, XTYP_EXECUTE, 1000, nil)
|
371
|
+
res.should == true
|
372
|
+
@server_calls.any? {|call| call[0] = 'XTYP_EXECUTE'}.should be_true
|
373
|
+
@data.read_string.should == POKE_STRING.rstrip
|
374
|
+
end
|
375
|
+
end # describe dde_client_transaction
|
376
|
+
|
377
|
+
describe '#dde_get_data' do
|
378
|
+
after(:each) { teardown_server}
|
344
379
|
|
345
|
-
|
346
|
-
|
347
|
-
|
380
|
+
spec{ use{ data_pointer, size = dde_get_data( data_handle = 123, max = 1073741823, offset = 0) }}
|
381
|
+
spec{ use{ size = DdeGetData( data_handle = 123, nil, 0, 0) }} # returns dde data set size in bytes
|
382
|
+
spec{ use{ size = DdeGetData( data_handle = 123, FFI::MemoryPointer.new(:char, 1024), max = 1024, offset = 0) }}
|
383
|
+
|
384
|
+
it 'original API returns 0 if trying to address invalid dde data handle' do
|
385
|
+
DdeGetData( data_handle = 123, nil, 0, 0).should == 0
|
386
|
+
end
|
387
|
+
|
388
|
+
it 'snake_case API returns [nil, 0] if trying to address invalid dde data handle' do
|
389
|
+
data, size = dde_get_data( data_handle = 123, 3741823, 0)
|
390
|
+
data.should == nil
|
391
|
+
end
|
392
|
+
|
393
|
+
it 'returns dde data if used inside dde callback block' do
|
394
|
+
setup_server do |*args|
|
395
|
+
@server_calls << extract_values(*args);
|
396
|
+
if args[0] == XTYP_POKE
|
397
|
+
data_handle = args[5]
|
398
|
+
data, size = dde_get_data(data_handle)
|
399
|
+
data.should be_an FFI::MemoryPointer
|
400
|
+
data.read_string.should == POKE_STRING.rstrip
|
401
|
+
size.should == 14
|
402
|
+
DdeGetData(data_handle, nil, 0, 0).should == 14
|
403
|
+
data = FFI::MemoryPointer.new(:char, 1024)
|
404
|
+
DdeGetData(data_handle, data, data.size, 0).should == 14
|
405
|
+
data.read_string.should == POKE_STRING.rstrip
|
406
|
+
end
|
407
|
+
DDE_FACK
|
348
408
|
end
|
349
|
-
|
409
|
+
@conv_handle = dde_connect( @server_id, @service_handle, @topic_handle, context=nil)
|
410
|
+
str = FFI::MemoryPointer.from_string POKE_STRING
|
411
|
+
dde_client_transaction(str, str.size, @conv_handle, @topic_handle, CF_TEXT, XTYP_POKE, 1000, nil)
|
412
|
+
end
|
350
413
|
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
414
|
+
it 'dde data handle expires once transaction is finished (DDE_FACK)' do
|
415
|
+
setup_server do |*args|
|
416
|
+
@server_calls << extract_values(*args);
|
417
|
+
DDE_FACK
|
418
|
+
end
|
419
|
+
@conv_handle = dde_connect( @server_id, @service_handle, @topic_handle, context=nil)
|
420
|
+
str = FFI::MemoryPointer.from_string POKE_STRING
|
421
|
+
dde_client_transaction(str, str.size, @conv_handle, @topic_handle, CF_TEXT, XTYP_POKE, 1000, nil)
|
422
|
+
|
423
|
+
# only inside callback block dde data handle is valid (while transaction still in progress)
|
424
|
+
data, size = dde_get_data(@server_calls.last[5])
|
425
|
+
data.should == nil
|
426
|
+
size.should == 0
|
427
|
+
end
|
355
428
|
|
356
|
-
|
357
|
-
|
429
|
+
end # describe '#dde_get_data'
|
430
|
+
|
431
|
+
describe "#dde_access_data" do
|
432
|
+
after(:each) { teardown_server}
|
433
|
+
|
434
|
+
spec{ use{ success = DdeAccessData(data_handle = 123, data_size=zero_id) }}
|
435
|
+
spec{ use{ data_pointer, size = dde_access_data(data_handle = 123) }}
|
436
|
+
|
437
|
+
it "provides access to the data in the specified DDE data handle (both inside and outside of callback)" do
|
438
|
+
setup_server do |*args|
|
439
|
+
@server_calls << extract_values(*args)
|
440
|
+
if args[0] == XTYP_POKE
|
441
|
+
data_handle = args[5]
|
442
|
+
data, size = dde_access_data(data_handle)
|
443
|
+
data.should be_kind_of FFI::Pointer
|
444
|
+
data.read_string.should == POKE_STRING.rstrip
|
445
|
+
size.should == 14
|
446
|
+
buf = FFI::MemoryPointer.new(:int16)
|
447
|
+
data = DdeAccessData(data_handle, buf)
|
448
|
+
buf.get_int16(0).should == 14
|
449
|
+
data.should be_kind_of FFI::Pointer
|
450
|
+
data.read_string.should == POKE_STRING.rstrip
|
451
|
+
dde_unaccess_data(data_handle)
|
452
|
+
end
|
453
|
+
DDE_FACK
|
358
454
|
end
|
455
|
+
@conv_handle = dde_connect( @server_id, @service_handle, @topic_handle, context=nil)
|
456
|
+
str = FFI::MemoryPointer.from_string POKE_STRING
|
457
|
+
dde_client_transaction(str, str.size, @conv_handle, @topic_handle, CF_TEXT, XTYP_POKE, 1000, nil)
|
458
|
+
end
|
359
459
|
|
360
|
-
|
361
|
-
|
460
|
+
it 'dde data handle expires once transaction is finished (DDE_FACK)' do
|
461
|
+
setup_server do |*args|
|
462
|
+
@server_calls << extract_values(*args);
|
463
|
+
DDE_FACK
|
362
464
|
end
|
465
|
+
@conv_handle = dde_connect( @server_id, @service_handle, @topic_handle, context=nil)
|
466
|
+
str = FFI::MemoryPointer.from_string POKE_STRING
|
467
|
+
dde_client_transaction(str, str.size, @conv_handle, @topic_handle, CF_TEXT, XTYP_POKE, 1000, nil)
|
468
|
+
|
469
|
+
# only inside callback block dde data handle is valid (while transaction still in progress)
|
470
|
+
data, size = dde_access_data(@server_calls.last[5])
|
471
|
+
data.should == nil
|
472
|
+
size.should == 0
|
473
|
+
end
|
474
|
+
end # describe dde_access_data
|
475
|
+
|
476
|
+
describe "#dde_unaccess_data" do
|
477
|
+
spec{ use{ success = DdeUnaccessData(data_handle = 123) }}
|
478
|
+
spec{ use{ success = dde_unaccess_data(data_handle = 123) }}
|
479
|
+
|
480
|
+
it "returns 0/false if given invalid DDE data handle " do
|
481
|
+
DdeUnaccessData(data_handle = 123).should == 0
|
482
|
+
dde_unaccess_data(data_handle = 123).should == false
|
483
|
+
end
|
484
|
+
|
485
|
+
it "unaccesses a DDE data handle that was previously accessed" do
|
486
|
+
setup_server do |*args|
|
487
|
+
@server_calls << extract_values(*args);
|
488
|
+
if args[0] == XTYP_POKE
|
489
|
+
data_handle = args[5]
|
490
|
+
dde_unaccess_data(data_handle).should == true
|
363
491
|
|
364
|
-
|
365
|
-
|
366
|
-
|
492
|
+
data, size = dde_access_data(data_handle)
|
493
|
+
data.should be_kind_of FFI::Pointer
|
494
|
+
data.read_string.should == POKE_STRING.rstrip
|
495
|
+
|
496
|
+
dde_unaccess_data(data_handle).should == true
|
497
|
+
end
|
498
|
+
DDE_FACK
|
367
499
|
end
|
500
|
+
@conv_handle = dde_connect( @server_id, @service_handle, @topic_handle, context=nil)
|
501
|
+
str = FFI::MemoryPointer.from_string POKE_STRING
|
502
|
+
dde_client_transaction(str, str.size, @conv_handle, @topic_handle, CF_TEXT, XTYP_POKE, 1000, nil)
|
503
|
+
end
|
368
504
|
|
369
|
-
|
370
|
-
|
371
|
-
|
505
|
+
it 'dde data handle expires once transaction is finished (DDE_FACK)' do
|
506
|
+
setup_server do |*args|
|
507
|
+
@server_calls << extract_values(*args);
|
508
|
+
DDE_FACK
|
372
509
|
end
|
510
|
+
@conv_handle = dde_connect( @server_id, @service_handle, @topic_handle, context=nil)
|
511
|
+
str = FFI::MemoryPointer.from_string POKE_STRING
|
512
|
+
dde_client_transaction(str, str.size, @conv_handle, @topic_handle, CF_TEXT, XTYP_POKE, 1000, nil)
|
373
513
|
|
374
|
-
|
514
|
+
# only inside callback block dde data handle is valid (while transaction still in progress)
|
515
|
+
dde_unaccess_data(@server_calls.last[5]).should == false
|
516
|
+
end
|
375
517
|
|
376
|
-
end #
|
518
|
+
end # describe dde_unaccess_data
|
377
519
|
end
|
378
520
|
end
|
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.26"
|
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-03-
|
12
|
+
s.date = %q{2010-03-17}
|
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.26
|
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-03-
|
12
|
+
date: 2010-03-17 00:00:00 +03:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|