• Welcome to Valhalla Legends Archive.
 

C# Events...

Started by shout, July 30, 2004, 12:24 PM

Previous topic - Next topic

shout

I am trying to create an event that is triggerd by reciving a packet but it does not work.

      #region Recive Packet Event Group

      protected virtual void OnRecivePacket(BnetPacketArgs e)
      {
         if (BnetSocket.Available != 0)
         {
            RecivePacket(this, e);
         }
      }

      public delegate void BnetPacketHandler(object sender, BnetPacketArgs e);

      public event BnetPacketHandler RecivePacket;

      private void bnetSocket_RecivePacket(object sender, BnetPacketArgs e)
      {
         PS.AddPacket(e.inBuffer);
      }
      #endregion

And this is in the constructor:
this.RecivePacket += new BnetPacketHandler(bnetSocket_RecivePacket);

Could someone tell me what I am doing wrong?

Banana fanna fo fanna

What's the error?

Try moving the delegate into the namespace and not the class

K

#2
youre code as posted, should work.

one minor suggestion, though.


if (ReceivePacket != null)
    ReceivePacket(this, e);

Maddox

Quote from: K on July 30, 2004, 04:12 PM
youre code as posted, should work.

one minor suggestion, though.


if (ReceivePacket != null)
    ReceivePacket(this, e);


That's more style than anything. Some people like all IF statements to have brackets to keep consistency.
asdf.

K

#4
My suggestion was not related to the style of his if statements.  If no delegates are registered to ReceivePacket and you try to call it, it will crash with a System.NullReferenceException.  That was my suggestion.

MyndFyre

Quote from: K on July 30, 2004, 05:28 PM
My suggestion was not related to the style of his if statements.  If no delegates are registered to ReceivePacket and you try to call it, it will crash with a System.NullReferenceException.  That was my suggestion.

That is correct.  I believe that this method is how the Microsoft best practices describe it, too.

Also, while try/catch handling is sometimes costly, if you're going to have an unknown set of untested methods hooking into events, you might want to isolate each call.  My API uses a model like this:


public delegate void PacketEventHandler(byte ID, byte[] Packet);

internal event PacketEventHandler PacketReceived;

internal void OnPacketReceived(byte ID, byte[] Packet)
{
 if (PacketReceived != null)
 {
    Delegate[] dels       = PacketReceived.GetInvocationList();
    object[] parms        = new object[] { ID, Packet };
    for (int i = 0; i < dels.Length; i++)
    {
       try
       {
         dels.DynamicInvoke(parms);
       }
       catch (Exception ex)
       {
          ErrorLog.WriteException(this, ex);  // WriteException associates an exception with a specific connection manager instance.
          ErrorLog.WriteDetails(this, ID, Packet);  // WriteDetails adds parameter information to a logged exception.
       }
    }
 }
}


That prevents a faulty handler from keeping the other handlers on the invocation list.from being fired.  Remember that an exception in the first called method will cause any subsequent methods from being called unless it is handled appropriately.  :)
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

shout

#6
I feel dumb for a couple of reasons.
1: I have managed to spell "receive" wrong every time I typed it in my code.
2: I hade the socket set to blocking.
3: I forgot to send the protocol byte.

Please kick me in the head until my noobness spills out.

K

#7
But the code you posted was correct!  ;)

Edit: Besides, I edited every single one of my posts above because I kept typing "recieve", clicking post, and then going "except after c!"

shout

I just found out I can have web pages open in VS.Net... that makes me alot happier. Please dont kick my head now.

shout

#9
Alright. The event stuff above is basically the same except the delegate is not inside the class. When I packet log, the bot sends the two packets, but the event does not work. But this works:


      public void Sendp50()
      {
         BnetPacket p50 = new BnetPacket(0x50);
         p50.InsertDWORD(0);
         p50.InsertNonNTString("IX86");
         p50.InsertNonNTString("SEXP");
//         p50.InsertDWORD(0xC9);
//         p50.InsertNonNTString("enUS");
//         p50.InsertDWORD(180);
//         p50.InsertDWORD(0);
//         p50.InsertDWORD(0);
         byte[] bytethis = new byte[] {0xC9, 0x00, 0x00, 0x00, 0x53, 0x55, 0x6E, 0x65, 0xAC, 0x97, 0x5B, 0x48, 0x2C, 0x01, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00};
         p50.InsertBYTEArray(bytethis);
         p50.InsertNTString("USA");
         p50.InsertNTString("United States");
         socket.Send(p50.Data);
         System.Threading.Thread.Sleep(System.TimeSpan.FromMilliseconds(20000));
         byte[] b = new byte[socket.BnetSocket.Available];
         socket.BnetSocket.Receive(b);
      }


Any less than 20000 milliseconds it does not receive the packet.

I know the byte thing is bad but at this point I don't give a flying fuck. But later I plan on fixing it.

Banana fanna fo fanna

* $t0rm thinks your socket should be in blocking mode

MyndFyre

#11
Quote from: shout on August 03, 2004, 02:37 AM
Alright. The event stuff above is basically the same except the delegate is not inside the class. When I packet log, the bot sends the two packets, but the event does not work. But this works:


      public void Sendp50()
      {
         BnetPacket p50 = new BnetPacket(0x50);
         p50.InsertDWORD(0);
         p50.InsertNonNTString("IX86");
         p50.InsertNonNTString("SEXP");
//         p50.InsertDWORD(0xC9);
//         p50.InsertNonNTString("enUS");
//         p50.InsertDWORD(180);
//         p50.InsertDWORD(0);
//         p50.InsertDWORD(0);
         byte[] bytethis = new byte[] {0xC9, 0x00, 0x00, 0x00, 0x53, 0x55, 0x6E, 0x65, 0xAC, 0x97, 0x5B, 0x48, 0x2C, 0x01, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00};
         p50.InsertBYTEArray(bytethis);
         p50.InsertNTString("USA");
         p50.InsertNTString("United States");
         socket.Send(p50.Data);
         System.Threading.Thread.Sleep(System.TimeSpan.FromMilliseconds(20000));
         byte[] b = new byte[socket.BnetSocket.Available];
         socket.BnetSocket.Receive(b);
      }


