dde 0.2.9 → 0.2.11

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