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