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 CHANGED
@@ -1 +1 @@
1
- 0.1.22
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], :HDDEDATA
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, ename|
331
+ effective_name = effective_names.inject(nil) do |func, effective_name|
332
332
  func || begin
333
- attach_function(name, ename, params.dup, returns) # creates basic CamelCase method via FFI
334
- ename
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
- describe 'register_clipboard_format' do
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(@instance_id) if @instance_id}
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 = 0)}}
64
- spec{ use{ id, status = dde_initialize( instance_id = 0, dde_cmd) do|*args|
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
- @instance_id, status = dde_initialize(0, APPCLASS_STANDARD) {|*args| }
69
- @instance_id.should be_an Integer
70
- @instance_id.should_not == 0
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
- @instance_id, status = dde_initialize(nil, APPCLASS_STANDARD) {|*args| }
76
- @instance_id.should be_an Integer
77
- @instance_id.should_not == 0
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
- @instance_id, status = dde_initialize(APPCLASS_STANDARD) {|*args| }
83
- @instance_id.should be_an Integer
84
- @instance_id.should_not == 0
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
- @instance_id, status = dde_initialize(12345, APPCLASS_STANDARD) {|*args| }
122
+ @id, status = dde_initialize(12345, APPCLASS_STANDARD) {|*args| }
90
123
  status.should == DMLERR_INVALIDPARAMETER
91
- @instance_id.should == nil
124
+ @id.should == nil
92
125
  end
93
126
 
94
127
  it 'is able to reinitialize with correct id' do
95
- @instance_id, status = dde_initialize(APPCLASS_STANDARD) {|*args| }
96
- new_id, status = dde_initialize(@instance_id, APPCLASS_STANDARD) {|*args| }
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 == @instance_id
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) {@instance_id, status = dde_initialize(APPCLASS_STANDARD) {|*args| }}
104
- after(:each) {dde_uninitialize(@instance_id) if @instance_id}
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( @instance_id ) }}
109
- spec{ use{ id, status = dde_uninitialize( @instance_id) }}
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(@instance_id)
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(@instance_id, @string_handle) if @string_handle}
156
+ after(:each) {dde_free_string_handle(@id, @string_handle) if @string_handle}
124
157
 
125
- spec{ use{ @string_handle = DdeCreateStringHandle(instance_id=0, string_pointer, code_page_id=CP_WINANSI) }}
126
- spec{ use{ @string_handle = dde_create_string_handle(instance_id=0, string='Any String', code_page_id=CP_WINANSI)}}
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(@instance_id, 'My String', CP_WINANSI)
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(@instance_id, 'My String')
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(@instance_id, 'My String')
174
+ @string_handle = dde_create_string_handle(@id, 'My String')
142
175
  10.times do
143
- string_handle1 = dde_create_string_handle(@instance_id, 'My String')
176
+ string_handle1 = dde_create_string_handle(@id, 'My String')
144
177
  string_handle1.should == @string_handle
