I am coding a rcon message tool for a game server in C#. However I've run across a error:
"The name 'm' does not exist in the current context"
By now you're shouting at your screen NOOB! and yes I admit I am; I have little real coding experience.
I've played with MFC C++ and OpenGL and I'm a fairly respected cod modder "script is gsc loosely based on c++" so I hope I can learn quickly, basically I tried to access an instance of b. outside of the main loop but it gave me the error:
The name b does not exist in the current context
so I made a new messages function that started a new connection in a new instance. Then I tried the access that in another function stopmessages() but I still get the error.
Sorry for the newb question. I've googled long and hard about this and I just don't understand.
Here's my code - it uses Nini.dll for config file access and BattleNET.dll for access to rcon for the game -
#region
using System;
using System.Net;
using System.Text;
using BattleNET;
using Nini.Config;
#endregion
namespace BattleNET_client
{
internal class Program
{
private static void Main(string[] args)
{
bool isit_ok = true;
Console.OutputEncoding = Encoding.UTF8;
Console.Title = "rotceh_dnih's DayZ servermessages";
BattlEyeLoginCredentials loginCredentials = GetLoginCredentials();
Console.Title += string.Format(" - {0}:{1}", loginCredentials.Host, loginCredentials.Port);
IBattleNET b = new BattlEyeClient(loginCredentials);
b.MessageReceivedEvent += DumpMessage;
b.DisconnectEvent += Disconnected;
b.ReconnectOnPacketLoss(true);
b.Connect();
while (true)
{
startmessages();
string cmd = Console.ReadLine();
if (cmd == "exit" || cmd == "logout" || cmd == "quit")
{
Environment.Exit(0);
}
if (cmd == "restart")
{
stopmessages();
}
if (cmd == "startstuff")
{
startmessages();
}
if (b.IsConnected())
{
if (isit_ok)
{
}
isit_ok = false;
b.SendCommandPacket(cmd);
}
else
{
Console.WriteLine("Not connected!");
}
}
}
private static BattlEyeLoginCredentials GetLoginCredentials()
{
IConfigSource source = new IniConfigSource("server/admindets.ini");
string serverip = source.Configs["rconlogin"].Get("ip");
int serverport = source.Configs["rconlogin"].GetInt("port");
string password = source.Configs["rconlogin"].Get("rconpwd");
var loginCredentials = new BattlEyeLoginCredentials
{
Host = serverip,
Port = serverport,
Password = password,
};
return loginCredentials;
}
public static void startmessages()
{
BattlEyeLoginCredentials loginCredentials = GetLoginCredentials();
IBattleNET m = new BattlEyeClient(loginCredentials);
m.MessageReceivedEvent += DumpMessage;
m.DisconnectEvent += Disconnected;
m.ReconnectOnPacketLoss(true);
m.Connect();
IConfigSource messagesource = new IniConfigSource("messages/servermessages.ini");
int messagewait = messagesource.Configs["timesettings"].GetInt("delay");
string[] messages = messagesource.Configs["rconmessages"].Get("messages1").Split('|');
// for (;;)
// {
foreach (string message in messages)
{
Console.WriteLine(message);
m.SendCommandPacket(EBattlEyeCommand.Say,message);
System.Threading.Thread.Sleep(messagewait * 60 * 1000);
}
// }
}
public static void stopmessages()
{
m.Disconnect();
}
private static void Disconnected(BattlEyeDisconnectEventArgs args)
{
Console.WriteLine(args.Message);
}
private static void DumpMessage(BattlEyeMessageEventArgs args)
{
Console.WriteLine(args.Message);
}
}
}
You need to put the declaration of m into the class scope:
internal class Program
{
// declare m as field at class level
private static IBattleNET m;
private static void Main(string[] args)
{
....
}
public static void startmessages()
{
BattlEyeLoginCredentials loginCredentials = GetLoginCredentials();
// JUST SET THE VALUE HERE
m = new BattlEyeClient(loginCredentials);
m.MessageReceivedEvent += DumpMessage;
m.DisconnectEvent += Disconnected;
m.ReconnectOnPacketLoss(true);
m.Connect();
IConfigSource messagesource = new IniConfigSource("messages/servermessages.ini");
int messagewait = messagesource.Configs["timesettings"].GetInt("delay");
string[] messages = messagesource.Configs["rconmessages"].Get("messages1").Split('|');
// for (;;)
// {
foreach (string message in messages)
{
Console.WriteLine(message);
m.SendCommandPacket(EBattlEyeCommand.Say,message);
System.Threading.Thread.Sleep(messagewait * 60 * 1000);
}
// }
}
The stopmessages() method won't be able to access m as the variable m only exists within the startmessages() method
Move the declaration of IBattleNET m
To outside the main function and make it static:
static IBattleNet b;
Then in your main you just do m = new BattlEyeClient(loginCredentials);
m is declared in scope of static method startmessages but then you are trying to use it in stopmessages, where it is not in scope. You should move the variable to class scope, and define it as static (since your methods are static).
Hopefully your client app is single-threaded, otherwise you will need to consider thread safety issues as well.
what you could do is after you declared your class, so bevore the static void main
declare your m value
internal class Program
{
IBattleNET m;
then in the startMessages method add
m = new BattlEyeClient(loginCredentials);
this will make the m value available to all the methods inside your class
I'm assuming m should refer to this:
IBattleNET m = new BattlEyeClient(loginCredentials);
in the method startmessages(). What you need to do is declare IBattleNET m outside the method body:
static IBattleNET m;
public static void startmessages()
{
//etc
Related
I wrote an IMAP client app, it works fine, but i need to use "Console.Readkey()" in the Main method, without this command program not work, the main problems is that I need to use them in a DLL and not a console application, i tried various things but couldn't solve the issue, please help me in this case.
namespace MAIL
{
class Program
{
// VARIABLES --------------------------------------------------------------------------------------------------
private static System.Timers.Timer aTimer;
public static string EXT_IMAP_SERVER = "imap.zoho.com";
public static int EXT_IMAP_PORT = 993;
public static string EXT_USERNAME = "***#zohomail.com";
public static string EXT_PASSWORD = "***";
public static int EXT_TIMER = 5000;
public static string DATA;
public static string EXT_IMAP_SERVER_BLOCK(string P1)
{
EXT_IMAP_SERVER = P1;
return P1;
}
public static int EXT_IMAP_PORT_BLOCK(int P1)
{
EXT_IMAP_PORT = P1;
return P1;
}
public static string EXT_USERNAME_BLOCK(string P1)
{
EXT_USERNAME = P1;
return P1;
}
public static string EXT_PASSWORD_BLOCK(string P1)
{
EXT_PASSWORD = P1;
return P1;
}
public static int EXT_TIMER_BLOCK(int P1)
{
EXT_TIMER = P1;
return P1;
}
// MAIN BLOCK --------------------------------------------------------------------------------------------------
public static void Main()
{
SetTimer();
Console.ReadKey();
}
// TIMER METHOD --------------------------------------------------------------------------------------------------
public static void SetTimer()
{
// Create a timer with a two second interval.
aTimer = new System.Timers.Timer(EXT_TIMER);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += OnTimedEvent;
aTimer.AutoReset = true;
aTimer.Enabled = true;
}
public static void OnTimedEvent(object sender, ElapsedEventArgs e)
{
using (var client = new ImapClient())
{
client.Connect(EXT_IMAP_SERVER, EXT_IMAP_PORT, true);
client.Authenticate(EXT_USERNAME, EXT_PASSWORD);
// The Inbox folder is always available on all IMAP servers...
var inbox = client.Inbox;
inbox.Open(FolderAccess.ReadOnly);
//Console.WriteLine("Total messages: {0}", inbox.Count);
//Console.WriteLine("Recent messages: {0}", inbox.Recent);
for (int i = 0; i < inbox.Count; i++)
{
var message = inbox.GetMessage(i);
DATA = message.Subject;
//Console.WriteLine("Subject: {0}", message.Subject);
Console.WriteLine(DATA);
}
client.Disconnect(true);
}
}
}
}
Replace timer with loop and delay:
public static void Main()
{
while(true)
{
DoAction();
Task.Wait(5000);
}
}
public static void DoAction()
{
using (var client = new ImapClient())
{
client.Connect(EXT_IMAP_SERVER, EXT_IMAP_PORT, true);
client.Authenticate(EXT_USERNAME, EXT_PASSWORD);
// The Inbox folder is always available on all IMAP servers...
var inbox = client.Inbox;
inbox.Open(FolderAccess.ReadOnly);
//Console.WriteLine("Total messages: {0}", inbox.Count);
//Console.WriteLine("Recent messages: {0}", inbox.Recent);
for (int i = 0; i < inbox.Count; i++)
{
var message = inbox.GetMessage(i);
DATA = message.Subject;
//Console.WriteLine("Subject: {0}", message.Subject);
Console.WriteLine(DATA);
}
client.Disconnect(true);
}
}
There are two common issues here.
For the first issue, the program actually does work, but it works so quickly that without ReadKey() you don't see it work. In this case better logging can help give you confidence that things are running as you expect.
I included that for completeness, but I don't think it's your situation.
The other issue has to do process and thread life cycles. In a Console app, when the Main() method/thread completes, the process ends, including any additional threads or events the process created. You fix this not by adding Console.ReadKey(), but rather by adding code in Main() to monitor and check on the status of the additional objects.
That is your issue. You set the timer, including the event, but there's no other work and so the program just finishes immediately.
There are things you can do to fix this, like adding a loop at the end of Main with a Sleep() call inside, but, as a dll, this isn't your code's responsibility. It's up to the code that calls into your dll to make sure the process doesn't just end. In other words, you don't really need to change anything here.
I have this code
class MainClass
{
public static void Main(string[] args)
{
MiddleMethod();
}
public static void MiddleMethod() {
try
{
int b = 0;
int a = 10 / b;
} catch (Exception e)
{
Console.WriteLine(GetAllFootprints(e));
}
}
public static string GetAllFootprints(Exception x)
{
var st = new StackTrace(x, false);
var frames = st.GetFrames();
var traceString = "";
foreach (var frame in frames)
{
traceString += frame.GetMethod().DeclaringType.FullName + "#" + frame.GetMethod().Name;
traceString += "\n";
}
return traceString;
}
}
When i run this code i only get the last method where exception happens. like this
TestException2.MainClass#MiddleMethod
But i want to have caller methods as well in this example Main method. I want a way to print out all the caller methods from beginning to where exception happens. How can i fix this?
i have an application which turns your webcam on and off. It turns it on, on a new thread and im trying to make a button work from the main code to turn it off buts cross threading doesnt work and as their is no form, i cant invoke. here is the code:
public class Program
{
public static FilterInfoCollection CaptureDevicesList;
public static VideoSourcePlayer videoSourcePlayer = new VideoSourcePlayer();
public static VideoCaptureDevice videoSource;
public static System.Timers.Timer TimerClose = new System.Timers.Timer();
[STAThread]
static void Main()
{
TimerClose.Elapsed += (o, e) => TimerClose_Tick();
TimerClose.Interval = 10000;
TimerClose.Start();
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
CaptureDevicesList = new FilterInfoCollection(FilterCategory.VideoInputDevice);
Class1.oncam();
}).Start();
Application.Run();
}
private static void TimerClose_Tick()
{
Class1.CloseCurrentVideoSource(); // <--- function cant run
}
}
So what im trying to do is get the close function to work which is trying to turn the webcam off which is running on a different thread. Here is class1:
class Class1
{
public static void oncam()
{
Program.videoSource = new VideoCaptureDevice(Program.CaptureDevicesList[0].MonikerString);
OpenVideoSource(Program.videoSource);
}
public static void OpenVideoSource(IVideoSource source)
{
CloseCurrentVideoSource();
Program.videoSourcePlayer.VideoSource = source;
Program.videoSourcePlayer.Start();
}
public static void CloseCurrentVideoSource()
{
if (Program.videoSourcePlayer.VideoSource != null)
{
Program.videoSourcePlayer.SignalToStop();
for (int i = 0; i < 30; i++)
{
if (!Program.videoSourcePlayer.IsRunning)
break;
System.Threading.Thread.Sleep(100);
}
if (Program.videoSourcePlayer.IsRunning)
{
Program.videoSourcePlayer.Stop();
}
Program.videoSourcePlayer.VideoSource = null;
}
}
}
Any help is appriciated
VideoSourcePlayer inherits from System.Windows.Forms.Control and thus requires synchronization for cross-thread access.
Call Invoke on this control when accessing it from another thread.
I am not sure why when I don't use "static", the function has error:
"An object reference is required for non-static field,method, or property.Dos2Unix(string)"
The code looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var f = #"\D:\temp\test.xls";
Dos2Unix(f);
}
private void Dos2Unix(string fileName)
{
const byte CR = 0x0D;
const byte LF = 0x0A;
byte[] data = File.ReadAllBytes(fileName);
using (FileStream fileStream = File.OpenWrite(fileName))
{
BinaryWriter bw = new BinaryWriter(fileStream);
int position = 0;
int index = 0;
do
{
index = Array.IndexOf<byte>(data, CR, position);
if ((index >= 0) && (data[index + 1] == LF))
{
// Write before the CR
bw.Write(data, position, index - position);
// from LF
position = index + 1;
}
}
while (index > 0);
bw.Write(data, position, data.Length - position);
fileStream.SetLength(fileStream.Position);
}
}
}
}
When I use the keyword "static", there is no error.
I am not sure what error I am making. Need some help on this.
When calling non-static method this parameter implictly passed into the method
private void Dos2Unix(string fileName) {
...
var sample = this.GetType(); // <- possible call
...
}
Static method can't provide such parameter (this) and so you have an error.
In your case you don't want Program class instance within Dos2Unix method, so make it static:
class Program
{
static void Main(string[] args)
{
var f = #"\D:\temp\test.xls";
Dos2Unix(f);
}
// Please, note "static"
private static void Dos2Unix(string fileName)
{
...
}
}
Technically, you dont't want Program class instances at all, and so declare the entire class as static:
// class is static
static class Program
{
static void Main(string[] args)
{
var f = #"\D:\temp\test.xls";
Dos2Unix(f);
}
// all methods are static
private static void Dos2Unix(string fileName)
{
...
}
}
You can not call non static method from static method directly, as Main method of Program class is static you can only call static method of program class from this method.
To call a non static method from Main method you can make object of program class and call non static method on this object.
static void Main(string[] args)
{
var f = #"\D:\temp\test.xls";
Program p = new Program();
p.Dos2Unix(f);
}
There is a reason why static method can not call non-static methods as the static method are not tied to instance of that class on the other hand the non-static method is tied to instance (can access the non-static data members). Think a static method calling a non-static method that is accessing instance members that actually does not exist for class, because the static method is called upon class not instance. You can read further in this post.
If you want to call a non-static method from the static method Main, you'll have to create a new object of type Program:
new Program().Dos2Unix(f);
You need to make an instance of your class.
This should work:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Program p = new Program();
var f = #"\D:\temp\test.xls";
p.Dos2Unix(f);
}
private void Dos2Unix(string fileName)
{
const byte CR = 0x0D;
const byte LF = 0x0A;
byte[] data = File.ReadAllBytes(fileName);
using (FileStream fileStream = File.OpenWrite(fileName))
{
BinaryWriter bw = new BinaryWriter(fileStream);
int position = 0;
int index = 0;
do
{
index = Array.IndexOf<byte>(data, CR, position);
if ((index >= 0) && (data[index + 1] == LF))
{
// Write before the CR
bw.Write(data, position, index - position);
// from LF
position = index + 1;
}
}
while (index > 0);
bw.Write(data, position, data.Length - position);
fileStream.SetLength(fileStream.Position);
}
}
}
}
So basically you only need to add:
Program p = new Program();
and call your method like:
p.Dos2Unix("....");
That's because you can't access a non-static method inside a static method (you can't also use this by the way).
I am working on converting a console application into a windowed format and as someone who knows little about it but has had experience with a similar application already in window format in the past I figured it wouldn't be too hard.
So I created a form and added a textbox to it just to get the logging information to start with.
This console app used to run in a single thread, I have since added a second thread to allow the form to run side by side with the console for testing. (it runs fine in a single thread strangely now too).
This is the code I am using to write text to the form except that I am not getting ANYTHING at all on the form.
static Form1 f = new Form1();
delegate void SetTextCallback(string s);
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (f.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
f.textBox1.Invoke(d, new object[] { text });
}
else
{
f.textBox1.AppendText(text);
}
}
I can confirm that there is text entering the "text" variable but it is not getting to the form.
Any help would be appreciated.
This is the full file:
using System;
using System.Windows.Forms;
using Chraft.Properties;
using System.IO;
using Chraft.Plugins.Events.Args;
using Chraft.Plugins.Events;
namespace Chraft
{
public class Logger
{
private StreamWriter WriteLog;
private Server Server;
internal Logger(Server server, string file)
{
Server = server;
try
{
WriteLog = new StreamWriter(file, true);
WriteLog.AutoFlush = true;
}
catch
{
WriteLog = null;
}
}
~Logger()
{
try
{
WriteLog.Close();
}
catch
{
}
}
public void Log(LogLevel level, string format, params object[] arguments)
{
Log(level, string.Format(format, arguments));
}
public void Log(LogLevel level, string message)
{
//Event
LoggerEventArgs e = new LoggerEventArgs(this, level, message);
Server.PluginManager.CallEvent(Event.LOGGER_LOG, e);
if (e.EventCanceled) return;
level = e.LogLevel;
message = e.LogMessage;
//End Event
LogToConsole(level, message);
LogToForm(level, message);
LogToFile(level, message);
}
private void LogToConsole(LogLevel level, string message)
{
if ((int)level >= Settings.Default.LogConsoleLevel)
{
Console.WriteLine(Settings.Default.LogConsoleFormat, DateTime.Now, level.ToString().ToUpper(), message);
}
}
static Form1 f = new Form1();
delegate void SetTextCallback(string s);
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (f.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
f.textBox1.Invoke(d, new object[] { text });
}
else
{
f.textBox1.AppendText(text);
}
}
private void LogToForm(LogLevel level, string message)
{
if ((int)level >= Settings.Default.LogConsoleLevel)
{
SetText(DateTime.Now + level.ToString().ToUpper() + message);
}
}
private void LogToFile(LogLevel level, string message)
{
if ((int)level >= Settings.Default.LogFileLevel && WriteLog != null)
WriteLog.WriteLine(Settings.Default.LogFileFormat, DateTime.Now, level.ToString().ToUpper(), message);
}
public void Log(Exception ex)
{
//Event
LoggerEventArgs e = new LoggerEventArgs(this, LogLevel.Debug, ex.ToString(), ex);
Server.PluginManager.CallEvent(Event.LOGGER_LOG, e);
if (e.EventCanceled) return;
//End Event
Log(LogLevel.Debug, ex.ToString());
}
public enum LogLevel : int
{
Trivial = -1,
Debug = 0,
Info = 1,
Warning = 2,
Caution = 3,
Notice = 4,
Error = 5,
Fatal = 6
}
}
}
The problem is that you are creating two Form objects. One that is created in your Program.cs file:
Application.Run(new Form1());
And the one you created in your logger class
Form f = new Form1();
The one passed to Application.Run is the one that the user is interacting with. It has become visible and responds to user interaction because of the Application.Run call.
The one you created on your logger class just sits there in memory. Its TextBox is happily adding the text you ask it to, but that one isn't visible anywhere.
There are many ways to handle this situation. You could gain access to the correct Form object through Application.OpenForms, but a more appropriate way to handle it would be to add an event on the logger that the form can subscribe to and it can handle updating the TextBox in response to the event.
Updated
class LoggerLogEventArgs : EventArgs
{
public LoggerLogEventArgs(string message)
{
this.message = message;
}
private string message;
public string Message { get { return message; } }
}
class Logger
{
public event EventHandler<LoggerLogEventArgs> Logged;
protected virtual void OnLogged(LoggerLogEventArgs e)
{
EventHandler<LoggerLogEventArgs> handler = Logged;
if (handler != null)
handler(this, e);
}
// I would change this method name to LogToEvent
private void LogToForm(LogLevel level, string message)
{
if ((int)level >= Settings.Default.LogConsoleLevel)
{
OnLogged(new LoggerLogEventArgs(message));
}
}
}
class Form1 : Form
{
// Subscribe to the logger only when we are ready to display text
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
GetLog().Logged += new EventHandler<LoggerLogEventArgs>(logger_Logged);
}
// Unsubscribe from the logger before we are no longer ready to display text
protected override void OnHandleDestroyed(EventArgs e)
{
GetLog().Logged -= new EventHandler<LoggerLogEventArgs>(logger_Logged);
base.OnHandleDestroyed(e);
}
private void logger_Logged(object sender, LoggerLogEventArgs e)
{
if (InvokeRequired)
BeginInvoke(new EventHandler<LoggerLogEventArgs>(logger_Logged), e);
else
textBox1.AppendText(e.Message);
}
}
hello i try this it works ( I make a console application and I add a windows form)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Permissions;
using System.Windows.Forms;
namespace ConsoleApplication6
{
class Program
{
delegate void SetTextCallback(string s);
static Form1 f;
static void Main(string[] args)
{
f = new Form1();
f.Show();
SetText("test");
Console.ReadLine();
}
private static void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (f.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
f.textBox1.Invoke(d, new object[] { text });
}
else
{
f.textBox1.AppendText(text);
}
}
}
}