win 0.1.22 → 0.1.26

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION 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