private IntPtr ODdeNetCallback(int uType, int uFmt, IntPtr hConv, IntPtr hsz1, IntPtr hsz2, IntPtr hData, IntPtr dwData1, IntPtr dwData2) { // Create a new transaction object that will be dispatched to a DdemlClient, DdemlServer, or ITransactionFilter. DdemlTransaction t = new DdemlTransaction(uType, uFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2); // Run each transaction filter. foreach (IDdemlTransactionFilter filter in _Filters) { if (filter.PreFilterTransaction(t)) { return t.dwRet; } } // Dispatch the transaction. switch (uType) { case Ddeml.XTYP_ADVDATA: { DdemlClient client = _ClientTable[hConv] as DdemlClient; if (client != null) { if (client.ProcessCallback(t)) { return t.dwRet; } } break; } case Ddeml.XTYP_ADVREQ: { DdemlServer server = _ServerTable1[hConv] as DdemlServer; if (server != null) { if (server.ProcessCallback(t)) { return t.dwRet; } } break; } case Ddeml.XTYP_ADVSTART: { DdemlServer server = _ServerTable1[hConv] as DdemlServer; if (server != null) { if (server.ProcessCallback(t)) { return t.dwRet; } } break; } case Ddeml.XTYP_ADVSTOP: { DdemlServer server = _ServerTable1[hConv] as DdemlServer; if (server != null) { if (server.ProcessCallback(t)) { return t.dwRet; } } break; } case Ddeml.XTYP_CONNECT: { // Get the service name from the hsz2 string handle. StringBuilder psz = new StringBuilder(Ddeml.MAX_STRING_SIZE); int length = Ddeml.DdeQueryString(_InstanceId, hsz2, psz, psz.Capacity, Ddeml.CP_WINANSI); string service = psz.ToString(); DdemlServer server = _ServerTable2[service] as DdemlServer; if (server != null) { if (server.ProcessCallback(t)) { return t.dwRet; } } break; } case Ddeml.XTYP_CONNECT_CONFIRM: { // Get the service name from the hsz2 string handle. StringBuilder psz = new StringBuilder(Ddeml.MAX_STRING_SIZE); int length = Ddeml.DdeQueryString(_InstanceId, hsz2, psz, psz.Capacity, Ddeml.CP_WINANSI); string service = psz.ToString(); DdemlServer server = _ServerTable2[service] as DdemlServer; if (server != null) { _ServerTable1[hConv] = server; if (server.ProcessCallback(t)) { return t.dwRet; } } break; } case Ddeml.XTYP_DISCONNECT: { DdemlClient client = _ClientTable[hConv] as DdemlClient; if (client != null) { _ClientTable[hConv] = null; if (client.ProcessCallback(t)) { return t.dwRet; } } DdemlServer server = _ServerTable1[hConv] as DdemlServer; if (server != null) { _ServerTable1[hConv] = null; if (server.ProcessCallback(t)) { return t.dwRet; } } break; } case Ddeml.XTYP_EXECUTE: { DdemlServer server = _ServerTable1[hConv] as DdemlServer; if (server != null) { if (server.ProcessCallback(t)) { return t.dwRet; } } break; } case Ddeml.XTYP_POKE: { DdemlServer server = _ServerTable1[hConv] as DdemlServer; if (server != null) { if (server.ProcessCallback(t)) { return t.dwRet; } } break; } case Ddeml.XTYP_REQUEST: { DdemlServer server = _ServerTable1[hConv] as DdemlServer; if (server != null) { if (server.ProcessCallback(t)) { return t.dwRet; } } break; } case Ddeml.XTYP_XACT_COMPLETE: { DdemlClient client = _ClientTable[hConv] as DdemlClient; if (client != null) { if (client.ProcessCallback(t)) { return t.dwRet; } } break; } case Ddeml.XTYP_WILDCONNECT: { // This library does not support wild connects. return IntPtr.Zero; } case Ddeml.XTYP_MONITOR: { // Monitors are handled separately in DdemlMonitor. return IntPtr.Zero; } case Ddeml.XTYP_ERROR: { // Get the error code, but do nothing with it at this time. int error = dwData1.ToInt32(); return IntPtr.Zero; } case Ddeml.XTYP_REGISTER: { if (Register != null) { // Get the service name from the hsz1 string handle. StringBuilder psz = new StringBuilder(Ddeml.MAX_STRING_SIZE); int length = Ddeml.DdeQueryString(_InstanceId, hsz1, psz, psz.Capacity, Ddeml.CP_WINANSI); string service = psz.ToString(); Register(this, new DdemlRegistrationEventArgs(service)); } return IntPtr.Zero; } case Ddeml.XTYP_UNREGISTER: { if (Unregister != null) { // Get the service name from the hsz1 string handle. StringBuilder psz = new StringBuilder(Ddeml.MAX_STRING_SIZE); int length = Ddeml.DdeQueryString(_InstanceId, hsz1, psz, psz.Capacity, Ddeml.CP_WINANSI); string service = psz.ToString(); Unregister(this, new DdemlRegistrationEventArgs(service)); } return IntPtr.Zero; } } return IntPtr.Zero; }
internal bool ProcessCallback(DdemlTransaction transaction) { // This is here to alias the transaction object with a shorter variable name. DdemlTransaction t = transaction; switch (t.uType) { case Ddeml.XTYP_ADVDATA: { // Get the item name from the hsz2 string handle. StringBuilder psz = new StringBuilder(Ddeml.MAX_STRING_SIZE); int length = Ddeml.DdeQueryString(_InstanceId, t.hsz2, psz, psz.Capacity, Ddeml.CP_WINANSI); string item = psz.ToString(); // Delegate processing to the advise loop object. if (_AdviseLoopTable.ContainsKey(item)) { t.dwRet = _AdviseLoopTable[item].Process(t.uType, t.uFmt, t.hConv, t.hsz1, t.hsz2, t.hData, t.dwData1, t.dwData2); return true; } // This transaction could not be processed here. return false; } case Ddeml.XTYP_XACT_COMPLETE: { // Get the transaction identifier from dwData1. int transactionId = t.dwData1.ToInt32(); // Get the IAsyncResult from the asynchronous transaction table and delegate processing to it. if (_AsynchronousTransactionTable.ContainsKey(transactionId)) { AsyncResultBase arb = _AsynchronousTransactionTable[transactionId]; // Remove the IAsyncResult from the asynchronous transaction table. _AsynchronousTransactionTable.Remove(arb.TransactionId); t.dwRet = arb.Process(t.uType, t.uFmt, t.hConv, t.hsz1, t.hsz2, t.hData, t.dwData1, t.dwData2); return true; } // This transaction could not be processed here. return false; } case Ddeml.XTYP_DISCONNECT: { // Assign each active asynchronous transaction an exception so that the EndXXX methods do not deadlock. foreach (AsyncResultBase arb in _AsynchronousTransactionTable.Values) { arb.Process(new DdemlException(Resources.NotConnectedMessage)); } // Make sure the asynchronous transaction and advise loop tables are empty. _AsynchronousTransactionTable.Clear(); _AdviseLoopTable.Clear(); // Unregister this client from the context so that it will not receive DDEML callbacks. _Context.UnregisterClient(this); // Indicate that this object is no longer connected or paused. _Paused = false; _ConversationHandle = IntPtr.Zero; _InstanceId = 0; // Raise the StateChange event. if (StateChange != null) { StateChange(this, EventArgs.Empty); } // Raise the Disconnected event. if (Disconnected != null) { Disconnected(this, new DdemlDisconnectedEventArgs(true, false)); } // Return zero to indicate that there are no problems. t.dwRet = IntPtr.Zero; return true; } } // This transaction could not be processed here. return false; }
internal DdeTransaction(DdemlTransaction transaction) { _DdemlObject = transaction; }
public bool PreFilterTransaction(DdemlTransaction t) { return _OuterFilter.PreFilterTransaction(new DdeTransaction(t)); }
internal bool ProcessCallback(DdemlTransaction transaction) { // This is here to alias the transaction object with a shorter variable name. DdemlTransaction t = transaction; switch (t.uType) { case Ddeml.XTYP_ADVREQ: { StringBuilder psz; int length; // Get the topic name from the hsz1 string handle. psz = new StringBuilder(Ddeml.MAX_STRING_SIZE); length = Ddeml.DdeQueryString(_InstanceId, t.hsz1, psz, psz.Capacity, Ddeml.CP_WINANSI); string topic = psz.ToString(); // Get the item name from the hsz2 string handle. psz = new StringBuilder(Ddeml.MAX_STRING_SIZE); length = Ddeml.DdeQueryString(_InstanceId, t.hsz2, psz, psz.Capacity, Ddeml.CP_WINANSI); string item = psz.ToString(); // Create the advise request cache key. string key = topic + "!" + item + ":" + t.uFmt.ToString(); // Get the data being advised if the cache does not contain it already. if (!_AdviseRequestCache.ContainsKey(key)) { // Get the data from the subclass. byte[] data = OnAdvise(topic, item, t.uFmt); // Add the data to the cache because it will be needed later. _AdviseRequestCache.Add(key, data); } // Get the data from the advise request cache. byte[] cached = _AdviseRequestCache[key]; // Get the number of remaining transactions of this type for the same topic name, item name, and format tuple. int remaining = t.dwData1.ToInt32(); // If this is the last transaction then free the data handle. if (remaining == 0) { // TODO: Does the data handle really need to be freed here? // Remove the data from the cache because it is no longer needed. _AdviseRequestCache.Remove(key); } // Create and return the data handle representing the data being advised. if (cached != null && cached.Length > 0) { t.dwRet = Ddeml.DdeCreateDataHandle(_InstanceId, cached, cached.Length, 0, t.hsz2, t.uFmt, 0); return true; } // This transaction could not be processed here. return false; } case Ddeml.XTYP_ADVSTART: { // Get the item name from the hsz2 string handle. StringBuilder psz = new StringBuilder(Ddeml.MAX_STRING_SIZE); int length = Ddeml.DdeQueryString(_InstanceId, t.hsz2, psz, psz.Capacity, Ddeml.CP_WINANSI); string item = psz.ToString(); // Get the Conversation from the conversation table. DdemlConversation conversation = _ConversationTable[t.hConv]; // Get a value indicating whether an advise loop should be initiated from the subclass. t.dwRet = OnStartAdvise(conversation, item, t.uFmt) ? new IntPtr(1) : IntPtr.Zero; return true; } case Ddeml.XTYP_ADVSTOP: { // Get the item name from the hsz2 string handle. StringBuilder psz = new StringBuilder(Ddeml.MAX_STRING_SIZE); int length = Ddeml.DdeQueryString(_InstanceId, t.hsz2, psz, psz.Capacity, Ddeml.CP_WINANSI); string item = psz.ToString(); // Get the Conversation from the conversation table. DdemlConversation conversation = _ConversationTable[t.hConv]; // Inform the subclass that the advise loop has been terminated. OnStopAdvise(conversation, item); // Return zero to indicate that there are no problems. t.dwRet = IntPtr.Zero; return true; } case Ddeml.XTYP_CONNECT: { // Get the topic name from the hsz1 string handle. StringBuilder psz = new StringBuilder(Ddeml.MAX_STRING_SIZE); int length = Ddeml.DdeQueryString(_InstanceId, t.hsz1, psz, psz.Capacity, Ddeml.CP_WINANSI); string topic = psz.ToString(); // Get a value from the subclass indicating whether the connection should be allowed. t.dwRet = OnBeforeConnect(topic) ? new IntPtr(1) : IntPtr.Zero; return true; } case Ddeml.XTYP_CONNECT_CONFIRM: { // Get the topic name from the hsz1 string handle. StringBuilder psz = new StringBuilder(Ddeml.MAX_STRING_SIZE); int length = Ddeml.DdeQueryString(_InstanceId, t.hsz1, psz, psz.Capacity, Ddeml.CP_WINANSI); string topic = psz.ToString(); // Create a Conversation object and add it to the conversation table. _ConversationTable.Add(t.hConv, new DdemlConversation(t.hConv, _Service, topic)); // Inform the subclass that a conversation has been established. OnAfterConnect(_ConversationTable[t.hConv]); // Return zero to indicate that there are no problems. t.dwRet = IntPtr.Zero; return true; } case Ddeml.XTYP_DISCONNECT: { // Get the Conversation from the conversation table. DdemlConversation conversation = _ConversationTable[t.hConv]; // Remove the Conversation from the conversation table. _ConversationTable.Remove(t.hConv); // Inform the subclass that the conversation has been disconnected. OnDisconnect(conversation); // Return zero to indicate that there are no problems. t.dwRet = IntPtr.Zero; return true; } case Ddeml.XTYP_EXECUTE: { // Get the command from the data handle. int length = Ddeml.DdeGetData(t.hData, null, 0, 0); byte[] data = new byte[length]; length = Ddeml.DdeGetData(t.hData, data, data.Length, 0); string command = _Context.Encoding.GetString(data, 0, data.Length); if (command[command.Length - 1] == '\0') { command = command.Substring(0, command.Length - 1); } // Get the Conversation from the conversation table. DdemlConversation conversation = _ConversationTable[t.hConv]; // Send the command to the subclass and get the result. ExecuteResult result = OnExecute(conversation, command); // Return DDE_FACK if the subclass processed the command successfully. if (result == ExecuteResult.Processed) { t.dwRet = new IntPtr(Ddeml.DDE_FACK); return true; } // Return CBR_BLOCK if the subclass needs time to process the command. if (result == ExecuteResult.PauseConversation) { // Increment the conversation's waiting count. conversation.IncrementWaiting(); t.dwRet = new IntPtr(Ddeml.CBR_BLOCK); return true; } // Return DDE_FBUSY if the subclass is too busy. if (result == ExecuteResult.TooBusy) { t.dwRet = new IntPtr(Ddeml.DDE_FBUSY); return true; } // Return DDE_FNOTPROCESSED if the subclass did not process the command. t.dwRet = new IntPtr(Ddeml.DDE_FNOTPROCESSED); return true; } case Ddeml.XTYP_POKE: { // Get the item name from the hsz2 string handle. StringBuilder psz = new StringBuilder(Ddeml.MAX_STRING_SIZE); int length = Ddeml.DdeQueryString(_InstanceId, t.hsz2, psz, psz.Capacity, Ddeml.CP_WINANSI); string item = psz.ToString(); // Get the data from the data handle. length = Ddeml.DdeGetData(t.hData, null, 0, 0); byte[] data = new byte[length]; length = Ddeml.DdeGetData(t.hData, data, data.Length, 0); // Get the Conversation from the conversation table. DdemlConversation conversation = _ConversationTable[t.hConv]; // Send the data to the subclass and get the result. PokeResult result = OnPoke(conversation, item, data, t.uFmt); // Return DDE_FACK if the subclass processed the data successfully. if (result == PokeResult.Processed) { t.dwRet = new IntPtr(Ddeml.DDE_FACK); return true; } // Return CBR_BLOCK if the subclass needs time to process the data. if (result == PokeResult.PauseConversation) { // Increment the conversation's waiting count. conversation.IncrementWaiting(); t.dwRet = new IntPtr(Ddeml.CBR_BLOCK); return true; } // Return DDE_FBUSY if the subclass is too busy. if (result == PokeResult.TooBusy) { t.dwRet = new IntPtr(Ddeml.DDE_FBUSY); return true; } // Return DDE_FNOTPROCESSED if the subclass did not process the data. t.dwRet = new IntPtr(Ddeml.DDE_FNOTPROCESSED); return true; } case Ddeml.XTYP_REQUEST: { // Get the item name from the hsz2 string handle. StringBuilder psz = new StringBuilder(Ddeml.MAX_STRING_SIZE); int length = Ddeml.DdeQueryString(_InstanceId, t.hsz2, psz, psz.Capacity, Ddeml.CP_WINANSI); string item = psz.ToString(); // Get the Conversation from the conversation table. DdemlConversation conversation = _ConversationTable[t.hConv]; // Send the request to the subclass and get the result. RequestResult result = OnRequest(conversation, item, t.uFmt); // Return a data handle if the subclass processed the request successfully. if (result == RequestResult.Processed) { // Create and return the data handle for the data being requested. if (result.Data != null) { t.dwRet = Ddeml.DdeCreateDataHandle(_InstanceId, result.Data, result.Data.Length, 0, t.hsz2, t.uFmt, 0); } return true; } // Return CBR_BLOCK if the subclass needs time to process the request. if (result == RequestResult.PauseConversation) { conversation.IncrementWaiting(); t.dwRet = new IntPtr(Ddeml.CBR_BLOCK); return true; } // Return DDE_FNOTPROCESSED if the subclass did not process the command. t.dwRet = new IntPtr(Ddeml.DDE_FNOTPROCESSED); return true; } } // This transaction could not be processed here. return false; }