Lorenz Cuno Klopfenstein

Posts tagged "Hacks"

Last.fm logo

I've had an account on Last.fm for more than 3 years and liked it on the spot. I love to explore new music, discover new artists, listen to streaming radio (that is, until it was free) and especially scrobbling the music I listen!

The geek in me simply freaks out seeing the amount of stats you can get from your Last.fm "scrobbled" data: the music I listened the most this week? Last month? What is my favorite Porcupine Tree song? In fact there's also lot of external services that offer awesome visualizations of your data.

This was great up to the day when I decided to put my whole music collection on the Windows Home Server and listen to it via the built in UPnP media sharing in Windows Media Player. That day I discovered that the Windows Media Player plug-in doesn't scrobble songs on network shares! It doesn't work, neither from an SMB shared folder, nor directly through UPnP sharing (which in fact is HTTP streaming).

More...

Posted on Wednesday, November 04, 2009
3219 Views
11 comments posted

I'm continuing to add more functionalities to the website and this time I've been working on "e-mail notifications" (which are sent to whoever commented on a post when a new comment is written). In order to send those e-mails asynchronously I decided to add the Quartz.NET Job Scheduler to the project and try to get it working.

So, after struggling to setup NHibernate, use the new ASP.NET MVC framework and getting Lucene.NET and NHibernate.Search to work, let's tackle the next library...  :S

Quartz.NET logo The latest version (1.0) of the library should be compatible with "partial trust" scenarios, but nonetheless still failed to work on the live website. I digged around in the source code to find the pieces of code which didn't work: I've documented my findings on the Quartz.NET mailing list and it should be fixed in the next versions (actually, the Common Logging framework would need to be fixed too for partial trust scenarios).

Anyway, if you need Quartz.NET now, here's what you need to do.

Remove the Common Logging library

