How to open Thumbscache.db

Asked by At

I'm trying to open a thumbscache.db file, I've tried to open it like any other database but no use. I've also looked for any API or support in C#. Kindly suggest if there is another way. BTW below is my approach so far.

1. Open it like any other db.

        path = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
        path += @"\Microsoft\Windows\Explorer\thumbcache_1280.db";
        datasource = "Data source = " + path;
        SQLiteCommand cmd = new SQLiteCommand();
        SQLiteConnection conn = new SQLiteConnection(datasource);
        cmd.Connection = conn;
        cmd.CommandText = "SELECT * FROM Filename";
        conn.Open();
        SQLiteDataAdapter sqda = new SQLiteDataAdapter(cmd);
        DataTable dt = new DataTable();
        sqda.Fill(dt);
        dataGridView1.DataSource = dt;
        conn.Close();

But this exception comes up.

enter image description here

2. Open it using ShellFile

        ShellFile shellFile = ShellFile.FromFilePath(path);
        Bitmap bitmap = shellFile.Thumbnail.ExtraLargeBitmap;
        pbThumbs.Image = bitmap;

And instead of thumbscache it gives file thumb icon.

enter image description here

3. Opening as OLE Document using OpenMcdf

        path = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
        path += @"\Microsoft\Windows\Explorer\thumbcache_1280.db";
        CompoundFile cf = new CompoundFile(path);
        CFStream foundStream = cf.RootStorage.GetStream("Filename");
        byte[] temp = foundStream.GetData();

And this exception comes up.

enter image description here

1 Answers

6
JJIqbal On Best Solutions

Following is C# class to open thumbcache*.db files.

public class ThumbCache
{

    private const int WindowsVista = 0x14;
    private const int Windows7 = 0x15;
    private const int Windows8 = 0x1A;
    private const int Windows8v2 = 0x1C;
    private const int Windows8v3 = 0x1E;
    private const int Windows8_1 = 0x1F;
    private const int Windows10 = 0x20;

    private Stream stream;
    private uint fileVersion;

    private byte[] tempBytes = new byte[65536];
    private uint[] entryOffsets;

    public int ImageCount { get { return entryOffsets.Length; } }

    public ThumbCache(string fileName)
    {
        stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
        ReadFromStream(stream);
    }

    public ThumbCache(Stream stream)
    {
        ReadFromStream(stream);
    }

    ~ThumbCache()
    {
        stream.Close();
    }

    private void ReadFromStream(Stream stream)
    {
        stream.Read(tempBytes, 0, 32);

        string magic = Encoding.ASCII.GetString(tempBytes, 0, 4);
        if (!magic.Equals("CMMM"))
            throw new ApplicationException("This is not a valid ThumbCache file.");

        fileVersion = BitConverter.ToUInt32(tempBytes, 4);
        uint fileType = BitConverter.ToUInt32(tempBytes, 8);

        uint firstEntryPtr = 0;
        uint availableEntryPtr = 0;
        if (fileVersion < Windows8v2)
        {
            firstEntryPtr = BitConverter.ToUInt32(tempBytes, 12);
            availableEntryPtr = BitConverter.ToUInt32(tempBytes, 16);
        }
        else
        {
            firstEntryPtr = BitConverter.ToUInt32(tempBytes, 16);
            availableEntryPtr = BitConverter.ToUInt32(tempBytes, 20);
        }

        stream.Seek(firstEntryPtr, SeekOrigin.Begin);

        List<uint> entryOffsetList = new List<uint>();

        try
        {
            uint entrySize;
            while (stream.Position < stream.Length)
            {
                entryOffsetList.Add((uint)stream.Position);

                stream.Read(tempBytes, 0, 8);
                if ((tempBytes[0] != 'C') || (tempBytes[1] != 'M') || (tempBytes[2] != 'M') || (tempBytes[3] != 'M'))
                    break;

                entrySize = BitConverter.ToUInt32(tempBytes, 4);
                stream.Seek(entrySize - 8, SeekOrigin.Current);
            }
        }
        catch { }

        entryOffsets = entryOffsetList.ToArray();
    }

