dde 0.2.9 → 0.2.11

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.
@@ -1,33 +1,33 @@
1
- module DDE
2
-
3
- # Class encapsulates DDE string. In addition to normal string behavior,
4
- # it also has *handle* that can be passed to dde functions
5
- class DdeString < String
6
- include Win::DDE
7
-
8
- attr_accessor :handle, # string handle passable to DDEML functions
9
- :instance_id, # instance id of DDE app that created this DdeString
10
- :code_page, # Windows code page for this string (CP_WINANSI or CP_WINUNICODE)
11
- :name # ORIGINAL string used to create this DdeString
12
-
13
- # Given the DDE application instance_id, you cane create DdeStrings
14
- # either from regular string or from known DdeString handle
15
- def initialize(instance_id, string_or_handle, code_page=CP_WINANSI)
16
- @instance_id = instance_id
17
- @code_page = code_page
18
-
19
- begin
20
- if string_or_handle.is_a? String
21
- @name = string_or_handle
22
- error unless @handle = dde_create_string_handle(@instance_id, @name, @code_page)
23
- else
24
- @handle = string_or_handle
25
- error unless @name = dde_query_string(@instance_id, @handle, @code_page)
26
- end
27
- rescue => e
28
- end
29
- raise DDE::Errors::StringError, "Failed to initialize DDE string: #{e} #{e.backtrace.join("\n")}" unless @handle && @name && !e
30
- super @name
31
- end
32
- end
1
+ module Dde
2
+
3
+ # Class encapsulates DDE string. In addition to normal string behavior,
4
+ # it also has *handle* that can be passed to dde functions
5
+ class DdeString < String
6
+ include Win::Dde
7
+
8
+ attr_accessor :handle, # string handle passable to DDEML functions
9
+ :instance_id, # instance id of DDE app that created this DdeString
10
+ :code_page, # Windows code page for this string (CP_WINANSI or CP_WINUNICODE)
11
+ :name # ORIGINAL string used to create this DdeString
12
+
13
+ # Given the DDE application instance_id, you cane create DdeStrings
14
+ # either from regular string or from known DdeString handle
15
+ def initialize(instance_id, string_or_handle, code_page=CP_WINANSI)
16
+ @instance_id = instance_id
17
+ @code_page = code_page
18
+
19
+ begin
20
+ if string_or_handle.is_a? String
21
+ @name = string_or_handle
22
+ error unless @handle = dde_create_string_handle(@instance_id, @name, @code_page)
23
+ else
24
+ @handle = string_or_handle
25
+ error unless @name = dde_query_string(@instance_id, @handle, @code_page)
26
+ end
27
+ rescue => e
28
+ end
29
+ raise Dde::Errors::StringError, "Failed to initialize DDE string: #{e} #{e.backtrace.join("\n")}" unless @handle && @name && !e
30
+ super @name
31
+ end
32
+ end
33
33
  end