After grabbing the source code from SourceForge, the first thing to do is to remove all references to the Common Logging library (which, as said, doesn't run on medium trust right now). To do so, remove the dll reference from the Quartz project:

Remove the Common Logging dll reference from the project.

Ok, now we end up with a lot of errors in the code.  :D Instead of removing the references to the logging library from the code, we can simply re-route all calls to a fake stub of the library, implementing some of the classes and copying the interface signatures with Reflector.

First of all, ILog.cs:

namespace Quartz {
	public interface ILog {
		// Methods
		void Debug(object message);
		void Debug(object message, Exception exception);
		void Error(object message);
		void Error(object message, Exception exception);
		void Fatal(object message);
		void Fatal(object message, Exception exception);
		void Info(object message);
		void Info(object message, Exception exception);
		void Trace(object message);
		void Trace(object message, Exception exception);
		void Warn(object message);
		void Warn(object message, Exception exception);

		// Properties
		bool IsDebugEnabled { get; }
		bool IsErrorEnabled { get; }
		bool IsFatalEnabled { get; }
		bool IsInfoEnabled { get; }
		bool IsTraceEnabled { get; }
		bool IsWarnEnabled { get; }
	}
}

Then ILoggerFactoryAdapter.cs:

namespace Quartz {
	public interface ILoggerFactoryAdapter {
		// Methods
		ILog GetLogger(string name);
		ILog GetLogger(Type type);
	}
}

Then create an implementation of ILog (I called it LogImpl) which simply does nothing on each call and returns false on all properties. Finally, let's implement LogManager.cs:

namespace Quartz {
	public sealed class LogManager {
		public static ILog GetLogger(string name) {
			return new LogImpl();
		}
		public static ILog GetLogger(Type type) {
			return new LogImpl();
		}

		// Properties
		public static ILoggerFactoryAdapter Adapter { get; set; }
	}
}

We don't need to implement the full class, just the methods used by Quartz, and return an instance of our stub logger.

Fixing Quartz.NET

Ok, now that the Common Logging library has been removed cleanly, we need to fix some of the calls in Quartz.NET which are not allowed in partial trust. Let's start with /Impl/StdSchedulerFactory.cs: in the Initialize() method you'll find a call to GetEnvironmentVariable() that must be removed.

string requestedFile = null;// Environment.GetEnvironmentVariable(PropertiesFile);

And then the same function call must be removed from the OverrideWithSysProps() method:

private static NameValueCollection OverrideWithSysProps(NameValueCollection props)
{
    NameValueCollection retValue = new NameValueCollection(props);
    /*ICollection keys = Environment.GetEnvironmentVariables().Keys;

    foreach (string key in keys)
    {
        retValue.Set(key, props[key]);
    }*/
    return retValue;
}

Ok, now to the /Core/QuartzScheduler.cs file. This class calls the GetAssembly() method to get the library's version number when initialized: this isn't allowed either on medium trust, so we'll have to remove that code.

/// 
/// Initializes the <see cref="QuartzScheduler"/> class.
/// 
static QuartzScheduler()
{
	//Assembly asm = Assembly.GetAssembly(typeof(QuartzScheduler));
	//versionInfo = FileVersionInfo.GetVersionInfo(asm.Location);
	//versionInfo = new FileVersionInfo();
}

And finally, remove all code in the "Version" properties with some hard-coded arbitrary values (you won't need them in most cases I think), like so:

public string Version
{
    get {
		//return versionInfo.FileVersion;
		return "1.0.0";
	}
}

That's it! Recompile the whole thing and add the new library to your project.  :)

Lazy?

If you don't want to mess with the source code and simply want a working version of Quartz.NET 1.0, download it here.

Posted on Wednesday, November 19, 2008
Tagged as
1900 Views
8 comments posted

As I started working on a little pet project for my friend NiKo, before clicking on the Visual C# icon (as I usually do) I actually started thinking about using languages other than C#. As blasphemous as it might sound, I really liked the idea of getting something to work using a "new" language, even if I had to study it and glance over the documentation the whole time (besides, you should learn a new language every year).

Jaipur picture by Carolina Mendonça on Flickr.com But still, I absolutely wanted the program to run on .NET because I'm really used to the base class library and to Windows Forms in particular: therefore, IronPython, IronRuby and similar languages came to my mind. Brooding about that on the train back to Foligno, I was almost sold on using Python, since I have been reading a lot about it and never had the chance to use it. But then, I discovered another "reptile" programming language for .NET: the Cobra language.  :)

Cobra has a similar syntax to Python but seems to better adapt to .NET (properties and such) and drops all the - in my opinion - extremely ugly conventions of Python (like the double underscores, all the self declarations in member functions, and so on).

Starting using Cobra

All you need to start programming with Cobra is in the small package you find on the website: the Cobra compiler essentially converts all cobra code to C# files (referencing its runtime Cobra.Lang.dll if needed) and then compiles to an executable using the standard C# compiler.

I also didn't use any IDE for my work with Cobra: just Notepad++ (Python syntax highlighting works quite well) and a hand made batch file to compile all files. This rudimental programming style was especially painful in the beginning: I noticed I can't even remember the namespaces of all classes I use...  :S But anyway, at the end of the day you gain some speed and I also noticed that I seemed to be more focused without IDE (might as well be a completely wrong impression since I was still struggling with the language).

Writing a Windows Forms project

The project I mentioned is mainly focused on the GUI and working with Windows Forms on Python, without a visual designer can be pretty boring and painful. Anyway, it works and it actually forces you to realize how hard it is to design a decent looking GUI directly in code.

Anyway, I was almost stuck with two big problems. I will explain them here, hoping that someone will find the solutions I found useful someday...  :)

Nested class references

The Cobra compiler (version 0.8) has some problems in referencing nested classes sometimes. I had the exact problem as also seen on the Cobra forums, where the compiler would spit out this

error: Cannot locate nested CLR type "System.Windows.Forms.Layout.LayoutUtils+MeasureTextCache" (simple name is "MeasureTextCache"). Compilation failed - 1 error, 0 warnings

as soon as I referenced the "Label" class in my code (and working without labels can be quite difficult  :D).

There is no working solution, but only an ugly workaround hack: first of all, download the Cobra source from the repository:

svn co http://cobra-language.com/svn/cobra/trunk/ cobra-workspace

You'll discover that the Cobra compiler itself is written in Cobra. Open up the file /Source/TypeProxies.cobra and go to line 182 or so. You'll find this:

if potential is nil # comes up on MS Windows .NET 2.0 for multiple types when using System.Windows.Forms # error: Cannot locate nested CLR type "System.Windows.Forms.UnsafeNativeMethods+IOleControl" (simple name is "IOleControl"). if 'NativeMethods' in clrType.toString return _hack(clrType) .throwError('Cannot locate nested CLR type "[clrType]" (simple name is "[clrType.name]").') else if potential inherits IType return potential else .throwError('Located CLR type spec "[clrType]" but got a [potential.englishName] instead of a type.')

As you can see, the bug is known but not fixed. Replace the code with something like this:

if potential is nil # comes up on MS Windows .NET 2.0 for multiple types when using System.Windows.Forms # error: Cannot locate nested CLR type "System.Windows.Forms.UnsafeNativeMethods+IOleControl" (simple name is "IOleControl"). if 'NativeMethods' in clrType.toString return _hack(clrType) #.throwError('Cannot locate nested CLR type "[clrType]" (simple name is "[clrType.name]").') return _hack(clrType) else if potential inherits IType return potential else .throwError('Located CLR type spec "[clrType]" but got a [potential.englishName] instead of a type.')

I know this is ugly and could probably bite you somewhere in other code, but it worked for me.  :D Recompile cobra (launching comp.bat) and replace the generated cobra.exe with your current compiler from the 0.8 version.

OpenFileDialog blocking

Another mysterious problem was caused by a simple call to OpenFileDialog.ShowDialog() which was blocking the whole application thread without showing any dialog. I investigated for hours to find the reason for this very weird behavioud and finally found out it was all my fault for forgetting something very basic...  :|

Therefore: always ensure that your Windows Forms application has the STAThread attribute set! It's easy to forget it because Visual Studio always generates those bits of code for you...

use System.Windows.Forms class MyApplication def main is shared has STAThread Application.enableVisualStyles Application.setCompatibleTextRenderingDefault(false) Application.run(MainForm())
Posted on Tuesday, November 04, 2008
310 Views
0 comments posted

Open Transport Tycoon

Just a couple of days after the public beta of Good Old Games (which will seriously jeopardize my ability to study anything this semester), I discovered the even more dangerous Open Transport Tycoon Deluxe! This officially declares war on all exam preparations I had in mind for the following months.  :D

Open Transport Tycoon Deluxe (OpenTTD for short) is an open-source clone of the original Transport Tycoon Deluxe engine: all loving 8 bit graphics are accurately reproduced, along with the interface and the well thought-out gameplay. The clone does not include the graphics and the music (you'll have to copy them from your copy of the game). It works perfectly on Vista, supports much higher resolutions than the original game and is an exemplary well behaved application in "windowed" mode (it doesn't block the mouse, can be freely moved and minimized).

Open Transport Tycoon

In order to install it you can get the latest stable release (0.6.3 at the time) from the project's online repository and copy the binaries somewhere on your computer (I hate installers). Then you need to copy the graphics from your original "Transport Tycoon Deluxe" disc (I bought my copy a couple of years ago, but it didn't work with my notebook's Radeon video adapter):

Copying the graphics files from the original disc to the OpenTTD folder

The selected files in the image can be found in the root folder on the disc. Simply copy them in the "data" subfolder of OpenTTD (or in one of the other suggested folders you'll find in the readme).

Then, in order to get the music working, you should be able to directly copy the "gm" folder on the disc to a newly created "gm" folder where you installed OpenTTD. Unfortunately, the DOS version of the game (and my version, for some unexplicable reason) includes the MIDI files as the packed archive "GM.CAT". Cirdan, an user of the OpenTTD forums, mercifully posted a simple C program that analyzes those CAT files and extracts the music files. I had to adapt the code to work on the Visual C++ compiler and to automatically generate the correct file names:

Download the source code (.C)

Put the file in some directory, along with the packed GM.CAT file. Compile it:

cl /MD gmext.c

and run the executable (you can also download the compiled utility directly if you don't want to compile it). This will (should) produce a lot of gm_ttXX.gm files (22 in total) that must be copied into the "OpenTTD/gm" folder.

The music folder with the etracted midi files

Now go enjoy Transport Tycoon in all its glory!  ;)

Posted on Saturday, October 25, 2008
Tagged as
297 Views
0 comments posted

ATi logo ATi has the good tradition of releasing a new set of video drivers each month, with performance improvements and fixes. Unfortunately owners of Radeon Mobility cards (on laptops) usually cannot benefit of these updates. Here I'll show you a simple workaround.

The problem

The monthly catalyst driver release from ATi's website cannot usually be installed on notebooks: because of some stupid vendor / license / OEM limitation, the installation will be blocked before completion and you'll be redirected to your laptop's vendor website in search for some updated drivers. This would be tolerable, if notebook vendors only updated the drivers on their websites once in a while... Usually you'll be stuck with some really old version for years.  :(

But there is hope... < Star Wars title song >

The solution

It is possible to actually fool the driver installer and let him think that your mobility card is actually supported by ATi. This requires a minor hack to the installer's .inf file (there used to be some kind of automated program that did the same thing, but it seems to have disappeared).

Unpack the installer

First of all, unpack the installer files to a directory of your choice. This is simply done by launching the installer you downloaded from ATi's website (the default directory should be C:\ATI\SUPPORT\[version]-[platform]-etc...). Once this is done, the installer will launch. You can abort it rightaway: if you go ahead it will abort as soon as it finds out that your card isn't supported.

Find out your hardware ID

In order to patch the .inf file, you must first find out what the unique ID of your graphical card looks like. In order to do this, simply open Windows' Device Manager, seek your card's entry, go into its properties and check the hardware details:

Device Manager screenshot

The numeric ID you see in the picture above is my graphical card's unique ID (an ATi Radeon Mobility X1700). Just copy it to the clipboard and close the device manager.

Get your hardware's chip name

Each graphical card is usually assembled putting a chip (the GPU) together with some memory and interconnecting the two with a bus (an ATi engineer would probably burst in laughter reading this, but...). Both chipset and memory are variable (type, size, frequency) and determine the final name under which your card is assembled and then sold. In order to install the right subset of the Catalyst drivers, you'll have to find out the exact codename of the chipset running your card.

To do this, you'll have to head to the ATi GPU comparison page on Wikipedia or the card's page on ati.com. In my case, my ATi Radeon Mobility X1700 actually features a RV535 chipset.

Patch the INF file

OK, now navigate back to the folder where you unpacked the driver installer and head to the directory Packages/Drivers/Display/LH_INF. You'll find a couple of files: open the bigger INF file (in the current driver version, the filename is CL_61008.inf) with notepad or a similar program. Ignore the header of the file and head down to the list of hardware identifiers (there's a lot of them). Now, simply try to spot a card similar to yours, mounting the SAME chipset of your card. For instance:

"Radeon X1700 FSC" = ati2mtag_RV535, PCI\VEN_1002&DEV_71C1&SUBSYS_0880174B

This line means that the card named "Radeon X1700 FSC" will load the driver for the "RV535" chipset. Again, in my case I searched for an "X1600" or "X1700" card and then picked the first line with "RV535" in it. Copy the whole line, paste it on a new line just below and replace the hardware ID with the one of your notebook's graphical card and the name of the card. You should have something like this:

... "Radeon X1650 Series Secondary" = ati2mtag_RV515, PCI\VEN_1002&DEV_71A1&SUBSYS_5921174B "Radeon X1700 FSC" = ati2mtag_RV535, PCI\VEN_1002&DEV_71C1&SUBSYS_0880174B "Mobility Radeon X1700" = ati2mtag_RV535, PCI\VEN_1002&DEV_71D5&SUBSYS_12421043 ...

Save and close the file.

Install the drivers!

That should be enough: launch the installer manually (launch Setup.exe in the driver's root folder, where you unpacked the installer, or update your drivers manually through the Windows device manager) and proceed as usual. The installer should recognize your hardware, will assume it is supported and then will install the driver for the chipset you specified. Hope that helps!

DISCLAIMER: as usual when you're doing something not foreseen by the installer, you could potentially destroy your operating system, your hardware, be killed in sleep by your mutated graphical card and so on... Eveything you do after reading this guide is at your own risk!

Posted on Saturday, April 19, 2008
Tagged as
295 Views
1 comments posted
Back to Klopfenstein.net
Clemens Klopfenstein Serena Kiefer Lukas Tiberio Klopfenstein Lorenz Cuno Klopfenstein
English German