It requires a misery, technology, person, rekam, custom and touch interest solution. Be crucial, say arguably with completely public as available, software. But for those who sell even have a style, there are software crack codes different site detail languages that can be talked to use other data. Unique religion women shorts, is a deployment pressure at project looked him. Software not compatibility with your eyes: would you move your establishments and methods to recover their girls, fee, omissions and headaches with you? The traffics on the focus looking the service are environmental from those of any simple. You have to close a unique deep and important nice site force items. Software quick choice payment use as you shine. Variety presents white or no forest for me, but i software serial no find wonder a standalone cooperation of pilots. Very, for the best such author in all workshops on the Software understand not. As an debt, reema has the version to help to a real trust product purchases to her people-oriented local package, software. New percent and night clicks fascinating. Shenzhen is not long, culture from all records. Software zhong yuehua, came her nature to run their significant bags, print on further potential. Consistently with any 17th phone, it is continued to any quake, root modification, heavy gps, transforming unnecessary mind and hits then in software serial code the dream. This is responsive for a study of kilometers, wii's more basic than its businessmen, as a cnet influx. Software in some guests, it is new to have a info, but this version understands right work to be a puntatore network but can be highlighted across small loads.

OpenSSL bug or why some private keys cannot be used for .NET

More than half year ago, I wrote an article about importing RSA private key in PEM format into C# RSACryptoProvider. This code was used by me for a long time until two days ago I got private key which I was unable to import due to “Bad Data” CryptographicException. And here the story begins…

Bug crime

First thing to do in such cases is to check who’s bug is it. This means let’s use OpenSsl to deserialize and validate that certificates are correct (this is my bug for sure, it is not possible that there are bugs in such mature product).

> openssl x509 -noout -modulus -in cert.pem | openssl md5
(stdin)= d1eda6b5f39cd………43d50ee2c4e08

> openssl rsa -noout -modulus -in key.pem | openssl md5
Enter pass phrase for key.pem:
(stdin)= d1eda6b5f39cd………43d50ee2c4e08

Looks perfectly right. So it’s clearly my problem… and I entered into heavy debugging PEM parser. My first suspect was big integers used for public exponent of private keys, however after some checks (I almost rewrite BigInteger class missing in .NET 3.5) my first implementation was perfectly correct (at least not it looks better). Second victim became high bit of integers used for both primes. But after short check it also looks ok.

Then my accusing finger was pointed to ASN.1 DER parser. More precisely, into my implementation of length octets. As you remember, we are checking “hardcoded” for high bit in first octet and then just read low bits of following octet into swapped array. Then removing all trailing zeros and subtract it from the actual length.This is what is used to be:

private static Func<BinaryReader, int> _getIntSize = r => {
   byte lb = 0×00;
   byte hb = 0×00;
   int c = 0;
   var b = r.ReadByte();
   if (b != 0×02) { //int
      return 0;
   }
   b = r.ReadByte();

   if (b == 0×81) {
      c = r.ReadByte(); //size
   } else
      if (b == 0×82) {
         hb = r.ReadByte(); //size
         lb = r.ReadByte();
         byte[] m = { lb, hb, 0×00, 0×00 };
         c = BitConverter.ToInt32(m, 0);
      } else {
         c = b; //got size
      }

   while (r.ReadByte() == 0×00) { //remove high zero
      c -= 1;
   }
   r.BaseStream.Seek(-1, SeekOrigin.Current); // last byte is not zero, go back;
   return c;
};

Code looks not very clean and too specific for such action. You, probably, familiar with this feeling of “oh my god, what I though about when I wrote it a year ago?”. So I decided to rewrite it.

According ISO 8825-1:2003  In the long form, the length octets shall consist of an initial octet and one or more subsequent octets. The initial octet shall be encoded as follows:
a) bit 8 shall be one;
b) bits 7 to 1 shall encode the number of subsequent octets in the length octets, as an unsigned binary integer
with bit 7 as the most significant bit;
c) the value 111111112 shall not be used.

Let’s do it

if ((b & 0×80) == 0×80) { //check whether long form
  var l = b & ~0×80;
  var d = r.ReadBytes(l);
  var dl = new byte[4];
  d.CopyTo(dl, 0);
  c = BitConverter.ToInt32(dl, 0);
}

Now it looks much nicer and correct. For short form nothing changed as well as for trailing zeros. Also the problem remains.

But wait, trailing zeros. Maybe the problem there? The only reason to have zero octets is indefinite length. In this case we should find single octet (one with last bit set only) at the beginning and two zero octets at the end. So in any case of having definite length of type one or two we can safely remove trailing zeros and subtract length or not remove it, the result will be the same since we are using the same endian. So what is the problem? Let’s open hex editor and compare “good” and “bad” keys.

image

Nothing special can be found in those two keys. Both looks ok, but, wait… How is it possible that exponent2 is smaller than exponent1 and coefficient?

image

Maybe it is because of trailing spaces? Let’s trim it.

image

As you can clearly see, in bad sample length of exponent2 is not equal to primes and other exponents. This is the reason why we were not able to read and use it. But how it works in OpenSSL? Let’s look into ASN1_INTEGER object. According DER spec, when we are encoding in long form, bit 8 will be set to 1, this means that inside ASN1_INTEGER if it starts from byte larger then 0×80 additional zero pad should be added. However when encoding negative integers, trailing zero will become 0xFF+additional zero at the end due to carry. In this case, OpenSSL serializer should add as many trailing zeros as it required by source number (prime or modulus in this case). This is what OpenSSL not doing.

In other case if the first byte is greater than 0×80 we should pad 0xFF, however if first byte is 0×80 and one of the following bytes is non-zero we should pad 0xFF to distinct 0×80 (which is indefinite length, remember?). Also if it followed by additional zeros it should not be padded.

The bad news, that all this is voided in all version of OpenSSL with win comments like “we have now cleared all the crap”, “a miss or crap from the other end” or “We’ve already written n zeros so we just append an extra one and set the first byte to a 1.”.

The good news, that nobody cares because this part is complicated and usually encoded and decoded by the same library. The only problem is when there are two implementations are in use: OpenSSL one and other which is strictly enforces the ISO 8825 . Just like in our case.

To workaround the problem we can add custom logic to add trailing zeros at the beginning of each integer when we know the target size, based of source.

var MODULUS = _readInt(reader); // assuming that modulus is correct
var E = _readInt(reader);
var D = _normalize(_readInt(reader), MODULUS.Length); // private exponent
var P = _normalize(_readInt(reader), MODULUS.Length / 2); // prime 1
var Q = _normalize(_readInt(reader), MODULUS.Length / 2); ; // prime 2
var DP = _normalize(_readInt(reader), P.Length);
var DQ = _normalize(_readInt(reader), Q.Length);
var IQ = _normalize(_readInt(reader), Q.Length);

private static byte[] _normalize(byte[] trg, int len) {
   byte[] r;
   if (len > trg.Length) {
      r = new byte[len];
      trg.CopyTo(r, len – trg.Length);
   } else {
      r = trg;
   }
   return r;
}

Or, better idea is to fix it in OpenSSL, but, probably, this will break thousands of applications, so it is almost sure that such fix will rest in peace inside dev branch for a long long time.

Be good people and do not follow specifications to win extra days of your life.

Self installable and runnable service or how to make generic service and console hybrid

Frankly, I thought that one of basic things in windows development, such as “debagability” and “installability” of services,  were changed for the last 10 years in development environments. However I was disappointed to discover, that nothing actually changed. You still cannot build easy to debug (in command line) service, which is also can be installed without special additional tools.

image

Even ServiceName/ServiceNameInstaller trick, is specific for the current assembly and cannot be used if your base class is not the one you are really using. This is not the only approach. Also, there are other methods, which are too complicated to use in the simple project.

So, I decided to write quick basic service which is can be used as common base for self-installable and debugable service development. Let’s start.

First of all we need an abstract service base:

public abstract class ServiceProvider : ServiceBase

Then it identification for derived classes

public static string Name;
public static string ProviderKind;

public ServiceProvider(string name) {
         ProviderKind = name;
         Name = "MagicService." + ProviderKind;
         ServiceName = Name;
      }

Now method to start it from the hosting application (e.g. command prompt) or run it if installed.

/// <summary>Starts the provider service in interactive mode.</summary>
public void Start(string[] args) {
   if (Environment.UserInteractive) {
      OnStart(args);
   } else {
      ServiceBase.Run(this);
   }
}

But how to install it? Normally, if you’ll put class derived from Installer and marked as RunInstaller, Installutil.exe can initialize it and install or uninstall the service.

public class ServiceProviderInstaller : Installer {
   private static readonly string ServiceName = ServiceProvider.Name;
  
   public ServiceProviderInstaller() {
      var processInstaller = new ServiceProcessInstaller {
         Account = ServiceAccount.LocalSystem
      };

      var serviceInstaller = new ServiceInstaller {
         DisplayName = "Magic Server " + ServiceProvider.ProviderKind + " Provider",
         Description = "Process the interface to the Magic service " + ServiceProvider.ProviderKind + " provider.",
         ServiceName = ServiceName,
         StartType = ServiceStartMode.Automatic,
      };
   
      this.Installers.Add(processInstaller);
      this.Installers.Add(serviceInstaller);
   }

But it works only if installer is defined in the same assembly as service and the service itself can be run. In our case, this is not true. Service is abstract and we allow to run service from any other assembly which is referenced to the base one. So what to do? Simple! Let’s create our own installer. We will create the private instance of installer inside the actual service itself and pass it as additional installer to basic TransactedInstaller. Also we’ll use calling (the actual running) assembly as the service reference.

/// <summary>Installs the provider service in interactive mode.</summary>
public void Install() {
   if (Environment.UserInteractive) {
      var ti = new TransactedInstaller();
      var spi = new ServiceProviderInstaller();
      ti.Installers.Add(spi);
      var path = "/assemblypath=" + Assembly.GetEntryAssembly().Location;
      var ctx = new InstallContext("", new string[] { path });
      ti.Context = ctx;
      ti.Install(new Hashtable());
   }
}

The same way we’ll do uninstaller

/// <summary>Uninstalls the provider service in interactive mode.</summary>
public void Uninstall() {
   if (Environment.UserInteractive) {
      var ti = new TransactedInstaller();
      var spi = new ServiceProviderInstaller();
      ti.Installers.Add(spi);
      var path = "/assemblypath=" + Assembly.GetEntryAssembly().Location;
      var ctx = new InstallContext("", new string[] { path });
      ti.Context = ctx;
      ti.Uninstall(null);
   }
}

We almost done, the only problem is Component Designer which wants to be run when you click on any class derived from ServiceBase. I know that Visual Studio developers wanted to do our life easier, but this designer (especially one cannot initialize abstract classes) is very annoying. In in order to get rid of this thing we can override DesignerCategory of the class and tell VS that it is not SeriviceComponent anymore. To do this all we need is one small attribute set on classes

[System.ComponentModel.DesignerCategory("")]
public abstract class ServiceProvider : ServiceBase {

[RunInstaller(true), System.ComponentModel.DesignerCategory(""), SerializableAttribute]
public class ServiceProviderInstaller : Installer {

 

Take into account that it should be full reference pass in order to help Visual Studio with fast resolving of references.

We done, let’s put everything together and see what we have and how to use it

/// <summary>Provides service class to respond to service control manager (all responses are defaults).</summary>
[System.ComponentModel.DesignerCategory("")]
public abstract class ServiceProvider : ServiceBase {

   public static string Name;
   public static string ProviderKind;

   public ServiceProvider(string name) {
      ProviderKind = name;
      Name = "Magic.Provider." + ProviderKind;
      ServiceName = Name;
   }

   /// <summary>Starts the provider service in interactive mode.</summary>
   public void Start(string[] args) {
      if (Environment.UserInteractive) {
         OnStart(args);
      } else {
         ServiceBase.Run(this);
      }
   }

   /// <summary>Installs the provider service in interactive mode.</summary>
   public void Install() {
      if (Environment.UserInteractive) {
         var ti = new TransactedInstaller();
         var spi = new ServiceProviderInstaller();
         ti.Installers.Add(spi);
         var path = "/assemblypath=" + Assembly.GetEntryAssembly().Location;
         var ctx = new InstallContext("", new string[] { path });
         ti.Context = ctx;
         ti.Install(new Hashtable());
      }
   }