@@ -1,94 +1,94 @@
1
- module DDE
2
-
3
- # Class encapsulates DDE Monitor that prints all DDE transactions to console
4
- class Monitor < App
5
-
6
- attr_accessor :print, :calls
7
-
8
- # Creates new DDE monitor instance
9
- def initialize(init_flags=nil, print = nil, &callback)
10
- init_flags ||=
11
- APPCLASS_MONITOR | # this is monitor
12
- MF_CALLBACKS | # monitor callback functions
13
- MF_CONV | # monitor conversation data
14
- MF_ERRORS | # monitor DDEML errors
15
- MF_HSZ_INFO | # monitor data handle activity
16
- MF_LINKS | # monitor advise loops
17
- MF_POSTMSGS | # monitor posted DDE messages
18
- MF_SENDMSGS # monitor sent DDE messages
19
-
20
- @print = print
21
- @calls = []
22
-
23
- callback ||= lambda do |*args|
24
- time = Time.now.strftime('%T.%6N')
25
- values = extract_values(*args)
26
- @calls << [time, values]
27
- puts "#{time} #{values}" if @print
28
- DDE_FACK
29
- end
30
-
31
- super init_flags, &callback
32
- end
33
-
34
- def extract_values(*args)
35
- values = args.map {|arg| interprete_value(arg)}
36
-
37
- # if this is a MONITOR transaction, extract hdata using the DdeAccessData
38
- if values.first == :XTYP_MONITOR
39
- data_type = case values.last
40
- when :MF_CALLBACKS
41
- MonCbStruct #.new(dde_get_data(args[5]).first)
42
- # cb:: Specifies the structure's size, in bytes.
43
- # dwTime:: Specifies the Windows time at which the transaction occurred. Windows time is the number of
44
- # milliseconds that have elapsed since the system was booted.
45
- # hTask:: Handle to the task (app instance) containing the DDE callback function that received the transaction.
46
- # dwRet:: Specifies the value returned by the DDE callback function that processed the transaction.
47
- # wType:: Specifies the transaction type.
48
- # wFmt:: Specifies the format of the data exchanged (if any) during the transaction.
49
- # hConv:: Handle to the conversation in which the transaction took place.
50
- # hsz1:: Handle to a string.
51
- # hsz2:: Handle to a string.
52
- # hData:: Handle to the data exchanged (if any) during the transaction.
53
- # dwData1:: Specifies additional data.
54
- # dwData2:: Specifies additional data.
55
- # cc:: Specifies a CONVCONTEXT structure containing language information used to share data in different languages.
56
- # cbData:: Specifies the amount, in bytes, of data being passed with the transaction. This value can be
57
- # more than 32 bytes.
58
- # Data:: Contains the first 32 bytes of data being passed with the transaction (8 * sizeof(DWORD)).
59
-
60
- when :MF_CONV
61
- MonConvStruct
62
- when :MF_ERRORS
63
- MonErrStruct
64
- when :MF_HSZ_INFO
65
- MonHszStruct
66
- when :MF_LINKS
67
- MonLinksStruct
68
- else
69
- MonMsgStruct
70
- end
71
-
72
- #casting DDE data pointer into appropriate struct type
73
- struct_pointer, size = dde_get_data(args[5])
74
- data = data_type.new(struct_pointer)
75
-
76
- values = [values.first, values.last] + data.members.map do |member|
77
- value = data[member] rescue 'plonk'
78
- "#{member}: #{interprete_value(value)}"
79
- end
80
- end
81
-
82
- values
83
- end
84
-
85
- def interprete_value(arg)
86
- return arg unless arg.kind_of? Fixnum rescue return 'plAnk'
87
- return 0 if arg == 0
88
- #Trying to interpete arg as a DDE string
89
- dde_query_string(@id, arg)\
90
- || Win::DDE.constants(false).inject(nil) {|res, const| arg == Win::DDE.const_get(const) ? res || const : res }\
91
- || arg
92
- end
93
- end
1
+ module Dde
2
+
3
+ # Class encapsulates DDE Monitor that prints all DDE transactions to console
4
+ class Monitor < App
5
+
6
+ attr_accessor :print, :calls
7
+
8
+ # Creates new DDE monitor instance
9
+ def initialize(init_flags=nil, print = nil, &callback)
10
+ init_flags ||=
11
+ APPCLASS_MONITOR | # this is monitor
12
+ MF_CALLBACKS | # monitor callback functions
13
+ MF_CONV | # monitor conversation data
14
+ MF_ERRORS | # monitor DDEML errors
15
+ MF_HSZ_INFO | # monitor data handle activity
16
+ MF_LINKS | # monitor advise loops
17
+ MF_POSTMSGS | # monitor posted DDE messages
18
+ MF_SENDMSGS # monitor sent DDE messages
19
+
20
+ @print = print
21
+ @calls = []
22
+
23
+ callback ||= lambda do |*args|
24
+ time = Time.now.strftime('%T.%6N')
25
+ values = extract_values(*args)
26
+ @calls << [time, values]
27
+ puts "#{time} #{values}" if @print
28
+ DDE_FACK
29
+ end
30
+
31
+ super init_flags, &callback
32
+ end
33
+
34
+ def extract_values(*args)
35
+ values = args.map {|arg| interprete_value(arg)}
36
+
37
+ # if this is a MONITOR transaction, extract hdata using the DdeAccessData
38
+ if values.first == :XTYP_MONITOR
39
+ data_type = case values.last
40
+ when :MF_CALLBACKS
41
+ MonCbStruct #.new(dde_get_data(args[5]).first)
42
+ # cb:: Specifies the structure's size, in bytes.
43
+ # dwTime:: Specifies the Windows time at which the transaction occurred. Windows time is the number of
44
+ # milliseconds that have elapsed since the system was booted.
45
+ # hTask:: Handle to the task (app instance) containing the DDE callback function that received the transaction.
46
+ # dwRet:: Specifies the value returned by the DDE callback function that processed the transaction.
47
+ # wType:: Specifies the transaction type.
48
+ # wFmt:: Specifies the format of the data exchanged (if any) during the transaction.
49
+ # hConv:: Handle to the conversation in which the transaction took place.
50
+ # hsz1:: Handle to a string.
51
+ # hsz2:: Handle to a string.
52
+ # hData:: Handle to the data exchanged (if any) during the transaction.
53
+ # dwData1:: Specifies additional data.
54
+ # dwData2:: Specifies additional data.
55
+ # cc:: Specifies a CONVCONTEXT structure containing language information used to share data in different languages.
56
+ # cbData:: Specifies the amount, in bytes, of data being passed with the transaction. This value can be
57
+ # more than 32 bytes.
58
+ # Data:: Contains the first 32 bytes of data being passed with the transaction (8 * sizeof(DWORD)).
59
+
60
+ when :MF_CONV
61
+ MonConvStruct
62
+ when :MF_ERRORS
63
+ MonErrStruct
64
+ when :MF_HSZ_INFO
65
+ MonHszStruct
66
+ when :MF_LINKS
67
+ MonLinksStruct
68
+ else
69
+ MonMsgStruct
70
+ end
71
+
72
+ #casting DDE data pointer into appropriate struct type
73
+ struct_pointer, size = dde_get_data(args[5])
74
+ data = data_type.new(struct_pointer)
75
+
76
+ values = [values.first, values.last] + data.members.map do |member|
77
+ value = data[member] rescue 'plonk'
78
+ "#{member}: #{interprete_value(value)}"
79
+ end
80
+ end
81
+
82
+ values
83
+ end
84
+
85
+ def interprete_value(arg)
86
+ return arg unless arg.kind_of? Fixnum rescue return 'plAnk'
87
+ return 0 if arg == 0
88
+ #Trying to interpete arg as a DDE string
89
+ dde_query_string(@id, arg)\
90
+ || Win::Dde.constants(false).inject(nil) {|res, const| arg == Win::Dde.const_get(const) ? res || const : res }\
91
+ || arg
92
+ end
93
+ end
94
94
  end
