C# Skype Bot Multi Threading - c#

So, I have a successful Skype bot that has about 800+ users and growing daily, I am trying to remake the bot for the current one is made very poorly and is quite generic. I'm trying to add a lot of things to it as in databases and multi threading. I have looked at some multi threading threads on here already to try to resolve my problem and I have one that works, i just get a COM exception every time i try to enter the thread itself. IF anyone could help that would be great. I'm new to C# and am learning as I'm going...
Code:
private void OnMessage(ChatMessage msg, TChatMessageStatus status)
{
if (msg.Body.StartsWith("!") && status == TChatMessageStatus.cmsReceived)
{
string message = msg.Body.Replace("!", "");
string[] cmd = message.Split(' ');
switch(cmd[0].ToLower())
{
case "help":
Thread chelp = new Thread(cHelp);
chelp.Start();
break;
default:
msg.Chat.SendMessage("Command not recognized! Check your usage or type \"!help\" for commands!");
break;
}
}
}
So this works fine, and it enters the case perfectly, then enters the thread to process the command.
private void cHelp()
{
msg.Chat.SendMessage("/me Here is a list of commands made by my Master!" +
"\n\"!help\" - Shows list of commands");
}
So, Once this is entered it breaks and highlights my whole command, saying "COMException was unhandled"
"Additional Information: Error HRESULT E_FAIL has been returned from a call to a COM component"
Screenshot:
As I said, I'm new to coding so any help is appreciated. Thanks!

Related

NET 6 COM: An outgoing call cannot be made since the application is dispatching an input-synchronous call

I have a Win11, NET 6.0, Windows App that calls Word through COM to run a Word macro stored inside of the Word instance. All the relevant code has been running for a year or so. I have been debugging for two days without success, reading up on the exception message that I am suddenly getting, trying random code changes, and so on.
My C# program gets the Word instance and tries to run the macro named "FH3" as shown in the code and log trace below. But the code never gets to run the macro because the code that tries to get the Word instance (WordAppGet) fails at runtime. Here are three lines from my log file that show the execution and exception error message.
MacroRun Running Word macro: 'FH3'
WordAppVarsGet GetActiveObject Word.Application failed.
Exception: An outgoing call cannot be made since the application is dispatching an input-synchronous call. (0x8001010D (RPC_E_CANTCALLOUT_ININPUTSYNCCALL))
The following test case code runs okay in Visual Studio.
[TestMethod()]
public void MacroRunTest() {
var me = MethodBase.GetCurrentMethod()?.Name;
MacroRunHelper("FH2", me);
}
// this code has been running fine for many months
public static void
MacroRunHelper(string macroName, string me) {
var msg1 = $"{me} Running Word macro: '{macroName}'";
LogMan.SendNormal(msg1);
var wapp = WordAppGet();
try {
wapp.Run(macroName);
}
catch (Exception ex) {
var msg = $"{me} {ex.Message} '{macroName}'";
LogMan.Send(LogType.Error, msg);
}
}
/// <summary>
/// Get and store a reference to the active Word application.
/// </summary>
public static Word.Application
WordAppGet() {
Word.Application wapp = null;
try {
// Marshal2.GetActiveObject is a copy of the Microsoft reference code
// because it was not included in the MS Interop library when the code was written.
// And GetActiveObject is still not included as of 2022-09-18.
//
// this call fails with the error message
wapp = Marshal2.GetActiveObject("Word.Application") as Application;
}
catch (Exception ex) {
var msg = $"{me} GetActiveObject Word.Application failed.";
LogMessage(PError, msg);
LogMessage(PError, ex.Message);
throw;
}
return wapp;
}
For what it's worth, the online doc about the error message talks a lot about windows controls and BeginInvoke, but this has nothing to do with any Windows controls as far as I can tell.
I have used this same code pattern to access Word, Excel, Outlook, PowerPoint, on NET Framework for a couple of years, and on NET 5 and 6 for more than a year.
It is a mystery to me why it stopped working for Word. It is a mystery to me why it continues to work in the Visual Studio debugger.
Does anyone know how I can fix it to run again? I wonder if any recent Win11 updates have had any changes that break this kind of code. Thank you.
The source of the problem was far away from the code shown above. I switched my top-level WindowsApp from receiving input commands using sockets to receiving using Windows messages. The WndProc branch called some helper code SYNCHRONOUSLY which called other code, and about 10 or 15 calls down the WordAppGet code was called.
Because WndProc calls were synchronous, the WndProc thread was not allowed to "call out" over COM because it might create a deadlock condition. Using Task.Run(...) in the WndProc message branch put the work on a separate thread that was allowed to call out over COM.
Receiving input commands via sockets does not involve the single-thread STA WndProc thread, so sockets worked for a year or more. I was trying to improve the speed of the code and thought Windows messages would be faster. But I wasted more time debugging the COM issue than sockets execution times would have used in 20 years. Bummer.
FWIW, I did not detect the problem until many weeks after I switched from sockets to messages because the COM use case was not tested after the switch.