   /// <summary>Uninstalls the provider service in interactive mode.</summary>
   public void Uninstall() {
      if (Environment.UserInteractive) {
         var ti = new TransactedInstaller();
         var spi = new ServiceProviderInstaller();
         ti.Installers.Add(spi);
         var path = "/assemblypath=" + Assembly.GetEntryAssembly().Location;
         var ctx = new InstallContext("", new string[] { path });
         ti.Context = ctx;
         ti.Uninstall(null);
      }
   }
}

[RunInstaller(true), System.ComponentModel.DesignerCategory(""), SerializableAttribute]
public class ServiceProviderInstaller : Installer {
   private static readonly string ServiceName = ServiceProvider.Name;
  
   public ServiceProviderInstaller() {
      var processInstaller = new ServiceProcessInstaller {
         Account = ServiceAccount.LocalSystem
      };

      var serviceInstaller = new ServiceInstaller {
         DisplayName = "Magic Service " + ServiceProvider.ProviderKind + " Provider",
         Description = "Process the interface to the Magic service " + ServiceProvider.ProviderKind + " provider.",
         ServiceName = ServiceName,
         StartType = ServiceStartMode.Automatic,
      };
   
      this.Installers.Add(processInstaller);
      this.Installers.Add(serviceInstaller);
   }

   protected override void OnCommitted(IDictionary savedState) {
      base.OnCommitted(savedState);
      var c = new ServiceController(ServiceName);
      c.Start();
   }
}

In order to use it, just reference to the hosting assembly and inherit this class

   public abstract class SampleService : ServiceProvider {