Any less than 20000 milliseconds it does not receive the packet.

I know the byte thing is bad but at this point I don't give a flying fuck. But later I plan on fixing it.

Why don't you start with Socket.BeginSend and Socket.BeginReceive like normal people, so that your socket is NOT in blocking mode, and so you don't have to poll it?

Here's the typical structure of a receiving class (note: this code is not tested and compiled for guarantees in accuracy, but I've done this so much that I'm relatively certain it's correct.  Ask about design decisions if you want):


public class Connection {
 public const int BUFFER_LENGTH = 512;
 private Socket sock;
 private EndPoint destination;
 private byte[] buffer;
 private AsyncCallback cb_Connected, cb_Received, cb_Sent; // delegate declarations

 public event EventHandler Error;
 protected virtual void OnError() {
  if (Error != null)
    Error(this, EventArgs.Empty);
 }
 public event EventHandler Connected;
 protected virtual void OnConnected() {
  if (Connected != null)
    Connected(this, EventArgs.Empty);
 }
 public event EventHandler Disconnected;
 protected virtual void OnDisconnected() {
  if (Disconnected != null)
    Disconnected(this, EventArgs.Empty);
 }

 public Connection(IPEndPoint dest) {
   sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
   cb_Connected = new AsyncCallback(sock_Connected);
   cb_Received = new AsyncCallback(sock_Received);
   cb_Sent = new AsyncCallback(sock_Sent);
   buffer = new byte[BUFFER_LENGTH];
   destination = dest;
 }

 public void Connect() {
  try {
   sock.BeginConnect(
    this.destination,
    this.cb_Connected,
    null); // MSDN recommends against using null here, but I don't think it matters
         // much unless you really need another object to store state data.
  } catch (SocketException se) {
    OnError();
    // do something with the exception, like tell the user why there was an error.
    sock.Close();
    OnDisconnected();
  }
 }

 private void sock_Connected(IAsyncResult iar) {
  try {
   sock.EndConnect(iar);
   OnConnected();
   // set up receiving loop
   sock.BeginReceive(
    buffer,
    0,
    BUFFER_LENGTH,
    SocketFlags.None,
    cb_Received,
    null); // again, MSDN recommends against using null here.
  } catch (SocketException se) {
   OnError();
   // again, do something
   sock.Close();
   OnDisconnected();
  }
 }

 private void sock_Received(IAsyncResult iar)
 {
   int dataLen = 0;
   byte[] tempBuffer = new byte[0];
   try {
    dataLen = sock.EndReceive(iar);
    // copy the buffer, recreate, and resume receiving.
    tempBuffer = new byte[dataLen];
    Array.Copy(buffer, 0, tempBuffer, 0, dataLen);
    buffer = new byte[BUFFER_LENGTH];
    sock.BeginReceive(
     buffer,
     0,
     BUFFER_LENGTH,
     SocketFlags.None,
     cb_Received,
     null);
   } catch (SocketException ex) {
     OnError();
     // be informative
     sock.Close();
     OnDisconnected();
   }
   // work with data in tempBuffer here.
 }

 public void Send(byte[] data) {
  try {
   sock.BeginSend(
    data,
    0,
    data.Length,
    SocketFlags.None,
    cb_Sent,
    null);
  } catch (SocketException se) {
   OnError();
   // yeah yeah
   sock.Close();
   OnDisconnected();
  }
 }

 private void sock_Sent(IAsyncResult iar) {
  try {
   sock.EndSend(iar);
  } catch (SocketException se) {
   OnError();
   // you know the drill
   sock.Close();
   OnDisconnected();
  }
 }
}


That will effectively work in asynchronous mode.  If you decompile my OpenConnectionManager class, you'll find that I have this set up doubly, one for BNLS, one for Bnet.  I also have structure there for UDP, but it's not used at this time.

By the way, last I checked, System.Threading.Thread.Sleep took an integral parameter of milliseconds, so there's no reason to do TimeSpan.FromMilliseconds() in your code.  :P
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

MyndFyre

I know you're thinking what a great guy I am for giving you this framework, so I'll just beat you to the punch and say that you're welcome.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

shout

#13
For the BeginConnect and EndConnect and related, would this not work?


     public void Connect()
     {
        socket.BeginConnect(endPoint, new AsyncCallback(ConnectCallback), null);
     }

     private void ConnectCallback(IAsyncResult ar)
     {
        socket.EndConnect(ar);
     }


Also, if a socket had a BeginReceive call before the last one was complete, would that cause it to crash?

MyndFyre

Quote from: shout on August 06, 2004, 12:38 AM
For the BeginConnect and EndConnect and related, would this not work?


     public void Connect()
     {
        socket.BeginConnect(endPoint, new AsyncCallback(ConnectCallback), null);
     }

     private void ConnectCallback(IAsyncResult ar)
     {
        socket.EndConnect(ar);
     }


Also, if a socket had a BeginReceive call before the last one was complete, would that cause it to crash?

Sure, they'd work.  However, you'd need to deal with Exceptions that can arise elsewhere in your code (specifically, where you call Connect).  Note that if you have an Exception at EndConnect, since it's a callback, the Exception will bubble up to the top-level event handler, which will (if you're using Forms) will display an ugly "Unhandled Exception" dialog, or will cause a Console App to stop.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.