Discord: how to catch direct message from user to bot?

I am creating own bot for Discrod server. So far I have managed to give it commands like "!roll" into the chat and bot catches it replies "you rolled 6" to the chat as well.
client.UsingCommands(input => { input.PrefixChar = '!' });
command.CreateCommand("roll").Do(async (e) => {
await channel.SendMessage(username + " rolls " + rng.Next(1, 7)) });
But I dislike the way people are typing commands into the chat because it might be disruptive at some point. I would like to create a possibility to call command by direct message from the user to the bot. You'd DM bot "roll" and it will write to the chat "andrew rolled 1".
But I have no idea how to do that or if it is even possible. Any ideas?
The current answers I found online were frustrating, this is how I did it (couldn't find any reference to the "Context" people kept saying, or the "IsPrivate"). Had to figure this stuff out just by inspecting the object themselves.
It appears the SocketMessage.Channel property changes from SocketTextChannel to SocketDMChannel depending on the source. Below is the method I made to determine if a message was a DM.
private bool IsPrivateMessage(SocketMessage msg) {
return (msg.Channel.GetType() == typeof(SocketDMChannel));
}
Hope this helps someone save the 5 hours this wasted me :)
One solution could be using Delegates/EventHandlers
var client = new DiscordClient();
client.MessageCreated += (s, e) =>
{
if (!e.Message.IsAuthor && e.Message.ToLower().Contains("roll")){
/*Code here*/
}
}
EventHandler<MessageEventArgs> handler = new EventHandler<MessageEventArgs>(HandleMessageCreated);
client.MessageCreated += handler;
Just make sure you place this delegate/EventHandler code below the Command Services setup, and the bot won't double-post when someone does !roll.
Also, you can use IsPrivate variable on channel Object to check if the message sent on the channel is a DM/PM channel or not.
In case you need the documentations for Discord.NET v0.9.6, here it is.
Also, you may want to consider using Discord.NET v1.0.0+ instead.

Issue with loaded Midi.Net DLL

