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).
Related
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.
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!
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
I am writing a program that does one thing, it finds out the current link speed of the wifi connection and reports it to the user in real time. the problem I am having is that it does not seem to be able to find out the current link speed, only the max link speed of the device (300 Mbps). the reason I am writing this is that I have a problem where, periodically the link speed will drop drastically (down to 1-2 Mbps) and I want to be able to see when that happens. with this code it will simply give me the maximum speed that the adapter supports, not the current link speed of the connection.
private void update(object state)
{
System.Net.NetworkInformation.NetworkInterface[] nics = null;
nics = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();
long speed = 0;
string adapter = "";
foreach (System.Net.NetworkInformation.NetworkInterface net in nics)
{
if (net.Name.Contains("Wireless") || net.Name.Contains("WiFi") || net.Name.Contains("802.11") || net.Name.Contains("Wi-Fi"))
{
speed = net.Speed;
adapter = net.Name;
break;
}
}
string temp;
if (speed == 0)
{
temp = "There is currently no Wi-Fi connection";
}
else
{
temp = "Current Wi-Fi Speed: " + (speed / 1000000) + "Mbps on " + adapter;
}
if (label1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(update);
label1.Invoke(d, new object[] { temp });
}
else
{
label1.Text = temp;
}
}
this run by calling
System.Threading.Timer ticker = new System.Threading.Timer(update, label1, 0, 1000);
in the main method.
Considering that it literally took me the whole entire day to find what the solution to this was, I figured I'd at least show StackOverflow for future reference what I came across and what did and did not work for this question.
tl;dr: Scroll to the The Code section
What I found
Good ol' control panel
If you are looking for the really easy way to do this you can simply go and open Contol Panel. Depending on what version of Windows you are on (in my case I'm on Windows 8), the path to the page is Control Panel >> Network and Internet >> Network and Sharing Center and then you can click on the link next to "Connections: " which will give you a window that looks like what is below.
The current link speed is highlighted in red which in my case is 36.0 Mbps. Though, of course, this might not satisfy your original question if you were intending to integrate some code with the actual value.
WMI
With a mix of Googling and whatnot, I thought I might have found something in Windows Management Instrumentation.
Long story short, AFAIK, WMI does not have what we're looking for.
WMI, in short, is a giant object database (that
can also be queried through SQL) that allows you to query information about a
Windows machine such as process, disks, etc. In WMI, everything is
represented by a class with a series of instances each with a set of
properties.
Anyhow, WMI Explorer allows you to view all of this on your machine.
I (supposedly) found two classes on MSDN that might have the info on link speed but from WMI Explorer, there was nothing useful.
The first class, MSFT_NetAdapter, did not even show up in WMI Explorer on my machine.
The second class, Win32_NetworkAdapter, showed up in WMI Explorer, but the Speed property was still incorrect. The same network adapter was showing a value of 168000000 or 168 Mbps which is not right. Though I find this strange because there was already a MaxSpeed but it was blank.
Scratch WMI off the list.
Win32 P/Invoke
Yes, of course, the solution to everything is always calling unmanaged Win32 APIs using P/Invoke magic.
This is the route used to solve the problem.
Luckily, the IP_ADAPTER_ADDRESSES structure solves the problem. If you look at the MSDN page, it's a fairly large structure but what is important here is TransmitLinkSpeed which actually works.
Calling the GetAdaptersAddresses() function will return the actual structure.
Now, the actual C# P/Invoke code. Luckily, pinvoke.net already had interop for this function which I've added. This is all that was necessary.
The Code
Finally, here is your code patched up with the new P/Invoke black magic. I've made it work as a console application for demo purposes:
Using Statements:
using System;
using System.Threading;
Code:
class Program
{
private static void Main(string[] args)
{
Timer ticker = new Timer(Update, null, 0, 1000);
// Keep the main thread from dying
while (true)
{
Thread.Sleep(1000);
}
}
private static void Update(object state)
{
ulong speed = 0;
string adapter = "";
string[] nameSearches = { "Wireless", "WiFi", "802.11", "Wi-Fi" };
// The enum value of `AF_INET` will select only IPv4 adapters.
// You can change this to `AF_INET6` for IPv6 likewise
// And `AF_UNSPEC` for either one
foreach (IPIntertop.IP_ADAPTER_ADDRESSES net in IPIntertop.GetIPAdapters(IPIntertop.FAMILY.AF_INET))
{
bool containsName = false;
foreach (string name in nameSearches)
{
if (net.FriendlyName.Contains(name))
{
containsName = true;
}
}
if (!containsName) continue;
speed = net.TrasmitLinkSpeed;
adapter = net.FriendlyName;
break;
}
string temp;
if (speed == 0)
{
temp = "There is currently no Wi-Fi connection";
}
else
{
temp = string.Format("Current Wi-Fi Speed: {0} Mbps on {1}", (speed / 1000000.0), adapter);
}
Console.WriteLine(temp);
}
}
You are then going to be looking for the actual IPIntertop class that I updated. Since it's pretty big you can find it updated at pinvoke.net or on this PasteBin in case something goes down.
Bottom Line
Windows has a lot of APIs which are somewhat broken (WMI), can have a few "leaky abstractions" (.Net), or can be a pain to work with (Win32).
Sigh, that is a lot and I hope it helps.
I come accross the same issue, and need to get windows wifi link speed which is current negotiated.
and thanks to #Jaxrtech's WMI approach, that really works.
the correct class is CIM_NetworkAdapter(i'm using windows7), and query the speed column to get the current speed.
while wifi current negotiated speed is changing, this speed is changing too. i tested it, this matched ok.
select Description , DeviceID, Speed from CIM_NetworkAdapter
get:
D-Link DWA-140 RangeBooster N USB Adapter 17 285000000
Since no-one here mentioned it yet: why not use https://learn.microsoft.com/en-us/dotnet/api/system.net.networkinformation.networkinterface.speed?view=net-5.0#System_Net_NetworkInformation_NetworkInterface_Speed
This is, if the table on this site is correct included since .NET Framework 2.0 and seem to included in all other versions of .net including .net core.
I'm guessing this doesn't work because of the StreamReader being non thread safe, (don't know howto fix that, google is no help)
Anyway I've been trying to figure exactly whats wrong with this code, it works 80% of the time, other times it fails to parse incoming packets and will just drop them.
This is a void for a http-like tcp server im writing. it works exactly like an http packet, but the "CONTENT-LENGTH" header tells it the length of the packets data (payload). This is where the problem is happening. Can anyone suggest to me howto improve this and fix this? because I'm completely lost.
void InternalStart()
{
bool continueWhile = true;
while (continueWhile)
{
if (SR.EndOfStream)
{
continueWhile = false;
break;
}
if (par_ReadStatus != ReadStatusEnum.WaitingForPayload)
{
int charCode = SR.Peek();
if (charCode == -1)
{
continueWhile = false;
break;
}
string outputLine = "";
outputLine = SR.ReadLine();
ReadLine(outputLine);
}
else if (par_ReadStatus == ReadStatusEnum.WaitingForPayload)
{
int length = int.Parse(par_ParsingPacket.Attributes["CONTENT-LENGTH"]);
char[] array = new char[length];
for (int i = 0; i < length; i++)
{
array.SetValue(Convert.ToChar(SR.Read()), i);
}
string payload = new string(array);
ReadLine(payload);
}
}
if (ReadEnd != null)
{
ReadEnd();
}
}
StreamReader being non thread safe, (don't know howto fix that, google is no help)
Simple. Beginner programmer level: Do not read the StreamReader from more than one thread. A design trying to do so is a failure to understand what a stream is and how efficient multi thread programming works.
There is no need to have multiple threads hit a single stream reader at all. You have to isolate threads before and assin a stream reader exclusively to a specific thread for the time of handling the data. If you want to get professional and fast you work like IIS and suck data out in infrastructure threads that then feed of work packets into a worker queue multiple threads work off.
And dependingo n performance requriements you may want to work off sockets and use the async socket mechanisms to make sure you are not wasting 1000 threads for 1000 operaions in progress at a great cost without any benefit.
Anyway i've been trying to figure exactly whats wrong with this code,
Ah - nice try. Sadly you neither tell us what problem you really have nor does your code show anything using threads, so at the end your question and the code fail to make any sense in combination.