@@ -1,41 +1,41 @@
1
- module DDE
2
-
3
- # Class encapsulates DDE Server with basic functionality (starting/stopping named service)
4
- class Server < App
5
-
6
- attr_reader :service # service(s) that this Server supports
7
-
8
- def start_service( name, init_flags=nil, &dde_callback )
9
- try "Starting service #{name}", DDE::Errors::ServiceError do
10
- # Trying to start DDE if it was inactive
11
- error unless dde_active? || start_dde( init_flags, &dde_callback )
12
-
13
- # Create DDE string for name (this creates handle that can be passed to DDEML functions)
14
- @service = DDE::DdeString.new(@id, name)
15
-
16
- # Register new DDE service, returns true/false success code
17
- error unless dde_name_service(@id, @service.handle, DNS_REGISTER)
18
- end
19
- end
20
-
21
- def stop_service
22
- try "Stopping active service", DDE::Errors::ServiceError do
23
- error "Either DDE or service not initialized" unless dde_active? && service_active?
24
-
25
- # Unregister DDE service, returns true/false success code
26
- error unless dde_name_service(@id, @service.handle, DNS_UNREGISTER);
27
-
28
- # Free string handle for service name
29
- error unless dde_free_string_handle(@id, @service.handle)
30
-
31
- # Clear handle if service successfuly stopped
32
- @service = nil
33
- end
34
- end
35
-
36
- def service_active?
37
- !!@service
38
- end
39
-
40
- end
1
+ module Dde
2
+
3
+ # Class encapsulates DDE Server with basic functionality (starting/stopping named service)
4
+ class Server < App
5
+
6
+ attr_reader :service # service(s) that this Server supports
7
+
8
+ def start_service( name, init_flags=nil, &dde_callback )
9
+ try "Starting service #{name}", Dde::Errors::ServiceError do
10
+ # Trying to start DDE if it was inactive
11
+ error unless dde_active? || start_dde( init_flags, &dde_callback )
12
+
13
+ # Create DDE string for name (this creates handle that can be passed to DDEML functions)
14
+ @service = Dde::DdeString.new(@id, name)
15
+
16
+ # Register new DDE service, returns true/false success code
17
+ error unless dde_name_service(@id, @service.handle, DNS_REGISTER)
18
+ end
19
+ end
20
+
21
+ def stop_service
22
+ try "Stopping active service", Dde::Errors::ServiceError do
23
+ error "Either DDE or service not initialized" unless dde_active? && service_active?
24
+
25
+ # Unregister DDE service, returns true/false success code
26
+ error unless dde_name_service(@id, @service.handle, DNS_UNREGISTER);
27
+
28
+ # Free string handle for service name
29
+ error unless dde_free_string_handle(@id, @service.handle)
30
+
31
+ # Clear handle if service successfuly stopped
32
+ @service = nil
33
+ end
34
+ end
35
+
36
+ def service_active?
37
+ !!@service
38
+ end
39
+
40
+ end
41
41
  end