Lately I'm having some issues in different applications that I have made. All of these applications use a Midi-controller to send midi-notes to a lighting desk. The issue is the same for all of these applications.
In runtime, when I'm working on the application, it sometimes occurs that my complete application freezes. I don't get any warningmessages, nor is the debugger popping up to tell me what's wrong. It always occurs when I want to play a midi-note. The only thing I can do at that point, is to reboot the entire machine, which is not that funny.
Because the application hangs and I don't get any debugging information, I'm certain it has to do with the DLL I use to send Midi-notes and that there's an issue there or in the way I have implemented the dll.
I've posted the code below and I would appreciate it, if someone could tell me what I'm doing wrong?
This is de code in the mainform initializing the Midi
MidiTools midi;
private void initMidi()
{
midi = new MidiTools();
midi.Enabled = true;
}
The initMidi() is called from inside the Form_Load-function.
The code to play a Midi-note is:
midi.playNote(22,0)
Below is the code inside the MidiTools-class file
using Midi;
namespace MidiTest
{
class MidiTools
{
public bool Enabled { get; set; }
OutputDevice outputDevice = OutputDevice.InstalledDevices[1];
Channel selectedChannel = Channel.Channel16;
int velocity = 127;
private void playNote(int noteNumber, int delay)
{
// CONVERT THE NOTE
Note selectedNote = (Note)noteNumber;
if (Enabled)
{
Thread.Sleep(delay);
Console.WriteLine(DateTime.Now.ToString("hh:mm:ss NOTE: ") + selectedNote.ToString());
outputDevice.Open();
outputDevice.SendNoteOn(selectedChannel, selectedNote, velocity);
outputDevice.Close();
}
}
}
}
The Midi-library itself was downloaded from this link:
https://midi-dot-net.googlecode.com/files/midi-dot-net_src_1.0.5.zip
In the past I've tried multiple ways of fixing this problem. I've tried inserting a bigger delay, I've tried cueing the messages in a list and processing them one by one to prevent a midinote from being asked to play wile another note is still being sent, but none of those helped.
In 98% of the cases it works, it's just occasionally that it freezes on me.
I'm using the M-Audio Midisport controller. (http://www.m-audio.com/products/view/midisport-4x4-anniversary-edition) but it has also happened on other controllers.
So any help is greatly appreciated.
Best regards,
Kenneth

System.UnauthorizedAccessException when trying to accept audio call in Lync 2013

I have a problem with my Lync client that I am designing. I am running Lync 2013 in UI Suppression mode and I am able to send/receive IM's just fine, and begin audio calls. But a problem occurs when I try to receive an audio conversation from someone else. I get a System.UnauthorizedAccessException when I try to call this line of code:
conv.Modalities[ModalityTypes.AudioVideo].BeginConnect(ModalityCallback, asyncState);
It runs perfectly fine otherwise, and the call goes through okay and I can hear and talk to the other side just fine, but my User Interface freezes and I can't control anything due to this error. Even when the other side hangs up, I have to kill the process in Task Manager.
Here is my InitiateAVStream method, based on the MSDN Join Lync conversation example:
public bool InitiateAVStream()
{
Console.WriteLine("InitiateAVStream");
if (conv.State == ConversationState.Terminated)
{
return false;
}
if (conv.Modalities[ModalityTypes.AudioVideo].CanInvoke(ModalityAction.Connect))
{
conv.Modalities[ModalityTypes.AudioVideo].ModalityStateChanged += _AVModality_ModalityStateChanged;
conv.Modalities[ModalityTypes.AudioVideo].ActionAvailabilityChanged += _AVModality_ActionAvailabilityChanged;
//Accept the notification. If Lync UI is enabled, incoming call notification is closed.
conv.Modalities[ModalityTypes.AudioVideo].Accept();
//Connect the AV modality and begin to send and received AV stream.
object[] asyncState = { conv.Modalities[ModalityTypes.AudioVideo], "CONNECT" };
try
{
conv.Modalities[ModalityTypes.AudioVideo].BeginConnect(ModalityCallback, asyncState);
}
catch (Exception ex)
{
Console.WriteLine(ex.StackTrace);
}
return true;
}
return false;
}
The output message:
A first chance exception of type 'System.UnauthorizedAccessException' occurred in Microsoft.Lync.Model.dll
at Microsoft.Office.Uc.ModalityClass.Connect(ModalityConnectOptions _options, Object _modalityCallback, Object _state)
at Microsoft.Lync.Model.Conversation.Modality.BeginConnect_private(ModalityConnectOptions options, AsyncCallback modalityCallback, Object state)
at Microsoft.Lync.Model.Conversation.Modality.BeginConnect(AsyncCallback modalityCallback, Object state)
at UIPrototype.MeetingForm.InitiateAVStream() in c:\Users\morrissi\Documents\Visual Studio 2012\Projects\UIPrototype\UIPrototype\MeetingForm.cs:line 758
Any input would be greatly appreciated. And it's strange to me that it only occurs when I try accepting an incoming audio call. Everything else works fine. I have not started work on video calls yet, but I will once I get audio working.
Thanks
Edit:
Replacing BeginConnect with BeginRetrieve still throws the same error and produces the same results. Still not sure what to do.
Where are you running your application from? I had a very similar stacktrace and moving the application into "C:\Users\MyUser" resolved the problem for me.
I was able to solve the problem. Apparently when you are connecting just an audio call, the only line you need is
conv.Modalities[ModalityTypes.AudioVideo].Accept();
You do not need to call BeginConnect to connect the audio. Removing BeginConnect prevents the error from being thrown and the audio connects just fine still. BeginConnect is used to connect video.
My problem with the form not loading completely and freezing is unrelated, it appears. That is being caused because I am trying to create a new form within ConversationManager_ConversationAdded. If I try creating a new form on a button click, it loads just fine and works, but it seems to be the event that is preventing it from working properly.
I'm not good enough at this to recognize when an error is being caused by Lync or C# yet.