    public ThumbInfo GetImage(int imageIndex, bool needImage)
    {
        if (entryOffsets.Length == 0) return null;
        if ((imageIndex < 0) || (imageIndex >= entryOffsets.Length)) return null;
        return new ThumbInfo(stream, entryOffsets[imageIndex], tempBytes, fileVersion, needImage);
    }

    public Dictionary<string, string> GetMetadata(ThumbInfo info)
    {
        var dict = new Dictionary<string, string>();
        if (entryOffsets.Length == 0) return dict;
        if (info == null) return dict;

        dict.Add("File offset", info.fileOffset.ToString());
        dict.Add("Entry size", info.entrySize.ToString());
        dict.Add("Entry hash", info.entryHash.ToString("X16"));
        dict.Add("Filename length", info.fileNameLength.ToString());
        dict.Add("Padding length", info.paddingLength.ToString());
        dict.Add("Data length", info.dataLength.ToString());
        dict.Add("Image width", info.imageWidth.ToString());
        dict.Add("Image height", info.imageHeight.ToString());
        dict.Add("Data checksum", info.dataChecksum.ToString("X16"));
        dict.Add("Header checksum", info.headerChecksum.ToString("X16"));
        return dict;
    }


    public class ThumbInfo
    {
        public Image image;
        public long fileOffset;
        public uint entrySize;
        public ulong entryHash;
        public uint fileNameLength;
        public uint paddingLength;
        public uint dataLength;
        public ulong dataChecksum;
        public ulong headerChecksum;
        public uint imageWidth;
        public uint imageHeight;

        public ThumbInfo(Stream stream, long offset, byte[] tempBytes, uint fileVersion, bool needImage)
        {
            fileOffset = offset;
            stream.Seek(fileOffset, SeekOrigin.Begin);
            stream.Read(tempBytes, 0, 64);

            int bytePtr = 0;
            string magic = Encoding.ASCII.GetString(tempBytes, bytePtr, 4); bytePtr += 4;
            if (!magic.Equals("CMMM"))
                throw new ApplicationException("Incorrect format.");

            entrySize = BitConverter.ToUInt32(tempBytes, bytePtr); bytePtr += 4;
            entryHash = BitConverter.ToUInt64(tempBytes, bytePtr); bytePtr += 8;

            if (fileVersion == WindowsVista)
            {
                bytePtr += 8; // wchar x 4
            }

            fileNameLength = BitConverter.ToUInt32(tempBytes, bytePtr); bytePtr += 4;
            paddingLength = BitConverter.ToUInt32(tempBytes, bytePtr); bytePtr += 4;
            dataLength = BitConverter.ToUInt32(tempBytes, bytePtr); bytePtr += 4;

            if (fileVersion >= Windows8)
            {
                imageWidth = BitConverter.ToUInt32(tempBytes, bytePtr); bytePtr += 4;
                imageHeight = BitConverter.ToUInt32(tempBytes, bytePtr); bytePtr += 4;
            }

            bytePtr += 4; // unknown

            dataChecksum = BitConverter.ToUInt64(tempBytes, bytePtr); bytePtr += 8;
            headerChecksum = BitConverter.ToUInt64(tempBytes, bytePtr); bytePtr += 8;

            if (!needImage || dataLength == 0 || dataLength > 0x1000000)
                return;

            stream.Seek(fileOffset + entrySize - dataLength, SeekOrigin.Begin);
            if (dataLength > tempBytes.Length)
                tempBytes = new byte[dataLength];

            stream.Read(tempBytes, 0, (int)dataLength);
            using (var mstream = new MemoryStream(tempBytes))
            {
                image = new Bitmap(mstream);
            }
        }

    }
}

Detailed solution here .