Class: Dde::XlServer

Inherits:
Server show all
Defined in:
lib/dde/xl_server.rb

Overview

Class encapsulates DDE Server mimicking Excel. It is used to create DDE server with specific service name (default name ‘excel’) and store data received by the server via DDE

Instance Attribute Summary collapse

Attributes inherited from Server

#service

Attributes inherited from App

#id, #init_flags

Instance Method Summary collapse

Methods inherited from Server

#service_active?, #stop_service

Methods inherited from App

#dde_active?, #error, #start_dde, #stop_dde, #try

Constructor Details

#initialize(init_flags = nil, &dde_callback) ⇒ XlServer

Creates new Xl Server instance



15
16
17
18
19
20
21
22
23
24
25
# File 'lib/dde/xl_server.rb', line 15

def initialize(init_flags = nil, &dde_callback )

  @data = Dde::XlTable.new

  # Trying to register or retrieve existing format XlTable
  try 'Registering format XlTable', Dde::Errors::FormatError do
    @format = register_clipboard_format("XlTable")
  end

  super init_flags, &dde_callback
end

Instance Attribute Details

#actionsObject

Actions to be run on table after each successful DDE input (:draw, :debug, :timer)



12
13
14
# File 'lib/dde/xl_server.rb', line 12

def actions
  @actions
end

#dataObject (readonly)

data format(s) (registered clipboard formats) that server supports



9
10
11
# File 'lib/dde/xl_server.rb', line 9

def data
  @data
end

#formatObject (readonly)

data format(s) (registered clipboard formats) that server supports



9
10
11
# File 'lib/dde/xl_server.rb', line 9

def format
  @format
end

Instance Method Details

#default_callbackObject

HDDEDATA CALLBACK DdeCallback(UINT uType, UINT uFmt, HCONV hConv, HSZ hsz1, HSZ hsz2,

HDDEDATA hData, DWORD dwData1, DWORD dwData2)


29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/dde/xl_server.rb', line 29

def default_callback
  lambda do |type, format, conv, hsz1, hsz2, data_handle, data1, data2|
    case type
      when XTYP_CONNECT  # Request to connect from client, creating data exchange channel
        #     format:: Not used.
        #     conv:: Not used.
        #     hsz1:: Handle to the topic name.
        #     hsz2:: Handle to the service name.
        #     data_handle:: Handle to DDE data. Meaning depends on the type of the current transaction.
        #     data1:: Pointer to a CONVCONTEXT structure that contains context information for the conversation.
        #             If the client is not a DDEML application, this parameter is 0.
        #     data2:: Specifies whether the client is the same application instance as the server. If the parameter
        #             is 1, the client is the same instance. If it is 0, the client is a different instance.
        #     *Returns*:: A server callback function should return TRUE(1, but DDE_FACK works just fine too)
        #                 to allow the client to establish a conversation on the specified service name and topic
        #                 name pair, or the function should return FALSE to deny the conversation. If the callback
        #                 function returns TRUE and a conversation is successfully established, the system passes
        #                 the conversation handle to the server by issuing an XTYP_CONNECT_CONFIRM transaction to
        #                 the server's callback function (unless the server specified the CBF_SKIP_CONNECT_CONFIRMS
        #                 flag in the DdeInitialize function).

        if hsz2 == @service.handle
          cout "Service #{@service}: connect requested by client\n"
          DDE_FACK # instead of true     # Yes, this server supports requested (name) handle
        else
          cout "Service #{@service} unable to process connection request for #{hsz2}\n"
          DDE_FNOTPROCESSED # 0 instead of false    # No, server does not support requested (name) handle
        end

      when XTYP_POKE  # Client initiated XTYP_POKE transaction to push unsolicited data to the server
        #     format:: Specifies the format of the data sent from the server.
        #     conv:: Handle to the conversation.
        #     hsz1:: Handle to the topic name. (Excel: [topic]item ?!)
        #     hsz2:: Handle to the item name.
        #     data_handle:: Handle to the data that the client is sending to the server.
        #     *Returns*:: A server callback function should return the DDE_FACK flag if it processes this
        #                 transaction, the DDE_FBUSY flag if it is too busy to process this transaction,
        #                 or the DDE_FNOTPROCESSED flag if it rejects this transaction.

        @data.topic = dde_query_string(@id, hsz1)  # Convert hsz1 into "[topic]item" string and
        if @data.receive(data_handle)              # Receive incoming DDE data and process it

          # Perform actions like :draw, :debug, :timer, :formats on received data (default :timer)
          @actions.each{|action| @data.send(action.to_sym)}
          DDE_FACK  # Transaction successful
        else
          @data.debug
          cout "Service #{@service} unable to process data request (XTYP_POKE) for #{hsz2}"
          DDE_FNOTPROCESSED   # 0 Transaction NOT successful - return (HDDEDATA)TRUE; ?!(why TRUE, not FALSE)
        end
      else
        DDE_FNOTPROCESSED   # 0 - return((HDDEDATA)NULL);// is it the same as 0 ?!
    end
  end
end

#start_service(name = 'excel', init_flags = nil, &dde_callback) ⇒ Object



85
86
87
# File 'lib/dde/xl_server.rb', line 85

def start_service( name='excel', init_flags=nil, &dde_callback)
  super name, init_flags, &dde_callback || default_callback
end