Feeds:
Posts
Comments

Archive for May, 2004

Andrew Phillips asked on my CodeProject article Events and event handling in C# forum whether delegates alone aren’t sufficient for event handling and what the purpose of the event keyword is. Here is his post in it’s entirety:-

OK, I understand delegates but there is a basic thing about events that no books, articles etc ever explain. What is the purpose of the “event” keyword. I have tried example code that demonstrates events and they all continue to work if you remove the “event” keyword from the declaration of the delegate.

It seems to me that delegates are sufficient for implementing event-handling code. I can’t see the purpose of the “event” keyword. What am I missing?

Andrew Phillips

Here is the answer I posted for him :-

Hi Andrew

There is a subtle difference between using the event keyword and not using the event keyword.

When you access the Event member from outside the class, the “event” keyword prevents you from both invoking the event as well as from setting the event to null. But if you remove the event keyword, you can set the delegate to null or even invoke the delegate directly.

So essentially the event keyword protects the event from being invoked or set to null from outside of the class.

Hope you understood what I said.

Regards
Nish

p.s. Good question by the way. After 2+ years I am glad someone read my article well enough to want to ask such a question

I thought it was an interesting enough issue and that it deserved a blog entry here. In fact here is some sample code to make things clearer.

/// <summary>
/// The delegate that will represent
/// the event handler
/// </summary>
public delegate void DivBySevenHandler(object o,
  DivBySevenEventArgs e);

/// <summary>
/// The EventArgs derived class that I use
/// to pass info to the event
/// </summary>
public class DivBySevenEventArgs : EventArgs
{
  public readonly int TheNumber;

  public DivBySevenEventArgs(int num)
  {
    TheNumber = num;
  }
}

/// <summary>
/// The listener class to whose member function
/// I hook my event to
/// </summary>
public class DivBySevenListener
{
  public void ShowOnScreen(object o, DivBySevenEventArgs e)
  {
    Console.WriteLine(
      "divisible by seven event raised!!!" +
      " the guilty party is {0}",
      e.TheNumber);
  }
}

/// <summary>
/// The class that has an event, a function
/// that raises the event and the event handler method
/// </summary>
public class Buster
{
  public event DivBySevenHandler EventSeven;

  public void OnEventSeven(DivBySevenEventArgs e)
  {
    if(EventSeven!=null)
      EventSeven(new object(),e);
  }

  public void GenNumbers()
  {
    for(int i=0;i<99;i++)
    {
      if(i%7==0)
      {
        DivBySevenEventArgs e1 = new DivBySevenEventArgs(i);
        OnEventSeven(e1);
      }
    }
  }
}

Now for some sample code that uses the class and raises an event :-

public class Nish
{
  public static void Main()
  {
    Buster b = new Buster();
    DivBySevenListener dbsl = new DivBySevenListener();
    b.EventSeven += new DivBySevenHandler(
      dbsl.ShowOnScreen);
    b.GenNumbers();
    //b.EventSeven(null,new DivBySevenEventArgs(11));
    //b.EventSeven = null;
  }
}

Lines 10 and 11 will not compile which is a very good thing. You certainly wouldn’t want people setting your event object to null or invoking your event handler directly. If you remove the event keyword from the declaration, you’ll find that both the above operations are allowed which can prove to be very nasty as far as end-results go.

So, there you go Andrew – now you know the importance of using the event keyword :-)

Read Full Post »

[Edit - Jan 26 2005]Unfortunately, the information in this entry is incorrect. See this later entry for details.[/Edit]