@@ -1,90 +1,90 @@
1
- require 'dde/xl_table'
2
-
3
- module DDE
4
-
5
- # Class encapsulates DDE Server mimicking Excel. It is used to create DDE server with specific service name
6
- # (default name 'excel') and store data received by the server via DDE
7
- class XlServer < Server
8
-
9
- attr_reader :format, # data format(s) (registered clipboard formats) that server supports
10
- :data # data storage/processor
11
-
12
- attr_accessor :actions # Actions to be run on table after each successful DDE input (:draw, :debug, :timer)
13
-
14
- # Creates new Xl Server instance
15
- def initialize(init_flags = nil, &dde_callback )
16
-
17
- @data = DDE::XlTable.new
18
-
19
- # Trying to register or retrieve existing format XlTable
20
- try 'Registering format XlTable', DDE::Errors::FormatError do
21
- @format = register_clipboard_format("XlTable")
22
- end
23
-
24
- super init_flags, &dde_callback
25
- end
26
-
27
- # HDDEDATA CALLBACK DdeCallback(UINT uType, UINT uFmt, HCONV hConv, HSZ hsz1, HSZ hsz2,
28
- # HDDEDATA hData, DWORD dwData1, DWORD dwData2)
29
- def default_callback
30
- lambda do |type, format, conv, hsz1, hsz2, data_handle, data1, data2|
31
- case type
32
- when XTYP_CONNECT # Request to connect from client, creating data exchange channel
33
- # format:: Not used.
34
- # conv:: Not used.
35
- # hsz1:: Handle to the topic name.
36
- # hsz2:: Handle to the service name.
37
- # data_handle:: Handle to DDE data. Meaning depends on the type of the current transaction.
38
- # data1:: Pointer to a CONVCONTEXT structure that contains context information for the conversation.
39
- # If the client is not a DDEML application, this parameter is 0.
40
- # data2:: Specifies whether the client is the same application instance as the server. If the parameter
41
- # is 1, the client is the same instance. If it is 0, the client is a different instance.
42
- # *Returns*:: A server callback function should return TRUE(1, but DDE_FACK works just fine too)
43
- # to allow the client to establish a conversation on the specified service name and topic
44
- # name pair, or the function should return FALSE to deny the conversation. If the callback
45
- # function returns TRUE and a conversation is successfully established, the system passes
46
- # the conversation handle to the server by issuing an XTYP_CONNECT_CONFIRM transaction to
47
- # the server's callback function (unless the server specified the CBF_SKIP_CONNECT_CONFIRMS
48
- # flag in the DdeInitialize function).
49
-
50
- if hsz2 == @service.handle
51
- cout "Service #{@service}: connect requested by client\n"
52
- DDE_FACK # instead of true # Yes, this server supports requested (name) handle
53
- else
54
- cout "Service #{@service} unable to process connection request for #{hsz2}\n"
55
- DDE_FNOTPROCESSED # 0 instead of false # No, server does not support requested (name) handle
56
- end
57
-
58
- when XTYP_POKE # Client initiated XTYP_POKE transaction to push unsolicited data to the server
59
- # format:: Specifies the format of the data sent from the server.
60
- # conv:: Handle to the conversation.
61
- # hsz1:: Handle to the topic name. (Excel: [topic]item ?!)
62
- # hsz2:: Handle to the item name.
63
- # data_handle:: Handle to the data that the client is sending to the server.
64
- # *Returns*:: A server callback function should return the DDE_FACK flag if it processes this
65
- # transaction, the DDE_FBUSY flag if it is too busy to process this transaction,
66
- # or the DDE_FNOTPROCESSED flag if it rejects this transaction.
67
-
68
- @data.topic = dde_query_string(@id, hsz1) # Convert hsz1 into "[topic]item" string and
69
- if @data.receive(data_handle) # Receive incoming DDE data and process it
70
-
71
- # Perform actions like :draw, :debug, :timer, :formats on received data (default :timer)
72
- @actions.each{|action| @data.send(action.to_sym)}
73
- DDE_FACK # Transaction successful
74
- else
75
- @data.debug
76
- cout "Service #{@service} unable to process data request (XTYP_POKE) for #{hsz2}"
77
- DDE_FNOTPROCESSED # 0 Transaction NOT successful - return (HDDEDATA)TRUE; ?!(why TRUE, not FALSE)
78
- end
79
- else
80
- DDE_FNOTPROCESSED # 0 - return((HDDEDATA)NULL);// is it the same as 0 ?!
81
- end
82
- end
83
- end
84
-
85
- def start_service( name='excel', init_flags=nil, &dde_callback)
86
- super name, init_flags, &dde_callback || default_callback
87
- end
88
-
89
- end
1
+ require 'dde/xl_table'
2
+
3
+ module Dde
4
+
5
+ # Class encapsulates DDE Server mimicking Excel. It is used to create DDE server with specific service name
6
+ # (default name 'excel') and store data received by the server via DDE
7
+ class XlServer < Server
8
+
9
+ attr_reader :format, # data format(s) (registered clipboard formats) that server supports
10
+ :data # data storage/processor
11
+
12
+ attr_accessor :actions # Actions to be run on table after each successful DDE input (:draw, :debug, :timer)
13
+
14
+ # Creates new Xl Server instance
15
+ def initialize(init_flags = nil, &dde_callback )
16
+
17
+ @data = Dde::XlTable.new
18
+
19
+ # Trying to register or retrieve existing format XlTable
20
+ try 'Registering format XlTable', Dde::Errors::FormatError do
21
+ @format = register_clipboard_format("XlTable")
22
+ end
23
+
24
+ super init_flags, &dde_callback
25
+ end
26
+
27
+ # HDDEDATA CALLBACK DdeCallback(UINT uType, UINT uFmt, HCONV hConv, HSZ hsz1, HSZ hsz2,
28
+ # HDDEDATA hData, DWORD dwData1, DWORD dwData2)
29
+ def default_callback
30
+ lambda do |type, format, conv, hsz1, hsz2, data_handle, data1, data2|
31
+ case type
32
+ when XTYP_CONNECT # Request to connect from client, creating data exchange channel
33
+ # format:: Not used.
34
+ # conv:: Not used.
35
+ # hsz1:: Handle to the topic name.
36
+ # hsz2:: Handle to the service name.
37
+ # data_handle:: Handle to DDE data. Meaning depends on the type of the current transaction.
38
+ # data1:: Pointer to a CONVCONTEXT structure that contains context information for the conversation.
39
+ # If the client is not a DDEML application, this parameter is 0.
40
+ # data2:: Specifies whether the client is the same application instance as the server. If the parameter
41
+ # is 1, the client is the same instance. If it is 0, the client is a different instance.
42
+ # *Returns*:: A server callback function should return TRUE(1, but DDE_FACK works just fine too)
43
+ # to allow the client to establish a conversation on the specified service name and topic
44
+ # name pair, or the function should return FALSE to deny the conversation. If the callback
45
+ # function returns TRUE and a conversation is successfully established, the system passes
46
+ # the conversation handle to the server by issuing an XTYP_CONNECT_CONFIRM transaction to
47
+ # the server's callback function (unless the server specified the CBF_SKIP_CONNECT_CONFIRMS
48
+ # flag in the DdeInitialize function).
49
+
50
+ if hsz2 == @service.handle
51
+ cout "Service #{@service}: connect requested by client\n"
52
+ DDE_FACK # instead of true # Yes, this server supports requested (name) handle
53
+ else
54
+ cout "Service #{@service} unable to process connection request for #{hsz2}\n"
55
+ DDE_FNOTPROCESSED # 0 instead of false # No, server does not support requested (name) handle
56
+ end
57
+
58
+ when XTYP_POKE # Client initiated XTYP_POKE transaction to push unsolicited data to the server
59
+ # format:: Specifies the format of the data sent from the server.
60
+ # conv:: Handle to the conversation.
61
+ # hsz1:: Handle to the topic name. (Excel: [topic]item ?!)
62
+ # hsz2:: Handle to the item name.
63
+ # data_handle:: Handle to the data that the client is sending to the server.
64
+ # *Returns*:: A server callback function should return the DDE_FACK flag if it processes this
65
+ # transaction, the DDE_FBUSY flag if it is too busy to process this transaction,
66
+ # or the DDE_FNOTPROCESSED flag if it rejects this transaction.
67
+
68
+ @data.topic = dde_query_string(@id, hsz1) # Convert hsz1 into "[topic]item" string and
69
+ if @data.receive(data_handle) # Receive incoming DDE data and process it
70
+
71
+ # Perform actions like :draw, :debug, :timer, :formats on received data (default :timer)
72
+ @actions.each{|action| @data.send(action.to_sym)}
73
+ DDE_FACK # Transaction successful
74
+ else
75
+ @data.debug
76
+ cout "Service #{@service} unable to process data request (XTYP_POKE) for #{hsz2}"
77
+ DDE_FNOTPROCESSED # 0 Transaction NOT successful - return (HDDEDATA)TRUE; ?!(why TRUE, not FALSE)
78
+ end
79
+ else
80
+ DDE_FNOTPROCESSED # 0 - return((HDDEDATA)NULL);// is it the same as 0 ?!
81
+ end
82
+ end
83
+ end
84
+
85
+ def start_service( name='excel', init_flags=nil, &dde_callback)
86
+ super name, init_flags, &dde_callback || default_callback
87
+ end
88
+
89
+ end
90
90
  end