private void OnConversation(Ddeml.MONCONVSTRUCT mon) { StringBuilder psz; int length; // Get the service name from the hszSvc string handle. psz = new StringBuilder(Ddeml.MAX_STRING_SIZE); length = Ddeml.DdeQueryString(_Context.InstanceId, mon.hszSvc, psz, psz.Capacity, Ddeml.CP_WINANSI); string service = psz.ToString(); // Get the topic name from the hszTopic string handle. psz = new StringBuilder(Ddeml.MAX_STRING_SIZE); length = Ddeml.DdeQueryString(_Context.InstanceId, mon.hszTopic, psz, psz.Capacity, Ddeml.CP_WINANSI); string topic = psz.ToString(); DdemlConversationActivityEventArgs args = new DdemlConversationActivityEventArgs( service, topic, mon.fConnect, mon.hConvClient, mon.hConvServer, mon.hTask); if (ConversationActivity != null) { ConversationActivity(this, args); } }
private void OnLink(Ddeml.MONLINKSTRUCT mon) { // Get the service name from the hszSvc string handle. var psz = new StringBuilder(Ddeml.MAX_STRING_SIZE); var length = Ddeml.DdeQueryString(_Context.InstanceId, mon.hszSvc, psz, psz.Capacity, Ddeml.CP_WINANSI); var service = psz.ToString(); // Get the topic name from the hszTopic string handle. psz = new StringBuilder(Ddeml.MAX_STRING_SIZE); length = Ddeml.DdeQueryString(_Context.InstanceId, mon.hszTopic, psz, psz.Capacity, Ddeml.CP_WINANSI); var topic = psz.ToString(); // Get the item name from the hszItem string handle. psz = new StringBuilder(Ddeml.MAX_STRING_SIZE); length = Ddeml.DdeQueryString(_Context.InstanceId, mon.hszItem, psz, psz.Capacity, Ddeml.CP_WINANSI); var item = psz.ToString(); var args = new DdemlLinkActivityEventArgs( service, topic, item, mon.wFmt, !mon.fNoData, mon.fEstablished, mon.fServer, mon.hConvClient, mon.hConvServer, mon.hTask); LinkActivity?.Invoke(this, args); }
private void OnString(Ddeml.MONHSZSTRUCT mon) { // Get the string from the hsz string handle. // TODO: For some reason this does not work correctly. var psz = new StringBuilder(Ddeml.MAX_STRING_SIZE); int length = Ddeml.DdeQueryString(_Context.InstanceId, mon.hsz, psz, psz.Capacity, Ddeml.CP_WINANSI); string str = psz.ToString(); var action = DdemlStringActivityType.CleanUp; switch (mon.fsAction) { case Ddeml.MH_CLEANUP: action = DdemlStringActivityType.CleanUp; break; case Ddeml.MH_CREATE: action = DdemlStringActivityType.Create; break; case Ddeml.MH_DELETE: action = DdemlStringActivityType.Delete; break; case Ddeml.MH_KEEP: action = DdemlStringActivityType.Keep; break; } var args = new DdemlStringActivityEventArgs(str, action, mon.hTask); if (StringActivity != null) StringActivity(this, args); }
private void OnString(Ddeml.MONHSZSTRUCT mon) { // Get the string from the hsz string handle. // TODO: For some reason this does not work correctly. var psz = new StringBuilder(Ddeml.MAX_STRING_SIZE); var length = Ddeml.DdeQueryString(_Context.InstanceId, mon.hsz, psz, psz.Capacity, Ddeml.CP_WINANSI); var str = psz.ToString(); var action = mon.fsAction switch { Ddeml.MH_CLEANUP => DdemlStringActivityType.CleanUp, Ddeml.MH_CREATE => DdemlStringActivityType.Create, Ddeml.MH_DELETE => DdemlStringActivityType.Delete, Ddeml.MH_KEEP => DdemlStringActivityType.Keep, _ => DdemlStringActivityType.CleanUp }; var args = new DdemlStringActivityEventArgs(str, action, mon.hTask); StringActivity?.Invoke(this, args); }
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; }
internal bool ProcessCallback(DdemlTransaction transaction) { // This is here to alias the transaction object with a shorter variable name. var t = transaction; switch (t.uType) { case Ddeml.XTYP_ADVREQ: { // Get the topic name from the hsz1 string handle. var psz = new StringBuilder(Ddeml.MAX_STRING_SIZE); var length = Ddeml.DdeQueryString(_InstanceId, t.hsz1, psz, psz.Capacity, Ddeml.CP_WINANSI); var 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); var item = psz.ToString(); // Create the advise request cache key. var key = topic + "!" + item + ":" + t.uFmt; // Get the data being advised if the cache does not contain it already. if (!_AdviseRequestCache.ContainsKey(key)) { // Get the data from the subclass. var 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. var cached = _AdviseRequestCache[key]; // Get the number of remaining transactions of this type for the same topic name, item name, and format tuple. var remaining = t.dwData1.ToInt32(); // If this is the last transaction then free the data handle. if (remaining == 0) _AdviseRequestCache.Remove(key); // Create and return the data handle representing the data being advised. if (cached == null || cached.Length <= 0) return false; t.dwRet = Ddeml.DdeCreateDataHandle(_InstanceId, cached, cached.Length, 0, t.hsz2, t.uFmt, 0); return true; // This transaction could not be processed here. } case Ddeml.XTYP_ADVSTART: { // Get the item name from the hsz2 string handle. var psz = new StringBuilder(Ddeml.MAX_STRING_SIZE); var length = Ddeml.DdeQueryString(_InstanceId, t.hsz2, psz, psz.Capacity, Ddeml.CP_WINANSI); var item = psz.ToString(); // Get the Conversation from the conversation table. var 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. var psz = new StringBuilder(Ddeml.MAX_STRING_SIZE); var length = Ddeml.DdeQueryString(_InstanceId, t.hsz2, psz, psz.Capacity, Ddeml.CP_WINANSI); var item = psz.ToString(); // Get the Conversation from the conversation table. var 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. var psz = new StringBuilder(Ddeml.MAX_STRING_SIZE); var length = Ddeml.DdeQueryString(_InstanceId, t.hsz1, psz, psz.Capacity, Ddeml.CP_WINANSI); var 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. var psz = new StringBuilder(Ddeml.MAX_STRING_SIZE); var length = Ddeml.DdeQueryString(_InstanceId, t.hsz1, psz, psz.Capacity, Ddeml.CP_WINANSI); var 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. var 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. var length = Ddeml.DdeGetData(t.hData, null, 0, 0); var data = new byte[length]; length = Ddeml.DdeGetData(t.hData, data, data.Length, 0); var command = _Context.Encoding.GetString(data, 0, data.Length); if (command[^1] == '\0')
private IntPtr OnDdeCallback(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; }