145
- dde_free_string_handle(@instance_id, string_handle1)
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(@instance_id, 'My String')
151
- string_handle1 = dde_create_string_handle(@instance_id, 'My String1')
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(@instance_id, string_handle1)
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(@instance_id, "", CP_WINANSI)
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(@instance_id, 'My String 2', CP_WINANSI)}
164
- after(:each) {dde_free_string_handle(@instance_id, @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(@instance_id, @string_handle, buffer, buffer.size, code_page=CP_WINANSI)}}
169
- spec{ use{ string = dde_query_string(@instance_id, @string_handle, code_page=CP_WINANSI )}}
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(@instance_id, @string_handle)
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(@instance_id, @string_handle)
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(@instance_id, 12345)
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( @instance_id, @string_handle)}}
190
- spec{ use{ success = dde_free_string_handle( @instance_id, @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(@instance_id, @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(@instance_id, 12345)
237
+ res = dde_free_string_handle(@id, 12345)
199
238
  res.should == false
200
239
  end
201
240
 
202
- it 'keeps string accessible if there are more handles to it around' do
203
- string_handle_1 = dde_create_string_handle(@instance_id, 'My String 2', CP_WINANSI)
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(@instance_id, @string_handle)
245
+ dde_free_string_handle(@id, @string_handle)
246
+ dde_query_string(@id, @string_handle).should == 'My String 2'
206
247
 
207
- dde_query_string(@instance_id, @string_handle).should == 'My String 2'
208
- dde_free_string_handle(@instance_id, string_handle_1)
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(@instance_id, @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( @instance_id) }}
233
- spec{ use{ error_code = dde_get_last_error( @instance_id) }}
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( @instance_id).should == DMLERR_NO_ERROR
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( @instance_id).should == nil
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( @instance_id, 1234, DNS_REGISTER )
245
- dde_get_last_error( @instance_id).should == DMLERR_INVALIDPARAMETER
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) do
254
- @client_calls = []
255
- @server_calls = []
256
- @client_id, status = dde_initialize(APPCLASS_STANDARD) {|*args| @client_calls << extract_values(*args); 1}
257
- @server_id, status = dde_initialize(APPCLASS_STANDARD) {|*args| @server_calls << extract_values(*args); 1}
258
- @service_handle = dde_create_string_handle(@server_id, 'service 2', CP_WINANSI)
259
- @topic_handle = dde_create_string_handle(@client_id, 'topic 2', CP_WINANSI)
260
- dde_name_service(@server_id, @service_handle, DNS_REGISTER)
261
- end
262
-
263
- after(:each) do
264
- # p @server_calls, @client_calls, @server_conv
265
- # p ERRORS[dde_get_last_error(@server_id)]
266
- # p ERRORS[dde_get_last_error(@client_id)]
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
- pending 'XTYP_DISCONNECT is not received by server callback for some reason'
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
- describe "#dde_client_transaction" do
321
- after(:each) do
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
- spec{ use{ res = DdeClientTransaction(data=nil, size=0, conv=0, item=0, format=0, type=0, timeout=0, result=nil) }}
328
- spec{ use{ res = dde_client_transaction(data=nil, size=0, conv=0, item=0, format=0, type=0, timeout=0, result=nil) }}
329
-
330
- it "original api is used by CLIENT to begins a data transaction with server" do
331
- # pending 'weird error - wrong number of arguments (8 for 0)'
332
- p @conv_handle = dde_connect( @server_id, @service_handle, @topic_handle, context=nil)
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
- it "snake_case api begins a data transaction between a client and a server. Only a Dynamic Data Exchange (DDE) client " do
346
- pending
347
- success = dde_client_transaction(p_data=0, cb_data=0, h_conv=0, hsz_item=0, w_fmt=0, w_type=0, dw_timeout=0, pdw_result=0)
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
- end # describe dde_client_transaction
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
- describe '#dde_get_data' do
352
- spec{ use{ buffer, success = dde_get_data( data_handle = 123, max = 1073741823, offset = 0) }}
353
- spec{ use{ length = DdeGetData( data_handle = 123, nil, 0, 0) }} # returns dde data set length
354
- spec{ use{ length = DdeGetData( data_handle = 123, FFI::MemoryPointer.new(:char, 1024), max = 1024, offset = 0) }}
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
- it 'original API returns 0 if trying to address invalid dde data handle' do
357
- DdeGetData( data_handle = 123, nil, 0, 0).should == 0
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
- it 'snake_case API returns nil if trying to address invalid dde data handle' do
361
- dde_get_data( data_handle = 123, 3741823, 0).should == nil
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
- it 'original API returns 1 if connect successful' do
365
- pending
366
- DdeGetData( data_handle = 123, nil, 0, 0).should == 0
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
- it 'snake_case API returns returns true if connect successful' do
370
- pending
371
- dde_get_data( data_handle = 123, 3741823, 0).should == nil
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
- end # describe '#dde_get_data'
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 # context 'with synthetic DDE server'
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.22"
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-06}
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.22
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-06 00:00:00 +03:00
12
+ date: 2010-03-17 00:00:00 +03:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency