Zune Now Playing support for Digsby and Winamp-compatible nowplaying software.
The Zune media player delivers Now Playing information to Windows Live Messenger, but other software isn’t able to pick up these messages. Quite a few users have asked for Zune Now Playing support in Digsby, so I put together this little app that lets this work. The application itself is generic, converting Zune now playing messages into the more widely implemented Winamp now playing method.
Download the executable and source (C++).
Code Listing:
#include "stdafx.h" #include "ZuneNowPlaying.h" #include "LimitSingleInstance.h" // KB243953 #include <regex> const std::tr1::wregex pattern(L".*?\\\\0Music\\\\0.*?\\\\0.*?\\\\0(.*?)\\\\0(.*?)\\\\0"); CLimitSingleInstance g_SingleInstanceObj(L"{24F3CD83-9FFE-4DE6-951D-63958942F834}"); HWND hWndWinamp; HWND hWndWindowsLiveMessenger; LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_COPYDATA: { COPYDATASTRUCT *cds = (COPYDATASTRUCT*)lParam; wchar_t *str = (wchar_t*)cds->lpData; std::tr1::wcmatch result; if(std::tr1::regex_search(str, result, pattern)) { std::wstring ret = result[2].str() + L" - " + result[1].str(); SetWindowText(hWndWinamp, ret.c_str()); } else { SetWindowText(hWndWinamp, L""); } break; } case WM_DESTROY: PostQuitMessage(0); break; case WM_USER: if (lParam == 104) { return 1; // Winamp=Playing (always) } } return DefWindowProc(hWnd, message, wParam, lParam); } void RegisterClasses(HINSTANCE hInstance) { WNDCLASSEX wcex = WNDCLASSEX(); wcex.cbSize = sizeof(WNDCLASSEX); wcex.lpfnWndProc = WndProc; wcex.hInstance = hInstance; wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszClassName = L"MsnMsgrUIManager"; RegisterClassEx(&wcex); wcex.lpszClassName = L"Winamp v1.x"; RegisterClassEx(&wcex); } bool CreateWindows(HINSTANCE hInstance) { // Pretend to be Windows Live Messenger, so WM_COPYDATA messages are sent to us. hWndWindowsLiveMessenger = CreateWindow(L"MsnMsgrUIManager", L"", WS_DISABLED, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); // Pretend to be Winamp (any version), so apps will pick us up for Now Playing. hWndWinamp = CreateWindow(L"Winamp v1.x", L"", WS_DISABLED, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); return hWndWinamp && hWndWindowsLiveMessenger; } int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR /*lpCmdLine*/, int /*nCmdShow*/) { MSG msg = MSG(); if (!g_SingleInstanceObj.IsAnotherInstanceRunning()) { RegisterClasses(hInstance); if (CreateWindows(hInstance)) { while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } } } return (int)msg.wParam; }</regex>
How it works:
It’s pretty simple, Zune software sends a WM_COPYDATA message to a window with class name MsnMsgrUIManager, the message contains a pointer to a unicode string, that looks something like this:
ZUNE\0Music\01\0{0} - {1}\0TRACK_TITLE\0TRACK_ARTIST\0TRACK_ALBUM\0zune:ZUNE_GUID\0 // TRACK_TITLE: Title // TRACK_ARTIST: Artist // TRACK_ALBUM: Album // ZUNE_GUID: A GUID that may refer to the Zune device, Zune account, or Zune software itself. // Note: {0} - {1} is the format of how the string should be displayed in WLM - I ignore this entirely. // Note2: This method is used by other software, so I don't gate on ZUNE for the sake of maximum flexibility. // Note3: The "1" after Music specifies the playing state. 0=Stopped, 1=Playing. I ignore this and instead just use whether or not the other fields exist.
Note: The \0’s in the above string are literally \ and 0, not NULL characters.
Using a regular expression to match the fields, The artist and title are extracted from the string, and set as the window caption for a window with class name Winamp v1.x. Software (like Digsby, or other now playing apps) may use FindWindow to locate the fake Winamp player, and read the caption with GetWindowText.
You may need to install the Microsoft Visual C++ 2010 Redistributable Package (x86).
WPF Windows 7 Explorer Toolbar Control
Today I have been working on emulating the Windows 7 Explorer Toolbar in WPF. I really like this control as it blends the older toolbar and menubar concepts into one which may support icons and dropdown menus.
WPF makes creating new controls quite easy. I decided to base my controls off of System.Windows.Controls.Toolbar, and similarly each item in the Toolbar is based off of the Button control.
Here’s the XAML that I came up with
Creating a new WPF application and using this code for Window1.xaml, you should see this:

Note that while this control is visually similar to the Windows 7 Explorer Toolbar, it does not handle overflow, or collapse menu items like the Explorer one does. Perhaps an eventual update to this control will provide more advanced support.
This control does handle the IsMouseOver, IsMouseDown, and IsKeyboardFocused states. Adding the menu glyph is a WPF Polygon.
What is CamServer?
I added a link to CamServer on the right of the page a little while ago, but didn’t explain what CamSever is and who would want to use it. CamServer is experimental software.
CamServer is a surveillance and monitoring application for Windows and Linux that lets you easily view and record remote cameras. Simply plug one or more USB or PCI capture devices into a computer, and then view the cameras from a remote location — on the same network or over the internet. Computers running CamServer on the local network are automatically discovered, no configuration is needed!
Screenshots:
Cameras are loaded from your computer, the local network, and over the internet. CamServer nodes can host cameras for remote access. Designate one instance for external use, and view all your cameras in one place.
Record video to AVI for future playback. Cameras may be designated as public or open-access, or protected with a username/password of your choosing.
Camera feeds may include timestamp and response information.
If the connection is lost, CamServer will let you know that the device is no longer providing video.
Grab a copy of CamServer and let me know what you think!
C# Threading Shorthand
As the complexity of an application increases, often so does the threading complication. I have two snippets which often come in useful when dealing with threads in C#.
Quickly execute code in the background:
new Thread((ThreadStart)delegate() { // code here is executed on a new thread // blocking operations will not block the calling thread }).Start();
Note that if this code is to be called often, a ThreadPool may be the better choice. ThreadPools’ have less overhead for instances when many threads would be created and destroyed.
Execute code that manipulates UI:
if (Control.IsHandleCreated) { Control.Invoke((MethodInvoker)delegate() { // code here is safe to interact with Control }); }
Replace ‘Control’ with ‘this’ inside the Form class. Control may refer to any control created on the UI thread.
TraceListener to a textbox
Trace, in System.Diagnostics is useful for determining where an application failed. .NET has build-in support for writing to the console or a file on disk, but it’s a little bit more complicated to direct this output to a TextBox on a windows form.
Here’s the class you need to get the trace information.
class FormTracer : TraceListener { public delegate void OnTextHandler(string msg, bool newLine); public event OnTextHandler OnText; public override void Write(string message) { if (OnText != null) OnText.Invoke(message, false); } public override void WriteLine(string message) { if (OnText != null) OnText.Invoke(message, true); } public FormTracer() { Trace.Listeners.Add(this); } ~FormTracer() { Trace.Listeners.Remove(this); } }
When created, FormTracer will add itself to the tracers collection and start receiving messages. To add these messages to your form, create a FormTracer object like so:
public Form1() { InitializeComponent(); FormTracer ft = new FormTracer(); ft.OnText += new FormTracer.OnTextHandler(ft_OnText); }
The event handler may be called on threads outside the UI, so you’ll want to make the OnText handler look something like this
void ft_OnText(string msg, bool newLine) { if (this.IsHandleCreated) { this.Invoke((MethodInvoker)delegate() { textBox1.Text += msg; if (newLine) textBox1.Text += "\r\n"; }); } }
Add a button and handle the Click event for a test Trace message.
private void button1_Click(object sender, EventArgs e) { Trace.WriteLine("Button Pressed!"); }
GVNotifier 1.1 adds Google Contacts, Sorting, Search
Screenshots for GVNotifier 1.1:
New Features:
- Small Font Option
- Hide ‘406′ area code numbers (Google Voice SMS numbers)
- Enter to send Message.
- Google Contacts integration
- Recent contacts are at the top of the contact list, other contacts are sorted alphabetically at the bottom.
- Callback number may be selected from the Message window.
- Performance improvements
Let me know what you think in the comments, or join the beta team!
GVNotifier.net requires the .NET Framework 3.5 and Windows XP, Windows Vista or Windows 7. Aero recommended.
If you’re already using GVNotifier, just restart for the update. (Try restarting twice if it doesn’t pop up)
GVNotifier.net 1.1 [ClickOnce Install]
C#: Don’t display the startup form.
Something that often seems to be a problem with beginning C# developers is the display of the initial form. Normally one would always want the startup form to be displayed as soon as possible–but sometimes the application lives in the tray, or should not initially display a window.
One may first think that an event in System.Windows.Forms.Form can be handled, and the form may be directed to Hide. Unfortunately, this won’t work as expected, the Form will always get the SW_SHOW message when Application.Run() is executed.
When creating a new project, Visual Studio will generate a Program.cs which looks similar to the following:
namespace CamOn { static class Program { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } } }
When Application.Run is invoked with a Form parameter, it will create and show the window. The easiest way to override this behavior is to simply not call Application.Run with the form:
namespace CamOn { static class Program { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); new Form1(); Application.Run(); } } }
Form1 will still be created and pump messages – but it won’t initially be shown.
Reading Motion-JPEG camera streams
I’ve recently come across a Hawking HNC230G network camera, which shares internals with the Edimax IC-1500Wg. These cameras pump out a Motion-JPEG stream which is unlike many other “Motion-JPEG” IP cameras.
Many of these devices will create video with a constantly updating jpeg file, served via HTTP. This is generally a better solution than what exists in my camera. Reading these streams is simple in many languages. The HNC230G took a little more probing and experimentation before I could read data without artifacts.
Camera Services
HTTP Administration website – Port 80
Motion-JPEG stream – Port 4321
There does not appear to be any images on the HTTP administration website. All video data passes through the service on 4321. Video data is not encrypted or secured in any way – there is no authentication.
Finished Protocol
After a socket is connected to the service on 4321, it should send the single command which is supported: 0110\n. Sending 0110 followed by a linebreak will signal the device to send a JFIF frame.
The camera will send 4 bytes of data before the JFIF header, these bytes can be interpreted as follows:
- Byte 1: High 8 bits of the frame size
- Byte 2: Low 8 bits of the frame size
- Byte 3: Active users on the camera
- Byte 4: Unknown reserved byte
The size of the frame is calculated only after the 4-byte header. The process can be repeated once the frame has been received by the client. The image data received will contain a JFIF (JPEG File Interchange Format) frame.
I’ve been able to achieve approximately 10fps at 640×480 with this method.
Limitations
The key limitations with this method relate to the firmware design for this camera.
- Image size can only be set through the HTTP web service.
- LED state can only be queried or set through the HTTP web service.
- The device will sometimes disconnect the client or return invalid data. This is solved by reconnecting the client.
- As the number of users increase, the possible frames-per-second decreases. Frame rates are 25-50% less when adding a second user.
Sample C# Code
public byte[] GetFrame() { if (!conn.Connected) { Connect(); if (!conn.Connected) { throw new Exception("Cannot fetch frame from camera. Not Connected."); } } StreamWriter sw = new StreamWriter(conn.GetStream()); // request a frame sw.WriteLine("0110"); sw.Flush(); // get the high 8bits of the size int size = conn.GetStream().ReadByte() << 8; // get the low 8bits of the size size += conn.GetStream().ReadByte(); // active users int j1 = conn.GetStream().ReadByte(); ActiveUsers = j1; // unknown byte int j2 = conn.GetStream().ReadByte(); if (size == 0) { return null; } return new BinaryReader(conn.GetStream()).ReadBytes(size); }
C#: WebClient Usage
Microsoft has provided a great utility since .NET 1.0 for doing quick I/O via websites. The WebClient class provides basic functionality for downloading from and uploading to webservers. the WebClient example on MSDN leaves a lot to be desired, especially for beginners. I’d like to expand on that, as well as provide some example code.
C#: Using WebClient to fetch a page:
// create a new instance of WebClient WebClient client = new WebClient(); // set the user agent to IE6 client.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705;)"); try { // actually execute the GET request string ret = client.DownloadString("http://www.google.com/"); // ret now contains the contents of the webpage Console.WriteLine("First 256 bytes of response: " + ret.Substring(0,265)); } catch (WebException we) { // WebException.Status holds useful information Console.WriteLine(we.Message + "\n" + we.Status.ToString()); } catch (NotSupportedException ne) { // other errors Console.WriteLine(ne.Message); }
(This code uses DownloadString, you can also use DownloadData for a more binary-friendly version)
This is great for fetching simple pages that have data encoded in the querystring, but there are some problems with the basic DownloadString method of WebClient. It’s synchronous, so it will block until the operation completes. So for slow connections, or large files, this would need to run in another thread. There is a better way. But first, here’s another example of another basic, but important, method, DownloadFile.
// create a new instance of WebClient WebClient client = new WebClient(); // set the user agent to IE6 client.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705;)"); try { // actually execute the GET request client.DownloadFile("http://www.google.com/","google_fetch.txt"); // ret now contains the contents of the webpage Console.WriteLine("File Saved."); } catch (WebException we) { // WebException.Status holds useful information Console.WriteLine(we.Message + "\n" + we.Status.ToString()); } catch (NotSupportedException ne) { // other errors Console.WriteLine(ne.Message); }
This example is almost identical to the above, aside from the client.DownloadFile method. This will save the file to disk, instead of returning a string–often what you would end up doing with the string anyway.
But can I send POST data?
Yes! Using WebClient.UploadString or WebClient.UploadData you can POST data to the server easily. I’ll show an example using UploadData, since UploadString is used in the same manner as DownloadString.
byte[] bret = client.UploadData("http://www.website.com/post.php", "POST", System.Text.Encoding.ASCII.GetBytes("field1=value1&field2=value2") ); string sret = System.Text.Encoding.ASCII.GetString(bret);
UploadData returns a byte array (byte[]) which contains the contents of the page. This can easily be converted to a string by using the System.Text.Encoding.ASCII.GetString() method. You can also use the other encoding types in System.Text.Encoding (such as UTF8) to do the same.
Also note the use of GetBytes(), the UploadData method will only take a byte array as a buffer for the upload. This works well if you are uploading a binary file.
What about the asynchronous methods of WebClient?
WebClient provides asynchronous methods for fetching webpages as well, they are named similarly to the synchronous methods, DownloadFileAsync, DownloadDataAsync, DownloadStringAsync, UploadFileAsync, UploadDataAsync, UploadStringAsync, and UploadValuesAsync.
In order to execute an Async request, you will need to attach event handlers before the method is executed. Without these event handlers you will not have any sense of when the operation finishes, or what stage it is at.
C# WebClient Asynchronous call example:
void do_upload() { WebClient client = new WebClient(); // add event handlers for completed and progress changed client.UploadProgressChanged += new UploadProgressChangedEventHandler(client_UploadProgressChanged); client.UploadFileCompleted += new UploadFileCompletedEventHandler(client_UploadFileCompleted); // carry out the operation as normal client.UploadFileAsync("http://www.daveamenta.com/up.php", @"c:\somefile.bin"); } void client_UploadProgressChanged(object sender, UploadProgressChangedEventArgs e) { Console.WriteLine(e.ProgressPercentage); } void client_UploadFileCompleted(object sender, UploadFileCompletedEventArgs e) { if(e.Result != null) { Console.WriteLine(System.Text.Encoding.ASCII.GetString(e.Result)); } }
The call to client.DownloadFileAsync will no longer block the thread, and will execute in the background, periodically calling the event handlers to display progress. The other methods can be used in this same way.
C#: Send text to a pastebin (HttpWebRequest POST example)
I’m working on a small application that hooks into the clipboard monitor chain and displays a list of options whenever text is saved to the clipbaord. One of the options I wanted was to be able to send data to pastebin.com, a popular text/code sharing service. This is a relatively mundane task, faking the postdata for a webpage, and sending the requests as a browser. There were some hicups though, mostly with Finding the redirect URL using HttpWebRequest/HttpWebResponse.
A little background:
HttpWebRequest and HttpWebResponse live in the System.Net namespace, and provide the ability to quickly send HTTP requests to a webserver. This is what a simple GET request would look like:
try { HttpWebRequest request = (HttpWebRequest) WebRequest.Create("http://davux.pastebin.com/pastebin.php"); HttpWebResponse res =(HttpWebResponse) request.GetResponse(); if (res.StatusCode == HttpStatusCode.OK) { StreamReader reader = new StreamReader(res.GetResponseStream()); Console.WriteLine(reader.ReadToEnd()); } else { // handle errors } res.Close(); } catch (Exception ex) { Console.WriteLine("Error: " + ex.Message); }
Note: For most simple tasks, it is wise to use System.Net.WebClient, which is not suitable for this task, because it does not expose the ability to disable automatic redirection.
To send new data to pastebin, it needs to be sent via HTTP POST. Using Firefox LiveHTTPHeaders, I determined what string needs to be sent in order to create a new entry. This can also be determined by reading the source of the page, and looking at each of the fields contained in the <form> block.
string post = "&parent_pid=&format=text&code2=" + code_text_to_send + "&poster=" + poster_name + "&paste=Send&expiry=" + expiry + "&email=";
- code_text_to_send – The data which should be used to create a new page.
- poster_name – The author of the post
- expiry – How long the data should be retained for. Options are ‘d’ for one day, ‘m’ for one month, and ‘f’ for indefinitely.
Note: Make sure to URLEncode each field that is sent!
After further examination of the headers and data sent back, I decided that the best way to extract the link was to catch the HTTP 302 Document Found response.
HTTP/1.x 302 Found Date: Thu, 08 May 2008 01:06:08 GMT Server: Apache/1.3.33 (Debian GNU/Linux) mod_python/2.7.10 Python/2.3.4 PHP/4.3.10-22 mod_perl/1.29 X-Powered-By: PHP/4.3.10-22 Location: http://davux.pastebin.com/m10a794d6 Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/html; charset=iso-8859-1
HttpWebRequest, by default, has AllowAutoRedirect set to true, which means that, internally, it will resolve this message, and fetch the new URL. This extra operation is needless in this circumstance, so it is best to disable it and extract the URL from the header. The headers associated with each request or response are found in the Headers object for each class. We wish to look at the Location field to find our URL.
C# WebClient HTTP POST Example:
try { HttpWebRequest request = (HttpWebRequest) WebRequest.Create("http://davux.pastebin.com/pastebin.php"); request.AllowAutoRedirect = false; request.Method = "POST"; string post = "&parent_pid=&format=text&code2=" + HttpUtility.UrlEncode(text) + "&poster=Dave&paste=Send&expiry=m&email="; byte[] data = System.Text.Encoding.ASCII.GetBytes(post); request.ContentType = "application/x-www-form-urlencoded"; request.ContentLength = data.Length; Stream response = request.GetRequestStream(); response.Write(data,0,data.Length); response.Close(); HttpWebResponse res =(HttpWebResponse) request.GetResponse(); res.Close(); // note that there is no need to hook up a StreamReader and // look at the response data, since it is of no need if (res.StatusCode == HttpStatusCode.Found) { Console.WriteLine(res.Headers["location"]); } else { Console.WriteLine("Error"); } } catch (Exception ex) { Console.WriteLine("Error: " + ex.Message); }
(Some error checking and extra code have been removed for the sake of clarity)
The values for expiry and author have been hard-coded in order to save space. This basic example will create a new Pastebin entry on my not so private pastebin, and print the URL of the entry to the console. If there is an error, it will print the exception message. If the HTTP code returned is not 302/Found, it will print a generic error. (If the server is not returning a 302 for this request, there is nothing codewise that can be fixed, and thus the only option for error is generic.)