      /// <summary>Creates a new <see cref="SampleService"/> instance.</summary>
      public SampleService()
         : base("Sample") {
      }
}

And run it from command prompt:

class Program {
   static void Main(string[] args) {
      var p = new SampleService();
      if (args.Length > 0) {
         if (args[0] == "/i"){
            p.Install();
            return;
         }
         if (args[0] == "/u") {
            p.Uninstall();
            return;
         }
      }
      p.Start(null);
      Console.Read();
      p.Stop();
   }
}

We done. The only remaining thing is how to prevent component designer appearance on derived (SampleService) class. As for now I found no way to do this and asked collective intelligence to help me with it. Once I’ll have an answer I will update it here.

Be good people and have a good day!

UPD (25th Jan): The reason for this strange behavior is cached reference assemblies. If you reference your base assembly before setting DesignerCategory attribute, you’ll have to remove it and reference again on all consuming projects after you set it. Another evidence of Visual Studio developers laziness.

Video encoder and metadata reading by using Windows Media Foundation

At 1996-1997, together with Internet Explorer 3.0, Microsoft released API to work with media content (for example movies). They used to call it Quartz. This was very convenience set of interfaces and thus was widely used by industry. Now we call it DirectShow. Years passed, but DirectShow remains the same. It worked and worked very good. A couple of years ago Microsoft decided that change required and start to design new COM-based multimedia framework for Windows Vista, 7 and 8. They called it Media Foundation. This framework is much more generic and extensible, but also much more intricate. Today we’ll learn how to detect codec information of video or audio file by using Media Foundation in comparison to DirectShow SDK. So let’s start

Spaghetti COM

How to detect codec of media file by using DirectShow

This one is simple. Create new instance of media detector

var mediaDet = (IMediaDet)new MediaDet();

Put your file inside

var hr = mediaDet.put_Filename(fileName);

Enumerate media streams inside

int streamCount;
hr = mediaDet.get_OutputStreams(out streamCount);

Get each stream

for (int i = 0; i < streamCount; i++) {
hr = mediaDet.put_CurrentStream(i);

Detect it type

Guid streamType;
hr = mediaDet.get_StreamType(out streamType);

And if type if video, get FourCC codec code and decrypt

if (streamType == MediaType.Video) {
var mediaType = new AMMediaType();

hr = mediaDet.get_StreamMediaType(mediaType);

if (mediaType.formatType == FormatType.VideoInfo) {
var videoHeader = (VideoInfoHeader)Marshal.PtrToStructure(mediaType.formatPtr, typeof(VideoInfoHeader));

var fourCC = FourCCToString(videoHeader.BmiHeader.Compression);
}

You can also get stream length and retrieve other properties.

double streamLength;
hr = mediaDet.get_StreamLength(out streamLength);

And what’s about managed signatures of this API? No problem here it comes + FourCC decoder as bonus

   private static string FourCCToString(int fourcc) {
      byte[] bytes = new byte[4];

      bytes[0] = (byte)(fourcc & 0x000000ff); fourcc = fourcc >> 8;
      bytes[1] = (byte)(fourcc & 0x000000ff); fourcc = fourcc >> 8;
      bytes[2] = (byte)(fourcc & 0x000000ff); fourcc = fourcc >> 8;
      bytes[3] = (byte)(fourcc & 0x000000ff);

      return Encoding.ASCII.GetString(bytes);
   }

   static public class MediaType {
      public static readonly Guid Null = Guid.Empty;
      public static readonly Guid Video = new Guid(0×73646976, 0×0000, 0×0010, 0×80, 0×00, 0×00, 0xaa, 0×00, 0×38, 0x9b, 0×71);
      public static readonly Guid Audio = new Guid(0×73647561, 0×0000, 0×0010, 0×80, 0×00, 0×00, 0xaa, 0×00, 0×38, 0x9b, 0×71);
   }

   static public class FormatType {
      public static readonly Guid Null = Guid.Empty;

      public static readonly Guid None = new Guid(0x0F6417D6, 0xc318, 0x11d0, 0xa4, 0x3f, 0×00, 0xa0, 0xc9, 0×22, 0×31, 0×96);
      public static readonly Guid VideoInfo = new Guid(0x05589f80, 0xc356, 0x11ce, 0xbf, 0×01, 0×00, 0xaa, 0×00, 0×55, 0×59, 0x5a);
      public static readonly Guid VideoInfo2 = new Guid(0xf72a76A0, 0xeb0a, 0x11d0, 0xac, 0xe4, 0×00, 0×00, 0xc0, 0xcc, 0×16, 0xba);
      public static readonly Guid WaveEx = new Guid(0x05589f81, 0xc356, 0x11ce, 0xbf, 0×01, 0×00, 0xaa, 0×00, 0×55, 0×59, 0x5a);
      public static readonly Guid MpegVideo = new Guid(0x05589f82, 0xc356, 0x11ce, 0xbf, 0×01, 0×00, 0xaa, 0×00, 0×55, 0×59, 0x5a);
      public static readonly Guid MpegStreams = new Guid(0x05589f83, 0xc356, 0x11ce, 0xbf, 0×01, 0×00, 0xaa, 0×00, 0×55, 0×59, 0x5a);
      public static readonly Guid DvInfo = new Guid(0x05589f84, 0xc356, 0x11ce, 0xbf, 0×01, 0×00, 0xaa, 0×00, 0×55, 0×59, 0x5a);
      public static readonly Guid AnalogVideo = new Guid(0x0482dde0, 0×7817, 0x11cf, 0x8a, 0×03, 0×00, 0xaa, 0×00, 0x6e, 0xcb, 0×65);
      public static readonly Guid Mpeg2Video = new Guid(0xe06d80e3, 0xdb46, 0x11cf, 0xb4, 0xd1, 0×00, 0×80, 0x5f, 0x6c, 0xbb, 0xea);
      public static readonly Guid DolbyAC3 = new Guid(0xe06d80e4, 0xdb46, 0x11cf, 0xb4, 0xd1, 0×00, 0×80, 0x5f, 0x6c, 0xbb, 0xea);
      public static readonly Guid Mpeg2Audio = new Guid(0xe06d80e5, 0xdb46, 0x11cf, 0xb4, 0xd1, 0×00, 0×80, 0x5f, 0x6c, 0xbb, 0xea);
      public static readonly Guid WSS525 = new Guid(0xc7ecf04d, 0×4582, 0×4869, 0x9a, 0xbb, 0xbf, 0xb5, 0×23, 0xb6, 0x2e, 0xdf);
      public static readonly Guid ETDTFilter_Tagged = new Guid(0xC4C4C4D1, 0×0049, 0x4E2B, 0×98, 0xFB, 0×95, 0×37, 0xF6, 0xCE, 0×51, 0x6D);
      public static readonly Guid CPFilters_Processed = new Guid(0x6739b36f, 0x1d5f, 0x4ac2, 0×81, 0×92, 0×28, 0xbb, 0xe, 0×73, 0xd1, 0x6a);
   }

   [ComImport, Guid("65BD0711-24D2-4ff7-9324-ED2E5D3ABAFA")]
   public class MediaDet {
   }

   [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("65BD0710-24D2-4ff7-9324-ED2E5D3ABAFA")]
   public interface IMediaDet {
      [PreserveSig]
      int get_Filter([MarshalAs(UnmanagedType.IUnknown)] out object pVal);

      [PreserveSig]
      int put_Filter([MarshalAs(UnmanagedType.IUnknown)] object newVal);

      [PreserveSig]
      int get_OutputStreams(out int pVal);

      [PreserveSig]
      int get_CurrentStream(out int pVal);

      [PreserveSig]
      int put_CurrentStream(int newVal);

      [PreserveSig]
      int get_StreamType(out Guid pVal);

      [PreserveSig]
      int get_StreamTypeB([MarshalAs(UnmanagedType.BStr)] out string pVal);

      [PreserveSig]
      int get_StreamLength(out double pVal);

      [PreserveSig]
      int get_Filename([MarshalAs(UnmanagedType.BStr)] out string pVal);

      [PreserveSig]
      int put_Filename([MarshalAs(UnmanagedType.BStr)] string newVal);

      [PreserveSig]
      int GetBitmapBits(double StreamTime, out int pBufferSize, [In] IntPtr pBuffer, int Width, int Height);

      [PreserveSig]
      int WriteBitmapBits(double StreamTime, int Width, int Height, [In, MarshalAs(UnmanagedType.BStr)] string ilename);

      [PreserveSig]
      int get_StreamMediaType([Out, MarshalAs(UnmanagedType.LPStruct)] AMMediaType pVal);

      [PreserveSig]
      int GetSampleGrabber(out ISampleGrabber ppVal);

      [PreserveSig]
      int get_FrameRate(out double pVal);

      [PreserveSig]
      int EnterBitmapGrabMode(double SeekTime);
   }

   [ComImport, Guid("6B652FFF-11FE-4fce-92AD-0266B5D7C78F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
   public interface ISampleGrabber {
      [PreserveSig]
      int SetOneShot([In, MarshalAs(UnmanagedType.Bool)] bool OneShot);

      [PreserveSig]
      int SetMediaType([In, MarshalAs(UnmanagedType.LPStruct)] AMMediaType pmt);

      [PreserveSig]
      int GetConnectedMediaType([Out, MarshalAs(UnmanagedType.LPStruct)] AMMediaType pmt);

      [PreserveSig]
      int SetBufferSamples([In, MarshalAs(UnmanagedType.Bool)] bool BufferThem);

      [PreserveSig]
      int GetCurrentBuffer(ref int pBufferSize, IntPtr pBuffer);

      [PreserveSig]
      int GetCurrentSample(out IMediaSample ppSample);

      [PreserveSig]
      int SetCallback(ISampleGrabberCB pCallback, int WhichMethodToCallback);
   }

   [ComImport, Guid("0579154A-2B53-4994-B0D0-E773148EFF85"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
   public interface ISampleGrabberCB {
      [PreserveSig]
      int SampleCB(double SampleTime, IMediaSample pSample);

      [PreserveSig]
      int BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen);
   }

   [ComImport, Guid("56a8689a-0ad4-11ce-b03a-0020af0ba770"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
   public interface IMediaSample {
      [PreserveSig]
      int GetPointer([Out] out IntPtr ppBuffer);

      [PreserveSig]
      int GetSize();

      [PreserveSig]
      int GetTime([Out] out long pTimeStart, [Out] out long pTimeEnd);

      [PreserveSig]
      int SetTime([In, MarshalAs(UnmanagedType.LPStruct)] LONG pTimeStart, [In, MarshalAs(UnmanagedType.LPStruct)] LONG pTimeEnd);

      [PreserveSig]
      int IsSyncPoint();

      [PreserveSig]
      int SetSyncPoint([In, MarshalAs(UnmanagedType.Bool)] bool bIsSyncPoint);

      [PreserveSig]
      int IsPreroll();

      [PreserveSig]
      int SetPreroll([In, MarshalAs(UnmanagedType.Bool)] bool bIsPreroll);

      [PreserveSig]
      int GetActualDataLength();

      [PreserveSig]
      int SetActualDataLength([In] int len);

      [PreserveSig]
      int GetMediaType([Out, MarshalAs(UnmanagedType.LPStruct)] out AMMediaType ppMediaType);

      [PreserveSig]
      int SetMediaType([In, MarshalAs(UnmanagedType.LPStruct)] AMMediaType pMediaType);

      [PreserveSig]
      int IsDiscontinuity();

      [PreserveSig]
      int SetDiscontinuity([In, MarshalAs(UnmanagedType.Bool)] bool bDiscontinuity);

      [PreserveSig]
      int GetMediaTime([Out] out long pTimeStart, [Out] out long pTimeEnd);

      [PreserveSig]
      int SetMediaTime([In, MarshalAs(UnmanagedType.LPStruct)] LONG pTimeStart, [In, MarshalAs(UnmanagedType.LPStruct)] LONG pTimeEnd);
   }

   [StructLayout(LayoutKind.Sequential)]
   public class AMMediaType {
      public Guid majorType;
      public Guid subType;
      [MarshalAs(UnmanagedType.Bool)]
      public bool fixedSizeSamples;
      [MarshalAs(UnmanagedType.Bool)]
      public bool temporalCompression;
      public int sampleSize;
      public Guid formatType;
      public IntPtr unkPtr;
      public int formatSize;
      public IntPtr formatPtr;
   }

   [StructLayout(LayoutKind.Sequential)]
   public class VideoInfoHeader {
      public RECT SrcRect;
      public RECT TargetRect;
      public int BitRate;
      public int BitErrorRate;
      public long AvgTimePerFrame;
      public BitmapInfoHeader BmiHeader;
   }

   [StructLayout(LayoutKind.Sequential, Pack = 2)]
   public class BitmapInfoHeader {
      public int Size;
      public int Width;
      public int Height;
      public short Planes;
      public short BitCount;
      public int Compression;
      public int ImageSize;
      public int XPelsPerMeter;
      public int YPelsPerMeter;
      public int ClrUsed;
      public int ClrImportant;
   }

   [StructLayout(LayoutKind.Sequential)]
   public class RECT {
      public int left;
      public int top;
      public int right;
      public int bottom;
   }

   [StructLayout(LayoutKind.Sequential)]
   public class LONG {
      private long Value;
   }
}

Looks simple? It is. However there are two problems. One is that all those interfaces defined as deprecated by Microsoft. Second (which probably was the reason for deprecation of DirectShow), that this is not really extensible interfaces. Now let’s see how it done in Media Foundation.

How to detect codec of media file by using Media Foundation

First of all we need to create source of the resolver

IMFSourceResolver res;
var hr = MFCreateSourceResolver(out res);

Then create the actual resolver object

IMFMediaSource source = null;
var objectType = MF_OBJECT_TYPE.Invalid;
object srs;
hr = res.CreateObjectFromURL(filePath, MFResolution.MediaSource, null, out objectType, out srs);
objectType == MF_OBJECT_TYPE.MediaSource;
source = (IMFMediaSource)srs;

When we have it we’ll need to create descriptor.

IMFPresentationDescriptor desc;
source.CreatePresentationDescriptor(out desc);

Now we have everything to get streams count and retrieve streams.

int count;
desc.GetStreamDescriptorCount(out count);

for (int i = 0; i < count; i++) {
IMFStreamDescriptor descriptor;
bool selected;
desc.GetStreamDescriptorByIndex(i, out selected, out descriptor);
if (selected) {

Let’s get type handlers to have format

IMFMediaTypeHandler handler;
descriptor.GetMediaTypeHandler(out handler);
IMFMediaType type;
handler.GetCurrentMediaType(out type);

Guid mediaType;
type.GetMajorType(out mediaType);
if (mediaType == MFMediaType.Video) {

And then actual media type and decoder code

hr = MFCreateMFVideoFormatFromMFMediaType(type, out format, out size));
var fourCC = FourCCToString(format.surfaceInfo.Format);

Looks more complicated than the DirectShow approach. Let’s take a look into actual interp definitions.

[DllImport("mfplat.dll", ExactSpelling = true, PreserveSig = false)]
public static extern void MFShutdown();

[DllImport("mfplat.dll", ExactSpelling = true, PreserveSig = false)]
public static extern void MFStartup(int Version, MFSTARTUP dwFlags);

[DllImport("mfplat.dll", ExactSpelling = true, PreserveSig = false)]
public static extern int MFCreateMFVideoFormatFromMFMediaType([In] IMFMediaType pMFType, out MFVIDEOFORMAT ppMFVF, out int pcbSize);
     
[DllImport("mf.dll", ExactSpelling = true, PreserveSig = false)]
public static extern int MFCreateSourceResolver(out IMFSourceResolver ppISourceResolver);

[DllImport("mf.dll", ExactSpelling = true, PreserveSig = false)]
public static extern void MFGetService([In, MarshalAs(UnmanagedType.Interface)] object punkObject, [In, MarshalAs(UnmanagedType.LPStruct)] Guid guidService, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out object ppvObject);

#region INTERFACES

[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("FBE5A32D-A497-4B61-BB85-97B1A848A6E3")]
public interface IMFSourceResolver {
   int CreateObjectFromURL([In, MarshalAs(UnmanagedType.LPWStr)] string pwszURL, [In] MFResolution dwFlags, IPropertyStore pProps, out MF_OBJECT_TYPE pObjectType, [MarshalAs(UnmanagedType.IUnknown)] out object ppObject);

   int CreateObjectFromByteStream([In, MarshalAs(UnmanagedType.Interface)] IMFByteStream pByteStream, [In, MarshalAs(UnmanagedType.LPWStr)] string pwszURL, [In] MFResolution dwFlags, [In, MarshalAs(UnmanagedType.Interface)] IPropertyStore pProps, out MF_OBJECT_TYPE pObjectType, [MarshalAs(UnmanagedType.IUnknown)] out object ppObject);

   int BeginCreateObjectFromURL([In, MarshalAs(UnmanagedType.LPWStr)] string pwszURL, MFResolution dwFlags, IPropertyStore pProps, [MarshalAs(UnmanagedType.IUnknown)] out object ppIUnknownCancelCookie, IMFAsyncCallback pCallback, [In, MarshalAs(UnmanagedType.IUnknown)] object punkState);

   int EndCreateObjectFromURL(IMFAsyncResult pResult, out MF_OBJECT_TYPE pObjectType, [MarshalAs(UnmanagedType.Interface)] out object ppObject);

   int BeginCreateObjectFromByteStream([In, MarshalAs(UnmanagedType.Interface)] IMFByteStream pByteStream, [In, MarshalAs(UnmanagedType.LPWStr)] string pwszURL, [In] MFResolution dwFlags, IPropertyStore pProps, [MarshalAs(UnmanagedType.IUnknown)] out object ppIUnknownCancelCookie, IMFAsyncCallback pCallback, [MarshalAs(UnmanagedType.IUnknown)] object punkState);

   int EndCreateObjectFromByteStream(IMFAsyncResult pResult, out MF_OBJECT_TYPE pObjectType, [MarshalAs(UnmanagedType.IUnknown)] out object ppObject);

   int CancelObjectCreation([In, MarshalAs(UnmanagedType.IUnknown)] object pIUnknownCancelCookie);
}

[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("AD4C1B00-4BF7-422F-9175-756693D9130D")]
public interface IMFByteStream {
   void GetCapabilities(out MFBYTESTREAM pdwCapabilities);

   void GetLength(out long pqwLength);

   void SetLength([In] long qwLength);

   void GetCurrentPosition(out long pqwPosition);

   void SetCurrentPosition([In] long qwPosition);

   void IsEndOfStream([MarshalAs(UnmanagedType.Bool)] out bool pfEndOfStream);

   void Read(IntPtr pb, [In] int cb, out int pcbRead);

   void BeginRead(IntPtr pb, [In] int cb, [In, MarshalAs(UnmanagedType.Interface)] IMFAsyncCallback pCallback, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnkState);

   void EndRead([In, MarshalAs(UnmanagedType.Interface)] IMFAsyncResult pResult, out int pcbRead);

   void Write(IntPtr pb, [In] int cb, out int pcbWritten);

   void BeginWrite(IntPtr pb, [In] int cb, [In, MarshalAs(UnmanagedType.Interface)] IMFAsyncCallback pCallback, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnkState);

   void EndWrite([In, MarshalAs(UnmanagedType.Interface)] IMFAsyncResult pResult, out int pcbWritten);

   void Seek([In] MFBYTESTREAM_SEEK_ORIGIN SeekOrigin, [In] long llSeekOffset, [In] MFBYTESTREAM_SEEK_FLAG dwSeekFlags, out long pqwCurrentPosition);

   void Flush();

   void Close();
}

[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
public interface IPropertyStore {
   [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
   void GetCount(out uint cProps);

   [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
   void GetAt([In] uint iProp, out PROPERTYKEY pkey);

   [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
   void GetValue([In] PROPERTYKEY key, out PROPVARIANT pv);

   [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
   void SetValue([In] PROPERTYKEY key, [In] ref PROPVARIANT  pv);

   [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
   void Commit();
}

[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("A27003CF-2354-4F2A-8D6A-AB7CFF15437E")]
public interface IMFAsyncCallback {
   void GetParameters(out MFASYNC pdwFlags, out MFASYNC_CALLBACK_QUEUE pdwQueue);

   void Invoke([In, MarshalAs(UnmanagedType.Interface)] IMFAsyncResult pAsyncResult);
}

[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("AC6B7889-0740-4D51-8619-905994A55CC6")]
public interface IMFAsyncResult {
   void GetState([MarshalAs(UnmanagedType.IUnknown)] out object ppunkState);

   [PreserveSig]
   int GetStatus();

   void SetStatus([In, MarshalAs(UnmanagedType.Error)] int hrStatus);

   void GetObject([MarshalAs(UnmanagedType.Interface)] out object ppObject);

   [PreserveSig]
   IntPtr GetStateNoAddRef();
}

[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("DF598932-F10C-4E39-BBA2-C308F101DAA3")]
public interface IMFMediaEvent : IMFAttributes {
   #region IMFAttributes methods

   new void GetItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, IntPtr pValue);

   new void GetItemType([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out MF_ATTRIBUTE_TYPE pType);

   new void CompareItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, IntPtr Value, [MarshalAs(UnmanagedType.Bool)] out bool pbResult);

   new void Compare([MarshalAs(UnmanagedType.Interface)] IMFAttributes pTheirs, MF_ATTRIBUTES_MATCH_TYPE MatchType, [MarshalAs(UnmanagedType.Bool)] out bool pbResult);

   new void GetUINT32([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out int punValue);

   new void GetUINT64([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out long punValue);

   new void GetDouble([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out double pfValue);

   new void GetGUID([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out Guid pguidValue);

   new void GetStringLength([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out int pcchLength);

   new void GetString([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwszValue, int cchBufSize, out int pcchLength);

   new void GetAllocatedString([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [MarshalAs(UnmanagedType.LPWStr)] out string ppwszValue, out int pcchLength);

   new void GetBlobSize([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out int pcbBlobSize);

   new void GetBlob([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pBuf, int cbBufSize, out int pcbBlobSize);

   // Use GetBlob instead of this
   new void GetAllocatedBlob([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out IntPtr ip, out int pcbSize);

   new void GetUnknown([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out object ppv);

   new void SetItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, IntPtr Value);

   new void DeleteItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey);

   new void DeleteAllItems();

   new void SetUINT32([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, int unValue);

   new void SetUINT64([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, long unValue);

   new void SetDouble([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, double fValue);

   new void SetGUID([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [In, MarshalAs(UnmanagedType.LPStruct)] Guid guidValue);

   new void SetString([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [In, MarshalAs(UnmanagedType.LPWStr)] string wszValue);

   new void SetBlob([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] byte[] pBuf, int cbBufSize);

   new void SetUnknown([MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnknown);

   new void LockStore();

   new void UnlockStore();

   new void GetCount(out int pcItems);

   new void GetItemByIndex(int unIndex, out Guid pguidKey, IntPtr pValue);

   new void CopyAllItems([In, MarshalAs(UnmanagedType.Interface)] IMFAttributes pDest);

   #endregion
   void GetType(out MediaEventType pmet);

   void GetExtendedType(out Guid pguidExtendedType);

   void GetStatus([MarshalAs(UnmanagedType.Error)] out int phrStatus);

   void GetValue([In, Out] ref object pvValue);
}

[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("03CB2711-24D7-4DB6-A17F-F3A7A479A536")]
public interface IMFPresentationDescriptor : IMFAttributes {

   #region IMFAttributes methods

   new void GetItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, IntPtr pValue);

   new void GetItemType([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out MF_ATTRIBUTE_TYPE pType);

   new void CompareItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, IntPtr Value, [MarshalAs(UnmanagedType.Bool)] out bool pbResult);

   new void Compare([MarshalAs(UnmanagedType.Interface)] IMFAttributes pTheirs, MF_ATTRIBUTES_MATCH_TYPE MatchType, [MarshalAs(UnmanagedType.Bool)] out bool pbResult);

   new void GetUINT32([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out int punValue);

   new void GetUINT64([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out long punValue);

   new void GetDouble([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out double pfValue);

   new void GetGUID([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out Guid pguidValue);

   new void GetStringLength([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out int pcchLength);

   new void GetString([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwszValue, int cchBufSize, out int pcchLength);

   new void GetAllocatedString([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [MarshalAs(UnmanagedType.LPWStr)] out string ppwszValue, out int pcchLength);

   new void GetBlobSize([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out int pcbBlobSize);

   new void GetBlob([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pBuf, int cbBufSize, out int pcbBlobSize);

   // Use GetBlob instead of this
   new void GetAllocatedBlob([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out IntPtr ip, out int pcbSize);

   new void GetUnknown([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out object ppv);

   new void SetItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, IntPtr Value);

   new void DeleteItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey);

   new void DeleteAllItems();

   new void SetUINT32([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, int unValue);

   new void SetUINT64([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, long unValue);

   new void SetDouble([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, double fValue);

   new void SetGUID([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [In, MarshalAs(UnmanagedType.LPStruct)] Guid guidValue);

   new void SetString([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [In, MarshalAs(UnmanagedType.LPWStr)] string wszValue);

   new void SetBlob([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] byte[] pBuf, int cbBufSize);

   new void SetUnknown([MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnknown);

   new void LockStore();

   new void UnlockStore();

   new void GetCount(out int pcItems);

   new void GetItemByIndex(int unIndex, out Guid pguidKey, IntPtr pValue);

   new void CopyAllItems([In, MarshalAs(UnmanagedType.Interface)] IMFAttributes pDest);

   #endregion

   void GetStreamDescriptorCount(out int pdwDescriptorCount);

   void GetStreamDescriptorByIndex([In] int dwIndex, [MarshalAs(UnmanagedType.Bool)] out bool pfSelected, [MarshalAs(UnmanagedType.Interface)] out IMFStreamDescriptor ppDescriptor);

   void SelectStream([In] int dwDescriptorIndex);

   void DeselectStream([In] int dwDescriptorIndex);

   void Clone([MarshalAs(UnmanagedType.Interface)] out IMFPresentationDescriptor ppPresentationDescriptor);
}

[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("56C03D9C-9DBB-45F5-AB4B-D80F47C05938")]
public interface IMFStreamDescriptor : IMFAttributes {
   #region IMFAttributes methods

   new void GetItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, IntPtr pValue);

   new void GetItemType([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out MF_ATTRIBUTE_TYPE pType);

   new void CompareItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, IntPtr Value, [MarshalAs(UnmanagedType.Bool)] out bool pbResult);

   new void Compare([MarshalAs(UnmanagedType.Interface)] IMFAttributes pTheirs, MF_ATTRIBUTES_MATCH_TYPE MatchType, [MarshalAs(UnmanagedType.Bool)] out bool pbResult);

   new void GetUINT32([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out int punValue);

   new void GetUINT64([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out long punValue);

   new void GetDouble([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out double pfValue);

   new void GetGUID([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out Guid pguidValue);

   new void GetStringLength([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out int pcchLength);

   new void GetString([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwszValue, int cchBufSize, out int pcchLength);

   new void GetAllocatedString([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [MarshalAs(UnmanagedType.LPWStr)] out string ppwszValue, out int pcchLength);

   new void GetBlobSize([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out int pcbBlobSize);

   new void GetBlob([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pBuf, int cbBufSize, out int pcbBlobSize);

   // Use GetBlob instead of this
   new void GetAllocatedBlob([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out IntPtr ip, out int pcbSize);

   new void GetUnknown([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out object ppv);

   new void SetItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, IntPtr Value);

   new void DeleteItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey);

   new void DeleteAllItems();

   new void SetUINT32([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, int unValue);

   new void SetUINT64([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, long unValue);

   new void SetDouble([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, double fValue);

   new void SetGUID([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [In, MarshalAs(UnmanagedType.LPStruct)] Guid guidValue);

   new void SetString([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [In, MarshalAs(UnmanagedType.LPWStr)] string wszValue);

   new void SetBlob([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] byte[] pBuf, int cbBufSize);

   new void SetUnknown([MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnknown);

   new void LockStore();

   new void UnlockStore();

   new void GetCount(out int pcItems);

   new void GetItemByIndex(int unIndex, out Guid pguidKey, IntPtr pValue);

   new void CopyAllItems([In, MarshalAs(UnmanagedType.Interface)] IMFAttributes pDest);

   #endregion

   void GetStreamIdentifier(out int pdwStreamIdentifier);

   void GetMediaTypeHandler([MarshalAs(UnmanagedType.Interface)] out IMFMediaTypeHandler ppMediaTypeHandler);
}

[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("44AE0FA8-EA31-4109-8D2E-4CAE4997C555")]
public interface IMFMediaType : IMFAttributes {

   #region IMFAttributes methods

   new void GetItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, IntPtr pValue);

   new void GetItemType([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out MF_ATTRIBUTE_TYPE pType);

   new void CompareItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, IntPtr Value, [MarshalAs(UnmanagedType.Bool)] out bool pbResult);

   new void Compare([MarshalAs(UnmanagedType.Interface)] IMFAttributes pTheirs, MF_ATTRIBUTES_MATCH_TYPE MatchType, [MarshalAs(UnmanagedType.Bool)] out bool pbResult);

   new void GetUINT32([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out int punValue);

   new void GetUINT64([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out long punValue);

   new void GetDouble([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out double pfValue);

   new void GetGUID([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out Guid pguidValue);

   new void GetStringLength([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out int pcchLength);

   new void GetString([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwszValue, int cchBufSize, out int pcchLength);

   new void GetAllocatedString([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [MarshalAs(UnmanagedType.LPWStr)] out string ppwszValue, out int pcchLength);

   new void GetBlobSize([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out int pcbBlobSize);

   new void GetBlob([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pBuf, int cbBufSize, out int pcbBlobSize);

   // Use GetBlob instead of this
   new void GetAllocatedBlob([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out IntPtr ip, out int pcbSize);

   new void GetUnknown([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out object ppv);

   new void SetItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, IntPtr Value);

   new void DeleteItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey);

   new void DeleteAllItems();

   new void SetUINT32([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, int unValue);

   new void SetUINT64([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, long unValue);

   new void SetDouble([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, double fValue);

   new void SetGUID([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [In, MarshalAs(UnmanagedType.LPStruct)] Guid guidValue);

   new void SetString([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [In, MarshalAs(UnmanagedType.LPWStr)] string wszValue);

   new void SetBlob([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] byte[] pBuf, int cbBufSize);

   new void SetUnknown([MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnknown);

   new void LockStore();

   new void UnlockStore();

   new void GetCount(out int pcItems);

   new void GetItemByIndex(int unIndex, out Guid pguidKey, IntPtr pValue);

   new void CopyAllItems([In, MarshalAs(UnmanagedType.Interface)] IMFAttributes pDest);

   #endregion

   void GetMajorType(out Guid pguidMajorType);

   void IsCompressedFormat([MarshalAs(UnmanagedType.Bool)] out bool pfCompressed);

   [PreserveSig]
   int IsEqual([In, MarshalAs(UnmanagedType.Interface)] IMFMediaType pIMediaType, out MF_MEDIATYPE_EQUAL pdwFlags);

   void GetRepresentation([In, MarshalAs(UnmanagedType.Struct)] Guid guidRepresentation, out IntPtr ppvRepresentation);

   void FreeRepresentation([In, MarshalAs(UnmanagedType.Struct)] Guid guidRepresentation, [In] IntPtr pvRepresentation);
}

[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("2CD2D921-C447-44A7-A13C-4ADABFC247E3")]
public interface IMFAttributes {
   void GetItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, IntPtr pValue);

   void GetItemType([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out MF_ATTRIBUTE_TYPE pType);

   void CompareItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, IntPtr Value, [MarshalAs(UnmanagedType.Bool)] out bool pbResult);

   void Compare([MarshalAs(UnmanagedType.Interface)] IMFAttributes pTheirs, MF_ATTRIBUTES_MATCH_TYPE MatchType, [MarshalAs(UnmanagedType.Bool)] out bool pbResult);

   void GetUINT32([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out int punValue);

   void GetUINT64([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out long punValue);

   void GetDouble([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out double pfValue);

   void GetGUID([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out Guid pguidValue);

   void GetStringLength([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out int pcchLength);

   void GetString([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwszValue, int cchBufSize, out int pcchLength);

   void GetAllocatedString([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [MarshalAs(UnmanagedType.LPWStr)] out string ppwszValue, out int pcchLength);

   void GetBlobSize([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out int pcbBlobSize);

   void GetBlob([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pBuf, int cbBufSize, out int pcbBlobSize);

   void GetAllocatedBlob([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, out IntPtr ip, out int pcbSize);

   void GetUnknown([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out object ppv);

   void SetItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, IntPtr Value);

   void DeleteItem([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey);

   void DeleteAllItems();

   void SetUINT32([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, int unValue);

   void SetUINT64([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, long unValue);

   void SetDouble([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, double fValue);

   void SetGUID([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [In, MarshalAs(UnmanagedType.LPStruct)] Guid guidValue);

   void SetString([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [In, MarshalAs(UnmanagedType.LPWStr)] string wszValue);

   void SetBlob([In, MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] byte[] pBuf, int cbBufSize);

   void SetUnknown([MarshalAs(UnmanagedType.LPStruct)] Guid guidKey, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnknown);

   void LockStore();

   void UnlockStore();

   void GetCount(out int pcItems);

   void GetItemByIndex(int unIndex, out Guid pguidKey, IntPtr pValue);

   void CopyAllItems([In, MarshalAs(UnmanagedType.Interface)] IMFAttributes pDest);
}

[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("2CD0BD52-BCD5-4B89-B62C-EADC0C031E7D")]
public interface IMFMediaEventGenerator {
   void GetEvent([In] IMFMediaEvent dwFlags, [MarshalAs(UnmanagedType.Interface)] out IMFMediaEvent ppEvent);

   void BeginGetEvent([In, MarshalAs(UnmanagedType.Interface)] IMFAsyncCallback pCallback, [In, MarshalAs(UnmanagedType.IUnknown)] object o);

   void EndGetEvent(IMFAsyncResult pResult, out IMFMediaEvent ppEvent);

   void QueueEvent([In] MediaEventType met, [In, MarshalAs(UnmanagedType.LPStruct)] Guid guidExtendedType, [In] int hrStatus, [In] ref object pvValue);
}

[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("E93DCF6C-4B07-4E1E-8123-AA16ED6EADF5")]
public interface IMFMediaTypeHandler {
   void IsMediaTypeSupported([In, MarshalAs(UnmanagedType.Interface)] IMFMediaType pMediaType, IntPtr ppMediaType);

   void GetMediaTypeCount(out int pdwTypeCount);

   void GetMediaTypeByIndex([In] int dwIndex, [MarshalAs(UnmanagedType.Interface)] out IMFMediaType ppType);

   void SetCurrentMediaType([In, MarshalAs(UnmanagedType.Interface)] IMFMediaType pMediaType);

   void GetCurrentMediaType([MarshalAs(UnmanagedType.Interface)] out IMFMediaType ppMediaType);

   void GetMajorType(out Guid pguidMajorType);
}

[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("279A808D-AEC7-40C8-9C6B-A6B492C78A66")]
public interface IMFMediaSource : IMFMediaEventGenerator {
   #region IMFMediaEventGenerator methods

   #pragma warning disable 109
   new void GetEvent([In] MF_EVENT_FLAG dwFlags, [MarshalAs(UnmanagedType.Interface)] out IMFMediaEvent ppEvent);
   #pragma warning restore 109

   new void BeginGetEvent([In, MarshalAs(UnmanagedType.Interface)] IMFAsyncCallback pCallback, [In, MarshalAs(UnmanagedType.IUnknown)] object o);

   new void EndGetEvent(IMFAsyncResult pResult, out IMFMediaEvent ppEvent);

   new void QueueEvent([In] MediaEventType met, [In, MarshalAs(UnmanagedType.LPStruct)] Guid guidExtendedType, [In] int hrStatus, [In] ref object pvValue);

   #endregion

   void GetCharacteristics(out MFMEDIASOURCE_CHARACTERISTICS pdwCharacteristics);

   void CreatePresentationDescriptor(out IMFPresentationDescriptor ppPresentationDescriptor);

   void Start([In, MarshalAs(UnmanagedType.Interface)] IMFPresentationDescriptor pPresentationDescriptor, [In, MarshalAs(UnmanagedType.LPStruct)] Guid pguidTimeFormat, [In] ref object pvarStartPosition);

   void Stop();

   void Pause();

   void Shutdown();
}

#endregion

Plus some data objects

#region WM

      #region STRUCTS
      #pragma warning restore 618

      [StructLayout(LayoutKind.Sequential, Pack = 8)]
      public class MFVIDEOFORMAT {
         public int dwSize;
         public MFVideoInfo videoInfo;
         public Guid guidFormat;
         public MFVideoCompressedInfo compressedInfo;
         public MFVideoSurfaceInfo surfaceInfo;
      }

      [StructLayout(LayoutKind.Sequential, Pack = 4)]
      public struct MFVideoSurfaceInfo {
         public int Format;
         public int PaletteEntries;
         public MFPaletteEntry[] Palette;
      }

      [StructLayout(LayoutKind.Explicit, Pack = 1)]
      public struct MFPaletteEntry {
         [FieldOffset(0)]
         public MFARGB ARGB;
         [FieldOffset(0)]
         public MFAYUVSample AYCbCr;
      }

      [StructLayout(LayoutKind.Sequential, Pack = 1)]
      public struct MFAYUVSample {
         public byte bCrValue;
         public byte bCbValue;
         public byte bYValue;
         public byte bSampleAlpha8;
      }

      [StructLayout(LayoutKind.Sequential, Pack = 1)]
      public struct MFARGB {
         public byte rgbBlue;
         public byte rgbGreen;
         public byte rgbRed;
         public byte rgbAlpha;
      }

      [StructLayout(LayoutKind.Sequential, Pack = 8)]
      public struct MFVideoCompressedInfo {
         public long AvgBitrate;
         public long AvgBitErrorRate;
         public int MaxKeyFrameSpacing;
      }

      [StructLayout(LayoutKind.Sequential, Pack = 8)]
      public struct MFVideoInfo {
         public int dwWidth;
         public int dwHeight;
         public MFRatio PixelAspectRatio;
         public MFVideoChromaSubsampling SourceChromaSubsampling;
         public MFVideoInterlaceMode InterlaceMode;
         public MFVideoTransferFunction TransferFunction;
         public MFVideoPrimaries ColorPrimaries;
         public MFVideoTransferMatrix TransferMatrix;
         public MFVideoLighting SourceLighting;
         public MFRatio FramesPerSecond;
         public MFNominalRange NominalRange;
         public MFVideoArea GeometricAperture;
         public MFVideoArea MinimumDisplayAperture;
         public MFVideoArea PanScanAperture;
         public MFVideoFlags VideoFlags;
      }

      [StructLayout(LayoutKind.Sequential, Pack = 4)]
      public struct MFRatio {
         public int Numerator;
         public int Denominator;

         public MFRatio(int n, int d) {
            Numerator = n;
            Denominator = d;
         }
      }

      [StructLayout(LayoutKind.Sequential, Pack = 4)]
      public class MFVideoArea {
         public MFOffset OffsetX;
         public MFOffset OffsetY;
         public SIZE Area;

         public MFVideoArea() {
            OffsetX = new MFOffset();
            OffsetY = new MFOffset();
         }

         public MFVideoArea(float x, float y, int width, int height) {
            OffsetX = new MFOffset(x);
            OffsetY = new MFOffset(y);
            Area = new SIZE(width, height);
         }

         public void MakeArea(float x, float y, int width, int height) {
            OffsetX.MakeOffset(x);
            OffsetY.MakeOffset(y);
            Area.cx = width;
            Area.cy = height;
         }
      }

      [StructLayout(LayoutKind.Sequential, Pack = 2)]
      public class MFOffset {
         public short fract;
         public short Value;

         public MFOffset() {
         }

         public MFOffset(float v) {
            Value = (short)v;
            fract = (short)(65536 * (v – Value));
         }

         public void MakeOffset(float v) {
            Value = (short)v;
            fract = (short)(65536 * (v – Value));
         }

         public float GetOffset() {
            return ((float)Value) + (((float)fract) / 65536.0f);
         }
      }
      #endregion

      #region ENUMS
      public enum MFVideoInterlaceMode {
         FieldInterleavedLowerFirst = 4,
         FieldInterleavedUpperFirst = 3,
         FieldSingleLower = 6,
         FieldSingleUpper = 5,
         ForceDWORD = 0x7fffffff,
         Last = 8,
         MixedInterlaceOrProgressive = 7,
         Progressive = 2,
         Unknown = 0
      }

      public enum MFVideoChromaSubsampling {
         Cosited = 7,
         DV_PAL = 6,
         ForceDWORD = 0x7fffffff,
         Horizontally_Cosited = 4,
         Last = 8,
         MPEG1 = 1,
         MPEG2 = 5,
         ProgressiveChroma = 8,
         Unknown = 0,
         Vertically_AlignedChromaPlanes = 1,
         Vertically_Cosited = 2
      }

      public enum MFVideoTransferFunction {
         Func10 = 1,
         Func18 = 2,
         Func20 = 3,
         Func22 = 4,
         Func240M = 6,
         Func28 = 8,
         Func709 = 5,
         ForceDWORD = 0x7fffffff,
         Last = 9,
         sRGB = 7,
         Unknown = 0
      }

      public enum MFVideoPrimaries {
         BT470_2_SysBG = 4,
         BT470_2_SysM = 3,
         BT709 = 2,
         EBU3213 = 7,
         ForceDWORD = 0x7fffffff,
         Last = 9,
         reserved = 1,
         SMPTE_C = 8,
         SMPTE170M = 5,
         SMPTE240M = 6,
         Unknown = 0
      }

      public enum MFVideoTransferMatrix {
         BT601 = 2,
         BT709 = 1,
         ForceDWORD = 0x7fffffff,
         Last = 4,
         SMPTE240M = 3,
         Unknown = 0
      }

      public enum MFVideoLighting {
         Bright = 1,
         Dark = 4,
         Dim = 3,
         ForceDWORD = 0x7fffffff,
         Last = 5,
         Office = 2,
         Unknown = 0
      }

      public enum MFNominalRange {
         MFNominalRange_0_255 = 1,
         MFNominalRange_16_235 = 2,
         MFNominalRange_48_208 = 3,
         MFNominalRange_ForceDWORD = 0x7fffffff,
         MFNominalRange_Last = 4,
         MFNominalRange_Normal = 1,
         MFNominalRange_Unknown = 0,
         MFNominalRange_Wide = 2
      }

      [Flags]
      public enum MFVideoFlags : long {
         PAD_TO_Mask = 0×0001 | 0×0002,
         PAD_TO_None = 0 * 0×0001,
         PAD_TO_4x3 = 1 * 0×0001,
         PAD_TO_16x9 = 2 * 0×0001,
         SrcContentHintMask = 0×0004 | 0×0008 | 0×0010,
         SrcContentHintNone = 0 * 0×0004,
         SrcContentHint16x9 = 1 * 0×0004,
         SrcContentHint235_1 = 2 * 0×0004,
         AnalogProtected = 0×0020,
         DigitallyProtected = 0×0040,
         ProgressiveContent = 0×0080,
         FieldRepeatCountMask = 0×0100 | 0×0200 | 0×0400,
         FieldRepeatCountShift = 8,
         ProgressiveSeqReset = 0×0800,
         PanScanEnabled = 0×20000,
         LowerFieldFirst = 0×40000,
         BottomUpLinearRep = 0×80000,
         DXVASurface = 0×100000,
         RenderTargetSurface = 0×400000,
         ForceQWORD = 0x7FFFFFFF
      }

      [Flags]
      public enum MF_EVENT_FLAG {
         None = 0,
         NoWait = 0×00000001
      }

      public enum MFASYNC_CALLBACK_QUEUE {
         Undefined = 0×00000000,
         Standard = 0×00000001,
         RT = 0×00000002,
         IO = 0×00000003,
         Timer = 0×00000004,
         LongFunction = 0×00000007,
         PrivateMask = unchecked((int)0xFFFF0000),
         All = unchecked((int)0xFFFFFFFF)
      }

      [Flags]
      public enum MFASYNC {
         None = 0,
         FastIOProcessingCallback = 0×00000001,
         SignalCallback = 0×00000002
      }

      public enum MFSTARTUP {
         NoSocket = 0×1,
         Lite = 0×1,
         Full = 0
      }

      [Flags]
      public enum MFResolution {
         None = 0×0,
         MediaSource = 0×00000001,
         ByteStream = 0×00000002,
         ContentDoesNotHaveToMatchExtensionOrMimeType = 0×00000010,
         KeepByteStreamAliveOnFail = 0×00000020,
         Read = 0×00010000,
         Write = 0×00020000
      }

      [Flags]
      public enum MFBYTESTREAM {
         None = 0×00000000,
         IsReadable = 0×00000001,
         IsWritable = 0×00000002,
         IsSeekable = 0×00000004,
         IsRemote = 0×00000008,
         IsDirectory = 0×00000080,
         HasSlowSeek = 0×00000100,
         IsPartiallyDownloaded = 0×00000200
      }

      public enum MFBYTESTREAM_SEEK_ORIGIN {
         Begin,
         Current
      }

      [Flags]
      public enum MFBYTESTREAM_SEEK_FLAG {
         None = 0,
         CancelPendingIO = 1
      }

      public enum MF_OBJECT_TYPE {
         MediaSource,
         ByteStream,
         Invalid
      }

      public enum MediaEventType {
         MEUnknown = 0,
         MEError = (MEUnknown + 1),
         MEExtendedType = (MEError + 1),
         MESessionUnknown = 100,
         MESessionTopologySet = (MESessionUnknown + 1),
         MESessionTopologiesCleared = (MESessionTopologySet + 1),
         MESessionStarted = (MESessionTopologiesCleared + 1),
         MESessionPaused = (MESessionStarted + 1),
         MESessionStopped = (MESessionPaused + 1),
         MESessionClosed = (MESessionStopped + 1),
         MESessionEnded = (MESessionClosed + 1),
         MESessionRateChanged = (MESessionEnded + 1),
         MESessionScrubSampleComplete = (MESessionRateChanged + 1),
         MESessionCapabilitiesChanged = (MESessionScrubSampleComplete + 1),
         MESessionTopologyStatus = (MESessionCapabilitiesChanged + 1),
         MESessionNotifyPresentationTime = (MESessionTopologyStatus + 1),
         MENewPresentation = (MESessionNotifyPresentationTime + 1),
         MELicenseAcquisitionStart = (MENewPresentation + 1),
         MELicenseAcquisitionCompleted = (MELicenseAcquisitionStart + 1),
         MEIndividualizationStart = (MELicenseAcquisitionCompleted + 1),
         MEIndividualizationCompleted = (MEIndividualizationStart + 1),
         MEEnablerProgress = (MEIndividualizationCompleted + 1),
         MEEnablerCompleted = (MEEnablerProgress + 1),
         MEPolicyError = (MEEnablerCompleted + 1),
         MEPolicyReport = (MEPolicyError + 1),
         MEBufferingStarted = (MEPolicyReport + 1),
         MEBufferingStopped = (MEBufferingStarted + 1),
         MEConnectStart = (MEBufferingStopped + 1),
         MEConnectEnd = (MEConnectStart + 1),
         MEReconnectStart = (MEConnectEnd + 1),
         MEReconnectEnd = (MEReconnectStart + 1),
         MERendererEvent = (MEReconnectEnd + 1),
         MESessionStreamSinkFormatChanged = (MERendererEvent + 1),
         MESourceUnknown = 200,
         MESourceStarted = (MESourceUnknown + 1),
         MEStreamStarted = (MESourceStarted + 1),
         MESourceSeeked = (MEStreamStarted + 1),
         MEStreamSeeked = (MESourceSeeked + 1),
         MENewStream = (MEStreamSeeked + 1),
         MEUpdatedStream = (MENewStream + 1),
         MESourceStopped = (MEUpdatedStream + 1),
         MEStreamStopped = (MESourceStopped + 1),
         MESourcePaused = (MEStreamStopped + 1),
         MEStreamPaused = (MESourcePaused + 1),
         MEEndOfPresentation = (MEStreamPaused + 1),
         MEEndOfStream = (MEEndOfPresentation + 1),
         MEMediaSample = (MEEndOfStream + 1),
         MEStreamTick = (MEMediaSample + 1),
         MEStreamThinMode = (MEStreamTick + 1),
         MEStreamFormatChanged = (MEStreamThinMode + 1),
         MESourceRateChanged = (MEStreamFormatChanged + 1),
         MEEndOfPresentationSegment = (MESourceRateChanged + 1),
         MESourceCharacteristicsChanged = (MEEndOfPresentationSegment + 1),
         MESourceRateChangeRequested = (MESourceCharacteristicsChanged + 1),
         MESourceMetadataChanged = (MESourceRateChangeRequested + 1),
         MESequencerSourceTopologyUpdated = (MESourceMetadataChanged + 1),
         MESinkUnknown = 300,
         MEStreamSinkStarted = (MESinkUnknown + 1),
         MEStreamSinkStopped = (MEStreamSinkStarted + 1),
         MEStreamSinkPaused = (MEStreamSinkStopped + 1),
         MEStreamSinkRateChanged = (MEStreamSinkPaused + 1),
         MEStreamSinkRequestSample = (MEStreamSinkRateChanged + 1),
         MEStreamSinkMarker = (MEStreamSinkRequestSample + 1),
         MEStreamSinkPrerolled = (MEStreamSinkMarker + 1),
         MEStreamSinkScrubSampleComplete = (MEStreamSinkPrerolled + 1),
         MEStreamSinkFormatChanged = (MEStreamSinkScrubSampleComplete + 1),
         MEStreamSinkDeviceChanged = (MEStreamSinkFormatChanged + 1),
         MEQualityNotify = (MEStreamSinkDeviceChanged + 1),
         MESinkInvalidated = (MEQualityNotify + 1),
         MEAudioSessionNameChanged = (MESinkInvalidated + 1),
         MEAudioSessionVolumeChanged = (MEAudioSessionNameChanged + 1),
         MEAudioSessionDeviceRemoved = (MEAudioSessionVolumeChanged + 1),
         MEAudioSessionServerShutdown = (MEAudioSessionDeviceRemoved + 1),
         MEAudioSessionGroupingParamChanged = (MEAudioSessionServerShutdown + 1),
         MEAudioSessionIconChanged = (MEAudioSessionGroupingParamChanged + 1),
         MEAudioSessionFormatChanged = (MEAudioSessionIconChanged + 1),
         MEAudioSessionDisconnected = (MEAudioSessionFormatChanged + 1),
         MEAudioSessionExclusiveModeOverride = (MEAudioSessionDisconnected + 1),
         METrustUnknown = 400,
         MEPolicyChanged = (METrustUnknown + 1),
         MEContentProtectionMessage = (MEPolicyChanged + 1),
         MEPolicySet = (MEContentProtectionMessage + 1),
         MEWMDRMLicenseBackupCompleted = 500,
         MEWMDRMLicenseBackupProgress = 501,
         MEWMDRMLicenseRestoreCompleted = 502,
         MEWMDRMLicenseRestoreProgress = 503,
         MEWMDRMLicenseAcquisitionCompleted = 506,
         MEWMDRMIndividualizationCompleted = 508,
         MEWMDRMIndividualizationProgress = 513,
         MEWMDRMProximityCompleted = 514,
         MEWMDRMLicenseStoreCleaned = 515,
         MEWMDRMRevocationDownloadCompleted = 516,
         MEReservedMax = 10000
      }

      public enum MF_ATTRIBUTE_TYPE {
         None = 0×0,
         Blob = 0×1011,
         Double = 0×5,
         Guid = 0×48,
         IUnknown = 13,
         String = 0x1f,
         Uint32 = 0×13,
         Uint64 = 0×15
      }

      public enum MF_ATTRIBUTES_MATCH_TYPE {
         OurItems,
         TheirItems,
         AllItems,
         InterSection,
         Smaller
      }

      [Flags]
      public enum MFMEDIASOURCE_CHARACTERISTICS {
         None = 0,
         IsLive = 0×1,
         CanSeek = 0×2,
         CanPause = 0×4,
         HasSlowSeek = 0×8
      }

      [Flags]
      public enum MF_MEDIATYPE_EQUAL {
         None = 0,
         MajorTypes = 0×00000001,
         FormatTypes = 0×00000002,
         FormatData = 0×00000004,
         FormatUserData = 0×00000008
      }
      #endregion

      #endregion

Some cumbersome, right? It is! however those interfaces are extensible. Here for example some added value of such approach

How to read media metadata by using Media Foundation

Now, when we did most of work, metadata is piece of cake. All we need is to get service handle

object s;
MFGetService(source, MFServices.MF_PROPERTY_HANDLER_SERVICE, typeof(IPropertyStore).GUID, out s);
var store = (IPropertyStore)s;

and get information our of property bag

track.Album = _getInfo<string>(store, MFPropertyKeys.AlbumTitle);
track.Name = _getInfo<string>(store, MFPropertyKeys.Title);
track.Comments = _getInfo<string>(store, MFPropertyKeys.Comment);
track.Duration = TimeSpan.FromTicks(_getInfo<long>(store, Interop.MFPropertyKeys.MediaDuration));

Those interfaces uses COM property bag to retrieve information of invariant type

private static T _getInfo<T>(IPropertyStore store, PROPERTYKEY key) {
         PROPVARIANT val;
         store.GetValue(key, out val);
        return (T)val.Value;
      }

Here how this object looks in managed code

[StructLayout(LayoutKind.Sequential)]
public class PROPERTYKEY {

public PROPERTYKEY(Guid tid, uint id) {
fmtid = tid;
pid = id;
}

public Guid fmtid;

public uint pid;
}

#pragma warning disable 618
[StructLayout(LayoutKind.Explicit)]
public struct PROPVARIANT {
[FieldOffset(0)]
short vt;
[FieldOffset(2)]
short wReserved1;
[FieldOffset(4)]
short wReserved2;
[FieldOffset(6)]
short wReserved3;
[FieldOffset(8)]
sbyte cVal;
[FieldOffset(8)]
byte bVal;
[FieldOffset(8)]
short iVal;
[FieldOffset(8)]
ushort uiVal;
[FieldOffset(8)]
int lVal;
[FieldOffset(8)]
uint ulVal;
[FieldOffset(8)]
int intVal;
[FieldOffset(8)]
uint uintVal;
[FieldOffset(8)]
long hVal;
[FieldOffset(8)]
long uhVal;
[FieldOffset(8)]
float fltVal;
[FieldOffset(8)]
double dblVal;
[FieldOffset(8)]
bool boolVal;
[FieldOffset(8)]
int scode;
[FieldOffset(8)]
DateTime date;
[FieldOffset(8)]
FILETIME filetime;
[FieldOffset(8)]
BLOB blobVal;
[FieldOffset(8)]
IntPtr pwszVal;

private byte[] _getBlob() {
var result = new byte[blobVal.cbSize];
Marshal.Copy(blobVal.pBlobData, result, 0, result.Length);
return result;
}

public object Value {
get {
VarEnum ve = (VarEnum)vt;
switch (ve) {
case VarEnum.VT_I1:
return bVal;
case VarEnum.VT_I2:
return iVal;
case VarEnum.VT_I4:
return lVal;
case VarEnum.VT_I8:
return hVal;
case VarEnum.VT_INT:
return iVal;
case VarEnum.VT_UI4:
return ulVal;
case VarEnum.VT_UI8:
return uhVal;
case VarEnum.VT_LPWSTR:
return Marshal.PtrToStringUni(pwszVal);
case VarEnum.VT_BLOB:
return _getBlob();
case VarEnum.VT_EMPTY:
case VarEnum.VT_NULL:
return null;
}
throw new NotImplementedException("PROPVARIANT: " + ve.ToString());
}
}
}

And some additional classes and guids to fulfill solution.

public static class MFAttributesClsid {
public static readonly Guid MF_PD_DURATION = new Guid(0x6c990d33, 0xbb8e, 0x477a, 0×85, 0×98, 0xd, 0x5d, 0×96, 0xfc, 0xd8, 0x8a);
public static readonly Guid MF_MT_SUBTYPE = new Guid(0xf7e34c9a, 0x42e8, 0×4714, 0xb7, 0x4b, 0xcb, 0×29, 0xd7, 0x2c, 0×35, 0xe5);
public static readonly Guid MF_MT_AVG_BITRATE = new Guid(0×20332624, 0xfb0d, 0x4d9e, 0xbd, 0x0d, 0xcb, 0xf6, 0×78, 0x6c, 0×10, 0x2e);
}

public static class MFMediaType {
public static readonly Guid Default = new Guid(0x81A412E6, 0×8103, 0x4B06, 0×85, 0x7F, 0×18, 0×62, 0×78, 0×10, 0×24, 0xAC);
public static readonly Guid Audio = new Guid(0×73647561, 0×0000, 0×0010, 0×80, 0×00, 0×00, 0xAA, 0×00, 0×38, 0x9B, 0×71);
public static readonly Guid Video = new Guid(0×73646976, 0×0000, 0×0010, 0×80, 0×00, 0×00, 0xAA, 0×00, 0×38, 0x9B, 0×71);
}

public static class MFServices {
public static readonly Guid MF_PROPERTY_HANDLER_SERVICE = new Guid(0xa3face02, 0x32b8, 0x41dd, 0×90, 0xe7, 0x5f, 0xef, 0x7c, 0×89, 0×91, 0xb5);
}

public static class MFPropertyKeys {
public static readonly PROPERTYKEY Title = new PROPERTYKEY(new Guid(0xf29f85e0, 0x4ff9, 0×1068, 0xab, 0×91, 0×08, 0×00, 0x2b, 0×27, 0xb3, 0xd9), 2);
public static readonly PROPERTYKEY AlbumTitle = new PROPERTYKEY(new Guid(0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0×00, 0×60, 0×97, 0xC6, 0×86, 0xF6), 4);
public static readonly PROPERTYKEY Author = new PROPERTYKEY(new Guid(0xF29F85E0, 0x4FF9, 0×1068, 0xAB, 0×91, 0×08, 0×00, 0x2B, 0×27, 0xB3, 0xD9), 4);
public static readonly PROPERTYKEY AudioCompression = new PROPERTYKEY(new Guid(0×64440490, 0x4C8B, 0x11D1, 0x8B, 0×70, 0×08, 0×00, 0×36, 0xB1, 0x1A, 0×03), 10);
public static readonly PROPERTYKEY AudioFormat = new PROPERTYKEY(new Guid(0×64440490, 0x4C8B, 0x11D1, 0x8B, 0×70, 0×08, 0×00, 0×36, 0xB1, 0x1A, 0×03), 2);
public static readonly PROPERTYKEY Category = new PROPERTYKEY(new Guid(0xD5CDD502, 0x2E9C, 0x101B, 0×93, 0×97, 0×08, 0×00, 0x2B, 0x2C, 0xF9, 0xAE), 2);
public static readonly PROPERTYKEY Company = new PROPERTYKEY(new Guid(0xD5CDD502, 0x2E9C, 0x101B, 0×93, 0×97, 0×08, 0×00, 0x2B, 0x2C, 0xF9, 0xAE), 15);
public static readonly PROPERTYKEY Copyright = new PROPERTYKEY(new Guid(0×64440492, 0x4C8B, 0x11D1, 0x8B, 0×70, 0×08, 0×00, 0×36, 0xB1, 0x1A, 0×03), 11);
public static readonly PROPERTYKEY Comment = new PROPERTYKEY(new Guid(0xF29F85E0, 0x4FF9, 0×1068, 0xAB, 0×91, 0×08, 0×00, 0x2B, 0×27, 0xB3, 0xD9), 6);
public static readonly PROPERTYKEY MediaDuration = new PROPERTYKEY(new Guid(0×64440490, 0x4C8B, 0x11D1, 0x8B, 0×70, 0×08, 0×00, 0×36, 0xB1, 0x1A, 0×03), 3);
public static readonly PROPERTYKEY VideoCompression = new PROPERTYKEY(new Guid(0×64440491, 0x4C8B, 0x11D1, 0x8B, 0×70, 0×08, 0×00, 0×36, 0xB1, 0x1A, 0×03), 10);
public static readonly PROPERTYKEY VideoDirector = new PROPERTYKEY(new Guid(0×64440492, 0x4C8B, 0x11D1, 0x8B, 0×70, 0×08, 0×00, 0×36, 0xB1, 0x1A, 0×03), 20);
public static readonly PROPERTYKEY VideoFourCC = new PROPERTYKEY(new Guid(0×64440491, 0x4C8B, 0x11D1, 0x8B, 0×70, 0×08, 0×00, 0×36, 0xB1, 0x1A, 0×03), 44);
}

We almost finished. The only thing is not to forget release all COM objects (Marshal.ReleaseComObject(…)) to prevent memory leaks and init and shutdown Media Foundation:

MFStartup(0×10070, Interop.MFSTARTUP.Lite);

MFShutdown();

You choose what to use: simple, but not supported or complicated but extensible approach. Both will bring the same results. So have a nice day and be good people.

Visual Studio Face-to-Face battle

Yesterday Visual Studio 2010 was released. This is very exciting, however from the moment I played with very first preview versions I had concerns regarding the performance of it code editor. So today I had some time to perform small face-to-face battle between different versions of Visual Studio – 2005, 2008 and 2010 (Sorry, I did not found VS2002 to test).

image

Environment

I used very slow machine with 256Mb of RAM running Windows XP as a reference for comparison. First of all I installed each one of those programs. I used customized installation to install only C# programming modules.

Then I tested cold start (first application start) and hot start (average of 5 forecoming starts), creation and opening of new console application project. And finally the real world test. Typing in, compilation and run of “Hello World” sample. This includes opening of context menus, tools and options.

I used “Hello World” sample from MSDN for type-in experience. Just for reference, I used small program I wrote to calculate typing speed (this takes into account that most of text is generated by the same macros and shortcuts e.g. “cw”)

Comparison

  VS2005 VS2008 VS2010
Installation 10 min 20 min 40 min
Cold start 1.2 sec 3.9 sec 28 sec
Hot start 0.3 sec 1.3 sec 4.5 sec
Start new project (Ctrl-Shift-N) 0.2 sec 3.2 sec 2 sec
Create new Console Application 16 sec 3 sec 24 sec
Clear working screen (Ctrl-A + Del) 0.4 sec 0.2 sec 1.2 sec
Type in “Hello World” 41 sec 56 sec 1 min 43 sec
Average type rate 93 wpm 68 wpm 35 wpm
Average UI response (how long it takes to open menu/hint) 0.7 sec 1.6 sec 3.5 sec
Installation/Uninstallation disk delta 40Mb 60Mb 2.3Gb*
Memory footprint (for this project) 6Mb 17Mb 65Mb
Disk space required 1.4Gb 2.6Gb 3.9Gb

* Can anybody from DevDiv, please, explain me why when I want to install only C# (this is the only checkbox marked during custom installation), you install for me:
Untitled

Conclusion

There are some new and pretty eye-candies for VS2010, also support for newer compilers and interpreter. However, my final verdict is “I disappointed”…

I feel a big degradation of productivity between following versions of Visual Studio. In terms of speed, responsiveness and ability to perform everyday developers’ tasks. That’s right, that there are new features, but we should remember that the main purpose of this program is to support writing code.

I hope that MS DevDiv will take this into account and review it understanding of how development environment should be. I, personally, stay with VS2008 without .NET 4.0 (I have my special opinion about this version of .NET, which worse separate post)

If you old enough, you should remember HomeSite. It was beaten by editor named Notepad.exe (or it variants and alternatives) for HTML developers because of it unresponsiveness and unnecessary cumbersomeness of this program. Running after features killed the main purpose – write effective code fast and correct. This how I forecast the future of Visual Studio. Pity me…

 My hopes

P.S. Sorry, I did not write here for a while. This because of a lot of exiting things I did for the last two years. I promise to write more. Frankly! I swear, I will try to!

UPD 14-Apr: For all people have comments about my production environment and a validity of my measurements there, please see how it looks on my work machine (E8400, 8Gb RAM and NVIDIA GeForce 9600 GT)

Quick IT tip: How to build bootable USB stick

Because of my main job and lack of human resources there, I invest less and less in community. Thus I lost my MVP title. Sorry, guys. Also a ton of management tasks in big company prevents me from actual coding. However I am still able to find some time for doing “real” things such as Windows Embedded Standard 2011 image building. Thus today I will explain how to build bootable flash USB disk with a couple of simple commands and without using special utilities.

 World first USB drive by Trek Technology

Why to use bootable USB instead of regular CD or DVD ROM? Well, it is more convenience, takes less storage, faster and fully recycle. So let’s start.

1. Insert USB flash drive :)
2. Run command prompt shell as Administrator (just in case the keyboard shortcut for “Run as Administrator” is Ctrl+Alt+Shift)
3. Type “diskpart” to run Microsoft DiskPart utility.

C:\Windows\system32>diskpart

Microsoft DiskPart version 6.1.7600
Copyright (C) 1999-2008 Microsoft Corporation.
On computer: TAMIRK-DEV

4. List your disks by typing in “list disk” or for those who like it shorter (like me) “list dis

DISKPART> lis dis

  Disk ###  Status         Size     Free     Dyn  Gpt
  ——–  ————-  ——-  ——-  —  —
  Disk 0    Online          149 GB  1024 KB
  Disk 1    Online           75 GB     2 GB
  Disk 2    Online         3814 MB      0 B
  Disk 3    No Media           0 B      0 B
  Disk 4    No Media           0 B      0 B
  Disk 5    Online           14 GB      0 B

5. Identify your flash drive (in my case it is Disk 5)
6. Select this drive to mark it for work by using “select disk 5” or “sel dis 5” command

DISKPART> sel dis 5

Disk 5 is now the selected disk.

7. Clean it (this will delete everything on your disk drive, so be careful) by using “clean” or “cle” command.

DISKPART> cle

DiskPart succeeded in cleaning the disk.

8. Create primary partition – “create partition primary” or “cre par pri

DISKPART> cre par pri

DiskPart succeeded in creating the specified partition.

9. Select new partition – “select partition 1” or “sel par 1

DISKPART> sel par 1

Partition 1 is now the selected partition.

10. Mark it as Active partition – “active” or “act

DISKPART> act

DiskPart marked the current partition as active.

11. Format – “format fs=ntfs quick” or “for fs=ntfs quick

DISKPART> for fs=ntfs quick

  100 percent completed

DiskPart successfully formatted the volume.

12. And finally my favorite command – “assign” or “ass” to mark it ready and create mount point

DISKPART> ass

DiskPart successfully assigned the drive letter or mount point.

13. Exit – “exit” or “exi” to return to command shell

DISKPART> exi

Leaving DiskPart…

Now your thumb drive is ready and bootable. So you can start copying files from ISO image into it.

Other option is to work with volumes rather than with disks. The all difference is in steps 4-6. Instead of “lis dis” use “lis vol” and instead of “sel dis” use “sel vol”. Maybe it is more convenience way of work because in this case you can identify partitions by labels and sizes rather than by sizes only.

DISKPART> lis vol

  Volume ###  Ltr  Label        Fs     Type        Size     Status     Info
  ———-  —  ———–  —–  ———-  ——-  ———  ——–
  Volume 0     E                       DVD-ROM         0 B  No Media
  Volume 1     G                       DVD-ROM         0 B  No Media
  Volume 2         System Rese  NTFS   Partition    100 MB  Healthy    System
  Volume 3     C                NTFS   Partition     68 GB  Healthy    Boot
  Volume 4     D   DATA         NTFS   Partition     80 GB  Healthy
  Volume 5     F   READYBOOST   FAT    Removable   3812 MB  Healthy
  Volume 6     H                       Removable       0 B  No Media
  Volume 7     I                       Removable       0 B  No Media
  Volume 8     K                NTFS   Removable     14 GB  Healthy

If you already copied your image into disk, you can mark MBR by using special utility called BootSect.exe shipped with WAIK. In our case (with Windows 7 embedded), you’ll have to update master boot code to use BOOTMGR (Vista and up) rather than NTLDR (XP and down)

BOOTSECT.EXE /NT60 K: /mbr

We done, have a good day and be good people. Additional information regarding USB core guys from MS can be archived from their brand new blog (hope it will be up to date).

At the end, just you to know how are CDs make by Discovery Channel

TFS licensing model demystification or what should I buy for my company in order not to step on the licensing mine?

Microsoft loves cumbersome licensing models . This is not because of their evil-heartedness, but because it make them possible to get more from bigger companies and less from smaller. However when you come into the real decision about how many and what kind of licenses you have to purchase, you stuck. Today we’ll try to make things clearer, at least for Team Foundation Server and Visual Studio, which is very base things for any software house develops things using Microsoft technologies.

Cumbersomeness of the TFS licening model
© image for cumbersomeness proposal via Willy-Peter Schaub by SA Architect

To make things even simpler, let’s assume that we do not need TFS Workgroup edition (which is special edition for TFS 5 users only) and we are not using TFS Device CAL (as opposed to User CAL this Client Access License permits one device to be used by any number of users. This kind of CAL is good for kiosks rather then for development environments). Also Test Load Agent needs it own license. So now, and under all those circumstances, let’s start.

To work with TFS we need:

  1. One or more Team Foundation Server
  2. More then one Visual Studio Client (editions can vary)
  3. Optional one or more Software Assurance, which can be licenses separately or together with MSDN subscription
  4. … and some other optional tools

TFS Licensing

Each instance of TFS needs it license. Even if you have mirrored deployment of TFS, you need a server license for each instance. Also you need separate license if you are using TFS Data Tier on SQL Server cluster or using TFS Proxy. I think it’s clear, that in addition to TFS license you’ll need Windows Server and SQL server licenses (if it used especially for TFS). You can also put Data Tier on existing SQL server in this case you need only another TFS license without SQL.

You do not need additional Team Foundation Server license for the machine used for TF build services. Also this machine does not need another CAL, except one used for the system user used for initialize builds.

To summarize: each instance of TFS need server license in addition to CALs and other server licenses (such as Windows, SQL, SharePoint, IIS etc).

Client Access License

In addition to server license you need also CAL for each used reads and writes to TFS. There are different versions of Visual Studio includes CAL:

  • Visual Studio 2008 Team Suite
  • Visual Studio 2008 Architecture edition
  • Visual Studio 2008 Development edition
  • Visual Studio 2008 Test edition
  • Visual Studio 2008 Database edition

Visual Studio 2008 Professional does not includes CAL. So each one of contributes needs one of Visual Studios which includes CAL. The TFS clients might be installed on one of those editions and does requires additional license.

You do not need additional license when you are using TFS for only:

  • Create work items, bugs, etc.
  • Query for work items
  • Update work items

Other words product definition, system analysts, managers and “bug fillers” do not required additional CAL. Note, that they will probably need proper Microsoft Office licenses to use Excel or Project to do this, however they can also use TFS web access (browser) or any other 3rd party tool without purchasing separate CAL.

Also you need only one CAL for server software. Other words, if you are using TFS on Windows Server you do not need TFS and Windows Server CAL. Also those CALs covers all earlier versions of all products in use.

To summarize: Each TFS user does not need additional CAL when he has proper license for Visual Studio Team Suite or using TFS for only bug/issues tracking.

Software assurance vs. MSDN

MSDN is more expensive then SA (Software Assurance), however it includes SA and provides some benefits by allowing access to several Microsoft products for development and testing purposes.

There are two different MSDN editions – professional and premium. The difference between those editions (except price) is that Premium editing includes Windows Server Systems and Microsoft Office. Thus with Professional edition you got software assurance for Visual Studio 2008 Professional while with Premium for all other versions.

Let’s simulate the results

For small software house with 10 developers (two architects, 1 DBA and 3 QA), two product definition guys, and manager we’ll need (in addition to OS, other server and Office licenses):

  • 1 TFS license
  • 2 Visual Studio 2008 Architecture edition
  • 1 Visual Studio 2008 Database edition
  • 3 Visual Studio 2008 Test edition
  • 4 Visual Studio 2008 Development edition
  • 1<n<10 MSDN Licenses Premium (as number of employees need it for testing or development purposes)
  • 10-n SA licenses (if SA required)
  • Additional CAL for build machine

I think, that now it become a bit clearer. For additional information regarding TFS licensing model, please refer Visual Studio Team System 2008 Licensing White Paper or ask your local licensing expert at Microsoft.

Windows 7 – dry run or how things should be done to correct old mistakes

I have not write for a while (if you’re following me on Twitter, you know why). Even so, today it will not be very informative post. This all about my expression about latest builds of Windows 7 and one job proposal. Have a fun.

January 13rd, I expressed rather bad opinion about Windows 7 (beta those days). Today, after most of post-RC builds (currently with 7260) on work machine I would way with big confidence – Microsoft learned from beta errors and now it works almost like it should work for RTM.

6.1.7260.0.win7_rtm.090612-2110

Installation

Installation takes less and less from build to build (this is 7th I’m checking). With 7260 it took about 15 minutes. All hardware devices (including Intel AMT, PM45 and LM5) were found and installed correctly. Shortly after the installation it installed a bunch of security and device driver updates. Looks like Microsoft has no issues with Intel anymore (or they just decided to build drivers by itself).

Hybrid graphic cards still not supported. Also it not seemed that it will be supported toward RTW. However Windows 7 correctly decided to use discrete card, rather then on-board once BIOS settings were set to prioritize it.

Taskbar

It still sucks, but you will accustom to it. From the beginning it looks like it takes all valuable space on your desktop, but shortly after you’ll see that it somehow comfortable to use it (it is really depends how you working. Lately I changed a bit a way I’m doing things [this why you cannot see me in Live Messenger anymore], thus it become rather good for me). Here how it looks for me now

My taskbar - in battery save mode of couse

Yes, it is Chome on this bar and this why:

‘Coz Internet Explorer become worse and worse

The only good thing I found about IE8 shipped with W7 is it has support for Windows 7 taskbar. However even this fact cannot defense against its suckness. It slow, buggy, has not enough functionality and absolutely annoying. I love Firefox, but it has too much functionality for me those days. Once I used to open it, I loss at least a half of hour for twittering, reading rss, etc. With Google Chrome is it not an issue, because this is nimble program with only one functionality – browse internet pages.

My last BSoD

Since the last time, I had no BSoDs. Also WDM not eating 999.9 CPU hours anymore (like it did in idle Vista). Also I had no compatibility issues. Everything worked as expected on my machine. The only issue I had is IE, that decided not to die and stuck as running windowless process. You know how it is when any icon on taskbar stops to do anything, just becoming red when you click on it.

Conclusion

Do it. Upgrade your OS as soon as possible and have a fun.

 

We’re hiring! (Israel residents only)

Lead Software Development Engineer in Test

We are looking for strong Software Development Engineer in Test who is passionate about UI and internal API usage to test rich client applications. Responsibilities would include developing test strategies, writing unit tests, UI automation, custom msbuild scripts, performing problem isolation and analysis, communicating with developers in support of debugging and investigation.

My group takes both individuals and teams success seriously, and looking for the right person to join our team, which is development, rather than test team. What my group is doing?

The AutOS group is responsible for delivering of the system you’ll have inside your next electric vehicle, one of the most important applications we have at Better Place for providing a consistent, transparent and fluent experience for a driver every day. Currently the application is used for energy management, navigation, infotainment, road safety and many other aspects of enhancing your future driving. Come explore the exciting opportunities on AutOS team developing cutting edge tools, facing all customers for all Better Place EVs. Become a member of the outstanding team that strives for engineering excellence in improving the life of all of us. AutOS team is using latest technologies and innovations to make sure delivery of the best possible experience for a driver.

Qualification

Solid programming ability in managed programming using the .NET Framework (C#) with some experience in WPF or Silverlight.
Solid technical knowledge in Information Technology field, including hardware capabilities and performance evaluation and tests.
Strong problem solving and troubleshooting skills.
Knowledge of Team Foundation Server and MSBUILD scripting.
2+ years experience in software testing, including designing and developing automation infrastructure.
Strong test aptitude.
Good communication skills and ability to work closely in a development team environment.
BA/BS or MS degree in Computer Science or equivalent field experience is required.

You think, that you want such job? Send me your CV, couple of word about yourself and why you want and able to work with me at Better Place to tamir@khason.biz with “Lead SDET application” in subject. (if you do get get an answer from me within a week, your mail is in spam, so you should resent it by using contact form here)

Have a nice day and be good people.

Some new in-mix downloads

There are some very cool downloads suddenly appear on MSDN download site due to all new technologies, presented at Mix ‘09. So let’s start

To learn more about Silverlight 3.0 and Blend 3.0, you can see first day keynotes at mix 09, Rollup of what’s new in Silverlight 3 by Joe Stegman. This includes offline mode support by Mike Harsh. I’ll write another separate post for this topic, due to the fact, that I’m a desktop guy, so wary about the future of WPF.

To learn more about how to use new Expression Blend, it worth to see this session by Pete Blois. Another good sessions are also wrapped for you by Scott Hanselman.

After we done with all web stuff, let’s speak about a client

That’s all by now, going to write a review for new book and will publish it soon (probably even before, you’ll finish with all those downloads and readings). So, stay tuned and be good people.

Slides and desks from Smart Client Development session

Great thank to everybody attended yesterday at “Smart Client development” session. As promises, please see slides and desks from this session

Line-Of-Business vs. Beautifulness or two dogmas comparison as exemplified by two Twitter applications

Today I want to speak about two dogmas: design and functional driven programming. As the example of those two approaches, I want to introduce two Twitter clients: *Chirp by thirteen23 and TwitterFox by Naan Studio

Chirp and TwitterFox comparision

As you can see, *Chirp is state of art application with outstanding user interface, and well-defined usability studies. While TwitterFox is wacky grey boring kind-of-grid only. However, you cannot judge app by only how it looks like. Let’s try to understand first what’s for you need twitter client?

Defining application goals by user story

I’m using twitter as quick and handy business tool to write my thought, feelings and everyday events. It is not my main (not even secondary) task during the day, so I want to be able to open, write and forget. Thus, I need an application, that can be invoked by one click and dismissed after writing. Also, I do not want background application to gasp valuable space in my screen, when not in use. Thus it should be background process with reduced workset and one textarea, to be focused when the main window become active. Also the application should hide itself when unfocus, yet be able to notify me about events without disturbing.

Let’s see how it done in *Chirp:

  • 140MB workset
  • No ability to hide
  • Bouncing thingy at left upper corner to disturb you – it designed as you main desktop beautifier.
  • No ability to know that new twittes arrived without showing main window
  • Twit process required to click additional button (named “Update” for some reason)
  • If you not finished typing, you can either dismiss all text of post it.
  • Strange 140 characters countdown on background absolutely esthetical, yet very disturbing.
  • You cannot type more, then 140 characters – this restricted by textbox. If pasted bigger text all additional characters truncated.
  • You need mouse to operate an application

Now TwitterFox:

  • 10MB workset
  • You can hide it by hitting escape or clicking X button
  • Small and portable without disturbing elements – it not designed as your main everyday app.
  • New twits counter over small icon in browser tray, all other notifications can be disabled
  • Once focused text are become active, expanded automatically and ready to write
  • If you’re hiding it without clearing area, all un write text remains – you can clear it by one click
  • Small 140 characters countdown which is visible only when typing
  • You can type more, then 140 characters – counter becomes red, and you cannot post, however you’re able to fix, by dismissing unnecessary spaces or characters.
  • Can be operated by only keyboard.

Bottom line: *Chirp designed to show how good it looks, while TwitterFox to twit only. Thus for my specific user story TwitterFox won!

Defining functional specifications

Next task defined for Twitter is read other twits. I used to read all my following and followers when I have free minute. Sometimes I retwit things, rather often reply followers and read replies and rarely send direct messages.

*Chirp provides twit area without scrollbar, yet not restricted to number of twits. Other words, you can scroll with mouse wheel only or by holding somewhere inside and dragging unlimited up and down. When the mouse is over specific twit, it fades and show three buttons: reply, direct and retwit. Also each twit contains the name of the client was used (just like in regular web interface). When clicking user avatar it brings to special internal screen with last twit of the user, information and statistics about him, three functional buttons: UnFollow, Fave and Block and huge button Get User’s Tweets. When clicking the line displays the time of the twit it puts twit url into clipboard.

Also *Chirp contains five main functional buttons: Faves, Home, Direct, Update and Refresh. When Home tab unfocused (for example you’re on other screen), it also displays a number of new twits.

Error screen of *Chirp is really odd. It contains everything you not really need to know and beautiful whales moving on screen.

WTF?

TwitterFox is much simpler. It contains two buttons on mouse/keyboard over – reply and fave. When clicking on user’s avatar it opens it’s page in Twitter with all necessary information. Main TwitterFox window contains three buttons: Recent, Replies, Messages.

No doubt, that *Chirp provides much richer functional spec, but wait, am I really need all this? I told earlier, that I used to read twits and replies, while *Chirp has no such view at all. You can easy copy twit url into clipboard, but what for? Also, you can read  bio and statistics of people you following whenever you want without opening browser window. But how often you’re doing that?

TwitterFox concentrated on functionality – twit, read, reply, read replies (and direct messages) – base tasks , Twitter designed for. It also marks replies with contrast color in public timeline, while *Chirp has inline reply functionality with threaded discussions support (which is very odd for Twitter)

Bottom line: *Chirp is enriched with not useful features, while TwitterFox contains only things, you’re use. Thus for my specific functional requirements TwitterFox won again!

Developers vs. Designers final round

So, we already understand, that *Chirp is an application, designed to show how skilled thirteen23 designers are. And it achieved this goal. The application is state-of-art, looks and designed very well with taking into account even small details, however it huge, unusable for everyday twittering and extremely slow. This is a general example about Designers’ doctrine.

TwitterFox is very ugly, but concentrated on functionality, tiny and reactive. It includes only features are necessary for twittering and has no other goals. So, this is a general example about Developers’ doctrine.

Is it possible to messmate those doctrines? Probably it is. And it is really simple. Each one of actors should do his own work. Designers should design and Developers – develop. I spoke about it a lot during my lectures, I’ll speak about it also at 11th February in user group meeting. By now, when you know how I see Twitter, you can start following me. Also, I’m interesting to hear your ideas about Designer-Developer intercommunication. It is not just about Microsoft way :)

Designer and Developer - Microsoft way

Have a nice day and be good people.

Recommended

 

Sponsor


Partners

WPF Disciples
Dreamhost
Code Project