Events in .NET winforms: more of what works and what doesn't

Download and get help for different MediaMonkey Addons.

Moderators: Peke, Gurus

darchangel
Posts: 26
Joined: Wed Nov 30, 2005 11:23 pm

Events in .NET winforms: more of what works and what doesn't

Post by darchangel » Fri Jun 15, 2007 7:14 am

Here are some more attempts at getting a .net winform to receive mm events:

WHAT DIDN'T WORK

try 1 auto launch script to launch winform and subscribe to events. delegate events to a method in the app
problem GetObject doesn't seem to get the currently running version of the winform. error is thrown. CreateObject also yields wrong results

try 2 same as #1 but make the winform single instance so CreateObject will always get the correct version
problem the only way I can figure out how to make an app single instance involves using the static Main() for much of the work. CreateObject bypasses Main and only calls constructor

try 3 same as #1 but use threading and Invoke/BeginInvoke to fire winform method
problem error about not being able to use Invoke/BeginInvoke without having a handle to the window. unsure how to do this in vbscript. again, GetObject didn't work here in trying to resolve it

WHAT WORKED (BUT SUCKS)

solution auto launch script registers for events and launches the winform. event methods create temp files when events are fired. (note: at the beginning of the onstart, delete old files or future runs will think that these events are new). the winform has a file system watcher (available in .net 2.0) which reacts to the file creation and deletes the files sequentially
why it sucks using files as events is simply lame. i also did a version where only 1 file was used but you come into IO collisions/exceptions when too many events happen too quickly. also, keeping the files in order when events fire quickly is more advanced than just using a timestamp with seconds as the greatest granularity

solution launch 2 .net apps: 1 winform, 1 console. the console one can handle events just fine. so set up a cross process connection between them either via .net remoting or through socket connections and have the console app delegate the events to the winform
why it sucks way too much overhead. and i refuse to keep a client server relationship on the same box just to delegate event callls

Peke
Posts: 12495
Joined: Tue Jun 10, 2003 7:21 pm
Location: Serbia
Contact:

Post by Peke » Fri Jun 15, 2007 2:05 pm

OK, Interesting, I'm not .NET coder but have you tried this way?

Open WinForm, On MM event Check FindWindow() to get Handle then use PostMessage() to send Custom Message to WinForm Handle and Handle On Message inside WinForm. All thrum WinAPI and without problems.

Note When you get Handle with FindWindow() save it sonwhere so that next time you skip that test and only Check For NULL value in saved Variable too see if your app is closed or not. Saves Speed and works (In Delphi).
Best regards,
Pavle
MediaMonkey Team lead QA/Tech Support guru
Admin of Free MediaMonkey addon Site HappyMonkeying
Image
Image
How to add SCREENSHOTS to forum

darchangel
Posts: 26
Joined: Wed Nov 30, 2005 11:23 pm

Post by darchangel » Mon Jun 18, 2007 4:40 pm

Great idea. Unfortunately, when I tried this script

Code: Select all

Sub OnStartup
  Dim hWnd
  hWnd = FindWindow("Untitled - Notepad", vbNullString)
End Sub
I got this error

Code: Select all

Error #13 - Microsoft.VBScript runtime error
Type mismatch: 'FindWindow'
File: "C:\PROGRA~1\MEDIAM~1\Scripts\Auto\test.vbs", Line: 3, Column:2

Steegy
Posts: 3452
Joined: Sat Nov 05, 2005 7:17 pm
Location: Belgium
Contact:

Post by Steegy » Mon Jun 18, 2007 6:59 pm

You can't use API through VBScript, unless you use some ActiveX object that can do that. C#.Net can easily do what you want, you only need to add the P/Invoke signature first.

Code: Select all

[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

IntPtr hWnd = FindWindow("Winamp v1.x", null);
Extensions: ExternalTools, ExtractFields, SongPreviewer, LinkedTracks, CleanImport, and some other scripts (Need Help with Addons > List of All Scripts).

darchangel
Posts: 26
Joined: Wed Nov 30, 2005 11:23 pm

Post by darchangel » Tue Jun 19, 2007 4:21 pm

Thanks for the C# code but I'm not sure how it helps solve the original problem: MM's VBScript still doesn't have a window handle through which it can send event notifications.

I've actually built everything without events now. However, if at any point in C# you call new SDBApplicationClass(); then when you shut down MM you get the "COM Server Warning" message box. This occurs regardless of whether you shut down the winform app or MM 1st.

I'm very close to giving up on programming with MM. Despite how good it looks like it could be, it's becoming damn impossible with C#. I'm playing whack-a-mole here. Every time I find one way to solve this events problem, it pops up somewhere else in a different idiosyncrasy.

Steegy
Posts: 3452
Joined: Sat Nov 05, 2005 7:17 pm
Location: Belgium
Contact:

Post by Steegy » Tue Jun 19, 2007 4:39 pm

when you shut down MM you get the "COM Server Warning" message box.
Indeed. The best way to get rid of this problem most of the times is to terminate my own application when it is exiting (you know, using something like Process.Kill()). Normally there should be no special requirements to make C# (or .Net) play nice. You can explicitly call a function to release the COM handle, but that doesn't change much, the MM warning is still there. In my opinion, and as other applications seem to do it, MM shouldn't give a warning but just exit.
Extensions: ExternalTools, ExtractFields, SongPreviewer, LinkedTracks, CleanImport, and some other scripts (Need Help with Addons > List of All Scripts).

darchangel
Posts: 26
Joined: Wed Nov 30, 2005 11:23 pm

Post by darchangel » Wed Jun 20, 2007 4:36 pm

And whack-a-mole continues...

Now I can do my own version of events, I can call SDBApplicationClass() from my app, and (now thanks to Steegy's Process.Kill() suggestion) I also close it without getting the COM server warning dialog.

However, now MediaMonkey cannot perform its own correct shutdown. This is inconvenient since it means that MM cannot save its previous state to resume on next launch -- such as the now playing playlist.

Here is the code I tried

Code: Select all

protected override void OnClosed(EventArgs e) {
    base.OnClosed(e);
    Process.GetCurrentProcess().Kill();
}

Code: Select all

protected override void OnClosed(EventArgs e) {
    base.OnClosed(e);
    Process[] procs = Process.GetProcessesByName("MEDIAM~1");
    foreach (Process p in procs)
        p.Kill();
}

Steegy
Posts: 3452
Joined: Sat Nov 05, 2005 7:17 pm
Location: Belgium
Contact:

Post by Steegy » Wed Jun 20, 2007 5:14 pm

I used Process.Kill() to terminate my own test application when it exits. You should never terminate MM that way!
Extensions: ExternalTools, ExtractFields, SongPreviewer, LinkedTracks, CleanImport, and some other scripts (Need Help with Addons > List of All Scripts).

darchangel
Posts: 26
Joined: Wed Nov 30, 2005 11:23 pm

Post by darchangel » Wed Jun 20, 2007 6:45 pm

@Steegy: Currently, MM launches my app via a vbs script in Scripts\Auto so when I kill current app, .NET must interpret Current as being MM. How would you suggest doing it? I'd prefer to have MM launch my app if possible.

darchangel
Posts: 26
Joined: Wed Nov 30, 2005 11:23 pm

Post by darchangel » Thu Jun 21, 2007 7:33 am

Oh yeah, and I also tried launching MM from my app even though I don't want to have to do it this way. With the above code killing my app on exit, I still get the COM server warning regardless of shutdown ordert. I just can't get MM to recognize that I've dropped my reference

Post Reply