I was trying out some RCW stuff (between VC++ 7.1 unmanaged and C#) and faced this little problem of a BSTR that could not be freed at all. I’ll explain the issue to you :-

Let’s say I have a COM method as follows :-

HRESULT GetHerName([in] LONG id, [out,retval] BSTR* namestr);

And say, I have the following implementation :-

STDMETHODIMP CNoomata::GetHerName(LONG id, BSTR* namestr)
{
    wchar_t str[100];
    swprintf(str,L"Sheila_%d",id);
    *namestr = SysAllocString(str);
    return S_OK;
}

Now C# will see this method as :-

string GetHerName(int id);

And I can use the class easily as follows :-

NoomataClass addr = new NoomataClass();
Console.WriteLine(addr.GetHerName(10));
string s2 = addr.GetHerName(22);

All that is very fine, but there is one *major* problem here. Every time I call GetHerName from my C# program I leak a BSTR! That’s bad, really bad!

RCW marshalling magic will create a new System.String object for me from the BSTR that is returned by the COM method, but then it ignores the BSTR – and eventually leaks it. Now had this been a COM client, the COM client would have been responsible for freeing the BSTR using SysFreeString, but the C# program does not even see the returned BSTR.

Heath Stewart (C# MVP and Fellow CPian) has confirmed that the BSTR will indeed leak in the above situation and he has offered an alternate solution that will avoid the leak. It’s not a very straightforward solution though – Heath suggests that instead of having the COM method return a BSTR*, we should have it return an IntPtr; now we can get a System.String object by using Marshal.PtrToStringBSTR (this will be a copy though), and once we do that we can use Marshal.FreeBSTR to free the BSTR pointed to by the IntPtr. I don’t usually say “ouch”, but I think this time I think I can say *ouch* and in fact *double ouch* :-)

Read Full Post »

Down with viral fever

Just in case anyone was wondering why my blog is not being updated, I’ve been down with viral fever since Friday the 14th (just escaped by 1 day eh?) and though I’ve still been able to edit and post articles on CodeProject, I haven’t felt strong enough to try out new stuff which is when I usually end up writing blog entries. I have finished work on my CP Zip Stripper editor tool and will probably upload it to the CodeProject tools section sometime today.

More than the fever, what annoys me is the absolute body weakness that has taken over me – I walk and move like a 130 year old man :cry:

Read Full Post »

I am currently working on a simple C# Windows Forms application to help me with editing/authoring articles for CodeProject, that basically strips unwanted files off zip files, and I wanted to associate an Explorer context menu entry with zip files that’d open the zip in my application. Of course, this was a mere matter of editing the registry and adding an odd key there and an odd value here. But I thought the function would be pretty useful for other people who might want similar functionality and so wrote it generically.

Usage

Here is how you can use the function :-

AddContextMenuItem(".zip", "ZipStrip",
  "Open with &ZipStrip", Application.ExecutablePath + " %1");

Code Listing

I had to mess with the indentation to avoid horizontal scrolling :-)

//Extension - Extension of the file (.zip, .txt etc.)
//MenuName - Name for the menu item (Play, Open etc.)
//MenuDescription - The actual text that will be shown
//MenuCommand - Path to executable
private bool AddContextMenuItem(string Extension,
  string MenuName, string MenuDescription, string MenuCommand)
{
  bool ret = false;
  RegistryKey rkey =
    Registry.ClassesRoot.OpenSubKey(Extension);
  if(rkey != null)
  {
    string extstring = rkey.GetValue("").ToString();
    rkey.Close();
    if( extstring != null )
    {
      if( extstring.Length > 0 )
      {
        rkey = Registry.ClassesRoot.OpenSubKey(
          extstring,true);
        if(rkey != null)
        {
          string strkey = "shell\\" + MenuName + "\\command";
          RegistryKey subky = rkey.CreateSubKey(strkey);
          if(subky != null)
          {
            subky.SetValue("",MenuCommand);
            subky.Close();
            subky = rkey.OpenSubKey("shell\\" +
              MenuName, true);
            if(subky != null)
            {
              subky.SetValue("",MenuDescription);
              subky.Close();
            }
            ret = true;
          }
          rkey.Close();
        }
      }
    }
  }
  return ret;
}

Read Full Post »

Jagged arrays in C++/CLI

PaulW asked on my CP article’s forum whether C++/CLI has support for jagged arrays. In the old syntax, there was no direct syntactical support for jagged arrays and we were left with the rather uneasy option of simulating jagged arrays through contrived code. My first answer to him was that there wasn’t direct support for jagged arrays in the new syntax as far as I knew. But Holger Grund (VC++ MVP) pointed out to me that it was quite easy to do jagged arrays in C++/CLI.

For example, the following C# code :-

int[][] arr = new int[][5]; // C#

corresponds to the following C++ code :-

array<array<int>^>^ arr = gcnew array<array<int>^> (5); // C++

Nice eh?

Read Full Post »

Follow

Get every new post delivered to your Inbox.