Lidgren - InvalidOperationException was unhandled

Argh! I'm back, guys! I hate having to bother others with my issues, but I've been working on this for like 3 days now.
Using the Chat Application example, I molded it into my game. The client and server connect appropriately but... My client is having some trouble. :/
public static void appendText(RichTextBox box, string line)
{
if (box == null || box.IsDisposed)
return;
//try
//{
box.AppendText(line + Environment.NewLine);
ScrollRichTextBox(box);
//}
//catch
//{
// Program.debug.print("Something went wrong.");
//}
}
The AppendText line keeps throwing an exception (InvalidOperationException). I commented out the try-catch, hoping the compiler would give me more advice on what's wrong and maybe how to fix it, but I get no where with its help.
In the examples, I can run that code without getting this error. I don't know where I went wrong here.
Oh, AppendText is called by...
public static void GotMessage(object peer)
{
NetIncomingMessage im;
while ((im = s_client.ReadMessage()) != null)
{
// handle incoming message
switch (im.MessageType)
{
case NetIncomingMessageType.DebugMessage:
case NetIncomingMessageType.ErrorMessage:
case NetIncomingMessageType.WarningMessage:
case NetIncomingMessageType.VerboseDebugMessage:
string text = im.ReadString();
//TextControl.appendText(menuWindow.richTextBoxStatus, text);
Program.printStatus(text);
break;
case NetIncomingMessageType.StatusChanged:
NetConnectionStatus status = (NetConnectionStatus)im.ReadByte();
/*if (status == NetConnectionStatus.Connected)
s_form.EnableInput();
else
s_form.DisableInput();
*/
//if (status == NetConnectionStatus.Disconnected)
//s_form.button2.Text = "Connect";
string reason = im.ReadString();
Program.printStatus(status.ToString() + ": " + reason);
break;
case NetIncomingMessageType.Data:
// incoming packet from the server, handle data
int size = im.ReadInt32();
byte[] bData = im.ReadBytes(size);
string data = Encoding.Unicode.GetString(bData);
Program.debug.print(data);
Program.printToChat(data);
handleData(data);
break;
default:
Program.printStatus("Unhandled type: " + im.MessageType + " " + im.LengthBytes + " bytes");
break;
}
}
}
where printToChat or printStatus are found. Those methods contain the calls to AppendText.
I tried to post to the Lidgren Google Group when the error first popped up, but I haven't gotten a response back from them, so I'm hoping people here could have the information I seek. :)
I can provide more information and code if needed (as always, heh).
(I did Google how to make thread-safe calls to UI elements, but the code was just too confusing to comprehend. When I finally thought I implemented a solution, it just refused to work at all..)
Pfft, look at me, figuring things out.
I was able to successfully add delegate methods to my forms so that they can be access across threads. Or so I'm led to believe. The code now functions as intended.
I coooould add code, to show what I did. And I will if anyone needs help with this type of problem. I think I'm capable of explaining it, but MSDN works wonders.
As always, I just had to ask the question, and read comments to be led in the right direction.
I really need to stop asking questions I end up answering days later. :/
I'm sooo sorry. I feel really bad for taking up space and wasting time.
edit: I've also written a very clever way of circumventing needing to use delegates. However, it requires the use of a timer, or a loop that also repaints the windows form every now and then (I've used a timer).

Categories

Resources