Преглед изворни кода

Merge pull request #469 from tomaszkot/master

PixiThumbnailProvider 0.9 done in native mode
Egor Mozgovoy пре 2 година
родитељ
комит
fa38cc3fc4
18 измењених фајлова са 997 додато и 0 уклоњено
  1. 1 0
      src/PixiThumbnailProvider/InstallPixiThumbnailProviderServer.bat
  2. 36 0
      src/PixiThumbnailProvider/PixiThumbnailProvider.sln
  3. 255 0
      src/PixiThumbnailProvider/PixiThumbnailProvider/Dll.cpp
  4. 144 0
      src/PixiThumbnailProvider/PixiThumbnailProvider/PixiThumbnailProvider.cpp
  5. 6 0
      src/PixiThumbnailProvider/PixiThumbnailProvider/PixiThumbnailProvider.def
  6. 132 0
      src/PixiThumbnailProvider/PixiThumbnailProvider/PixiThumbnailProvider.vcxproj
  7. 2 0
      src/PixiThumbnailProvider/PixiThumbnailProvider/PngImageProvider.cpp
  8. 142 0
      src/PixiThumbnailProvider/PixiThumbnailProvider/PngImageProvider.h
  9. 0 0
      src/PixiThumbnailProvider/PixiThumbnailProvider/README.md
  10. 60 0
      src/PixiThumbnailProvider/PixiThumbnailProvider/Utils.h
  11. 59 0
      src/PixiThumbnailProvider/PixiThumbnailProviderTests/ThumbnailProviderTests.cpp
  12. 112 0
      src/PixiThumbnailProvider/PixiThumbnailProviderTests/ThumbnailProviderTests.vcxproj
  13. 30 0
      src/PixiThumbnailProvider/PixiThumbnailProviderTests/ThumbnailProviderTests.vcxproj.filters
  14. BIN
      src/PixiThumbnailProvider/PixiThumbnailProviderTests/images/p1.pixi
  15. BIN
      src/PixiThumbnailProvider/PixiThumbnailProviderTests/images/sdf.png
  16. 5 0
      src/PixiThumbnailProvider/PixiThumbnailProviderTests/pch.cpp
  17. 12 0
      src/PixiThumbnailProvider/PixiThumbnailProviderTests/pch.h
  18. 1 0
      src/PixiThumbnailProvider/UninstallPixiThumbnailProviderServer.bat

+ 1 - 0
src/PixiThumbnailProvider/InstallPixiThumbnailProviderServer.bat

@@ -0,0 +1 @@
+C:\Windows\SysWOW64\regsvr32.exe PixiThumbnailProvider\x64\Release\PixiThumbnailProvider.dll

+ 36 - 0
src/PixiThumbnailProvider/PixiThumbnailProvider.sln

@@ -0,0 +1,36 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.32002.261
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PixiThumbnailProvider", "PixiThumbnailProvider\PixiThumbnailProvider.vcxproj", "{3AF44F8C-A331-4D74-995A-9BDF157E4B8A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ThumbnailProviderTests", "PixiThumbnailProviderTests\ThumbnailProviderTests.vcxproj", "{69CEF7E1-53F8-4771-975A-1F059A3B19F8}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Debug|x64 = Debug|x64
+		Release|Win32 = Release|Win32
+		Release|x64 = Release|x64
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{3AF44F8C-A331-4D74-995A-9BDF157E4B8A}.Debug|Win32.ActiveCfg = Debug|x64
+		{3AF44F8C-A331-4D74-995A-9BDF157E4B8A}.Debug|x64.ActiveCfg = Debug|x64
+		{3AF44F8C-A331-4D74-995A-9BDF157E4B8A}.Debug|x64.Build.0 = Debug|x64
+		{3AF44F8C-A331-4D74-995A-9BDF157E4B8A}.Release|Win32.ActiveCfg = Release|x64
+		{3AF44F8C-A331-4D74-995A-9BDF157E4B8A}.Release|x64.ActiveCfg = Release|x64
+		{3AF44F8C-A331-4D74-995A-9BDF157E4B8A}.Release|x64.Build.0 = Release|x64
+		{69CEF7E1-53F8-4771-975A-1F059A3B19F8}.Debug|Win32.ActiveCfg = Debug|x64
+		{69CEF7E1-53F8-4771-975A-1F059A3B19F8}.Debug|x64.ActiveCfg = Debug|x64
+		{69CEF7E1-53F8-4771-975A-1F059A3B19F8}.Debug|x64.Build.0 = Debug|x64
+		{69CEF7E1-53F8-4771-975A-1F059A3B19F8}.Release|Win32.ActiveCfg = Release|x64
+		{69CEF7E1-53F8-4771-975A-1F059A3B19F8}.Release|x64.ActiveCfg = Release|x64
+		{69CEF7E1-53F8-4771-975A-1F059A3B19F8}.Release|x64.Build.0 = Release|x64
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {17A84B81-5FC0-4B34-831C-83229B432D41}
+	EndGlobalSection
+EndGlobal

+ 255 - 0
src/PixiThumbnailProvider/PixiThumbnailProvider/Dll.cpp

@@ -0,0 +1,255 @@
+#include <objbase.h>
+#include <shlwapi.h>
+#include <thumbcache.h> // For IThumbnailProvider.
+#include <shlobj.h>     // For SHChangeNotify
+#include <string>
+
+extern HRESULT CPixiThumbProvider_CreateInstance(REFIID riid, void **ppv);
+
+#define SZ_CLSID_PIXITHUMBHANDLER     L"{50d9460f-2a80-4f08-93b9-2eb526477d1b}"
+#define SZ_PIXITHUMBHANDLER           L"Pixi Thumbnail Handler"
+
+const CLSID CLSID_PixiThumbHandler    = {0x50d9460f, 0x2a80, 0x4f08, {0x93, 0xb9, 0x2e, 0xb5, 0x26, 0x47, 0x7d, 0x1b}};
+
+typedef HRESULT (*PFNCREATEINSTANCE)(REFIID riid, void **ppvObject);
+struct CLASS_OBJECT_INIT
+{
+    const CLSID *pClsid;
+    PFNCREATEINSTANCE pfnCreate;
+};
+
+// add classes supported by this module here
+const CLASS_OBJECT_INIT c_rgClassObjectInit[] =
+{
+    { &CLSID_PixiThumbHandler, CPixiThumbProvider_CreateInstance }
+};
+
+
+long g_cRefModule = 0;
+
+// Handle the the DLL's module
+HINSTANCE g_hInst = NULL;
+
+// Standard DLL functions
+STDAPI_(BOOL) DllMain(HINSTANCE hInstance, DWORD dwReason, void *)
+{
+    if (dwReason == DLL_PROCESS_ATTACH)
+    {
+        g_hInst = hInstance;
+        DisableThreadLibraryCalls(hInstance);
+    }
+    return TRUE;
+}
+
+STDAPI DllCanUnloadNow()
+{
+    // Only allow the DLL to be unloaded after all outstanding references have been released
+    return (g_cRefModule == 0) ? S_OK : S_FALSE;
+}
+
+void DllAddRef()
+{
+    InterlockedIncrement(&g_cRefModule);
+}
+
+void DllRelease()
+{
+    InterlockedDecrement(&g_cRefModule);
+}
+
+class CClassFactory : public IClassFactory
+{
+public:
+    static HRESULT CreateInstance(REFCLSID clsid, const CLASS_OBJECT_INIT *pClassObjectInits, size_t cClassObjectInits, REFIID riid, void **ppv)
+    {
+        *ppv = NULL;
+        HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
+        for (size_t i = 0; i < cClassObjectInits; i++)
+        {
+            if (clsid == *pClassObjectInits[i].pClsid)
+            {
+                IClassFactory *pClassFactory = new (std::nothrow) CClassFactory(pClassObjectInits[i].pfnCreate);
+                hr = pClassFactory ? S_OK : E_OUTOFMEMORY;
+                if (SUCCEEDED(hr))
+                {
+                    hr = pClassFactory->QueryInterface(riid, ppv);
+                    pClassFactory->Release();
+                }
+                break; // match found
+            }
+        }
+        return hr;
+    }
+
+    CClassFactory(PFNCREATEINSTANCE pfnCreate) : _cRef(1), _pfnCreate(pfnCreate)
+    {
+        DllAddRef();
+    }
+
+    // IUnknown
+    IFACEMETHODIMP QueryInterface(REFIID riid, void ** ppv)
+    {
+        static const QITAB qit[] =
+        {
+            QITABENT(CClassFactory, IClassFactory),
+            { 0 }
+        };
+        return QISearch(this, qit, riid, ppv);
+    }
+
+    IFACEMETHODIMP_(ULONG) AddRef()
+    {
+        return InterlockedIncrement(&_cRef);
+    }
+
+    IFACEMETHODIMP_(ULONG) Release()
+    {
+        long cRef = InterlockedDecrement(&_cRef);
+        if (cRef == 0)
+        {
+            delete this;
+        }
+        return cRef;
+    }
+
+    // IClassFactory
+    IFACEMETHODIMP CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
+    {
+        return punkOuter ? CLASS_E_NOAGGREGATION : _pfnCreate(riid, ppv);
+    }
+
+    IFACEMETHODIMP LockServer(BOOL fLock)
+    {
+        if (fLock)
+        {
+            DllAddRef();
+        }
+        else
+        {
+            DllRelease();
+        }
+        return S_OK;
+    }
+
+private:
+    ~CClassFactory()
+    {
+        DllRelease();
+    }
+
+    long _cRef;
+    PFNCREATEINSTANCE _pfnCreate;
+};
+
+STDAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **ppv)
+{
+    return CClassFactory::CreateInstance(clsid, c_rgClassObjectInit, ARRAYSIZE(c_rgClassObjectInit), riid, ppv);
+}
+
+// A struct to hold the information required for a registry entry
+
+struct REGISTRY_ENTRY
+{
+    HKEY   hkeyRoot;
+    PCWSTR pszKeyName;
+    PCWSTR pszValueName;
+    PCWSTR pszData;
+    bool DWORD = false;
+};
+
+// Creates a registry key (if needed) and sets the default value of the key
+
+HRESULT CreateRegKeyAndSetValue(const REGISTRY_ENTRY *pRegistryEntry)
+{
+    HKEY hKey;
+    HRESULT hr = HRESULT_FROM_WIN32(RegCreateKeyExW(pRegistryEntry->hkeyRoot, pRegistryEntry->pszKeyName,
+                                0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hKey, NULL));
+    if (SUCCEEDED(hr))
+    {
+        DWORD type = REG_SZ;
+        unsigned int size = ((DWORD)wcslen(pRegistryEntry->pszData) + 1) * sizeof(WCHAR);
+        DWORD value = 0;
+        if (pRegistryEntry->DWORD)
+        {
+            type = REG_DWORD;
+            size = 4;
+            value = stoul(std::wstring(pRegistryEntry->pszData));
+            hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, pRegistryEntry->pszValueName, 0, type,
+                (LPBYTE)&value,
+                size));
+        }
+        else
+            hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, pRegistryEntry->pszValueName, 0, type,
+                            (LPBYTE) pRegistryEntry->pszData,
+                            size));
+        RegCloseKey(hKey);
+    }
+    return hr;
+}
+
+//
+// Registers this COM server
+//
+STDAPI DllRegisterServer()
+{
+    HRESULT hr;
+
+    WCHAR szModuleName[MAX_PATH];
+
+    if (!GetModuleFileNameW(g_hInst, szModuleName, ARRAYSIZE(szModuleName)))
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+    }
+    else
+    {
+        // List of registry entries we want to create
+        const REGISTRY_ENTRY rgRegistryEntries[] =
+        {
+            // RootKey            KeyName                                                                ValueName                     Data
+            {HKEY_CURRENT_USER,   L"Software\\Classes\\CLSID\\" SZ_CLSID_PIXITHUMBHANDLER,                                 NULL,                           SZ_PIXITHUMBHANDLER},
+            {HKEY_CURRENT_USER,   L"Software\\Classes\\CLSID\\" SZ_CLSID_PIXITHUMBHANDLER L"\\InProcServer32",             NULL,                           szModuleName},
+            {HKEY_CURRENT_USER,   L"Software\\Classes\\CLSID\\" SZ_CLSID_PIXITHUMBHANDLER L"\\InProcServer32",             L"ThreadingModel",              L"Apartment"},
+            {HKEY_CURRENT_USER,   L"Software\\Classes\\CLSID\\" SZ_CLSID_PIXITHUMBHANDLER,                                 L"DisableProcessIsolation",     L"1", true},
+            {HKEY_CURRENT_USER,   L"Software\\Classes\\.pixi\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}",            NULL,                           SZ_CLSID_PIXITHUMBHANDLER},
+        };
+
+        hr = S_OK;
+        for (int i = 0; i < ARRAYSIZE(rgRegistryEntries) && SUCCEEDED(hr); i++) 
+        {
+            hr = CreateRegKeyAndSetValue(&rgRegistryEntries[i]);
+        }
+    }
+    if (SUCCEEDED(hr))
+    {
+        // This tells the shell to invalidate the thumbnail cache.  This is important because any .pixi files
+        // viewed before registering this handler would otherwise show cached blank thumbnails.
+        SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
+    }
+    return hr;
+}
+
+//
+// Unregisters this COM server
+//
+STDAPI DllUnregisterServer()
+{
+    HRESULT hr = S_OK;
+
+    const PCWSTR rgpszKeys[] =
+    {
+        L"Software\\Classes\\CLSID\\" SZ_CLSID_PIXITHUMBHANDLER,
+        L"Software\\Classes\\.pixi\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}"
+    };
+
+    // Delete the registry entries
+    for (int i = 0; i < ARRAYSIZE(rgpszKeys) && SUCCEEDED(hr); i++)
+    {
+        hr = HRESULT_FROM_WIN32(RegDeleteTreeW(HKEY_CURRENT_USER, rgpszKeys[i]));
+        if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
+        {
+            // If the registry entry has already been deleted, say S_OK.
+            hr = S_OK;
+        }
+    }
+    return hr;
+}

+ 144 - 0
src/PixiThumbnailProvider/PixiThumbnailProvider/PixiThumbnailProvider.cpp

@@ -0,0 +1,144 @@
+#include <shlwapi.h>
+#include <thumbcache.h> // For IThumbnailProvider.
+
+#pragma comment(lib, "shlwapi.lib")
+#pragma comment(lib, "windowscodecs.lib")
+#pragma comment(lib, "Crypt32.lib")
+#pragma comment(lib, "msxml6.lib")
+
+#include <fstream>
+#include <string>
+#include <iostream>
+
+#include <string>
+#include <filesystem>
+#include "PngImageProvider.h"
+namespace fs = std::filesystem;
+
+static void GetEnvTempPath(std::wstring& input_parameter) {
+    wchar_t* env_var_buffer = nullptr;
+    std::size_t size = 0;
+    if (_wdupenv_s(&env_var_buffer, &size, L"TEMP") == 0 &&
+        env_var_buffer != nullptr) {
+        input_parameter = static_cast<const wchar_t*>(env_var_buffer);
+    }
+}
+
+void log(std::wstring line)
+{
+    try
+    {
+        std::wstring tmpPath;
+        GetEnvTempPath(tmpPath);
+        std::wofstream out(tmpPath + L"/PixiEditor/ThumbnailOutput.txt", std::ios_base::app);
+        out << line << std::endl;
+        out.close();
+    }
+    catch (const std::exception&)
+    {
+        //ups log to EventLog?
+    }
+}
+
+void log(std::string line)
+{
+    log(std::wstring(line.begin(), line.end()));
+}
+
+// this thumbnail provider implements IInitializeWithFile 
+class CPixiThumbProvider : public IInitializeWithFile, public IThumbnailProvider
+{
+public:
+    CPixiThumbProvider() : _cRef(1){
+    }
+
+    virtual ~CPixiThumbProvider(){
+    }
+
+    // IUnknown
+    IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv)
+    {
+        static const QITAB qit[] =
+        {
+            QITABENT(CPixiThumbProvider, IInitializeWithFile),
+            QITABENT(CPixiThumbProvider, IThumbnailProvider),
+            { 0 },
+        };
+        return QISearch(this, qit, riid, ppv);
+    }
+
+    IFACEMETHODIMP_(ULONG) AddRef()
+    {
+        return InterlockedIncrement(&_cRef);
+    }
+
+    IFACEMETHODIMP_(ULONG) Release()
+    {
+        ULONG cRef = InterlockedDecrement(&_cRef);
+        if (!cRef)
+        {
+            delete this;
+        }
+        return cRef;
+    }
+
+    IFACEMETHODIMP Initialize(LPCWSTR pszFilePath, DWORD grfMode);
+
+    // IThumbnailProvider
+    IFACEMETHODIMP GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_ALPHATYPE *pdwAlpha);
+
+private:
+
+    long _cRef;
+    std::wstring m_filePath;
+};
+
+HRESULT CPixiThumbProvider_CreateInstance(REFIID riid, void **ppv)
+{
+    CPixiThumbProvider *pNew = new (std::nothrow) CPixiThumbProvider();
+    HRESULT hr = pNew ? S_OK : E_OUTOFMEMORY;
+    if (SUCCEEDED(hr))
+    {
+        hr = pNew->QueryInterface(riid, ppv);
+        pNew->Release();
+    }
+    return hr;
+}
+
+IFACEMETHODIMP CPixiThumbProvider::Initialize(LPCWSTR pszFilePath, DWORD /*grfMode*/)
+{
+    m_filePath = pszFilePath;
+    std::wstring tmpPath;
+    GetEnvTempPath(tmpPath);
+    log(L"1)  m_filePath:" + std::wstring(m_filePath));
+    auto ext = fs::path(m_filePath).extension().string();
+    if(ext != ".pixi")
+      return  S_FALSE;
+    return S_OK;
+}
+
+IFACEMETHODIMP CPixiThumbProvider::GetThumbnail(UINT /*cx*/, HBITMAP *phbmp, WTS_ALPHATYPE */*pdwAlpha*/)
+{
+    log(L"2) GetThumbnail called! m_filePath: "+ std::wstring(m_filePath));
+    try
+    {
+        HBITMAP tmpBmp = nullptr;
+        PngImageProvider pngBitmapProvider([](std::wstring line) { log(line); });
+        ULONG_PTR gdiplusToken;
+
+        tmpBmp = pngBitmapProvider.LoadPixiBitmapPreviewHandle(m_filePath.c_str(), gdiplusToken);
+        
+        if (tmpBmp != nullptr)
+        {
+            *phbmp = tmpBmp;
+            return  S_OK;
+        }
+        return  S_FALSE;
+    }
+    catch (const std::exception& ex)
+    {
+        log(ex.what());
+        return  S_FALSE;
+    }
+}
+

+ 6 - 0
src/PixiThumbnailProvider/PixiThumbnailProvider/PixiThumbnailProvider.def

@@ -0,0 +1,6 @@
+EXPORTS
+    DllGetClassObject       PRIVATE
+    DllCanUnloadNow         PRIVATE
+    DllRegisterServer       PRIVATE
+    DllUnregisterServer     PRIVATE
+                    

+ 132 - 0
src/PixiThumbnailProvider/PixiThumbnailProvider/PixiThumbnailProvider.vcxproj

@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{3AF44F8C-A331-4D74-995A-9BDF157E4B8A}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <ProjectName>PixiThumbnailProvider</ProjectName>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <PlatformToolset>v142</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <PlatformToolset>v142</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup>
+    <_ProjectFileVersion>16.0.32002.118</_ProjectFileVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <OutDir>$(Platform)\$(Configuration)\</OutDir>
+    <IntDir>$(Platform)\$(Configuration)\</IntDir>
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <OutDir>$(Platform)\$(Configuration)\</OutDir>
+    <IntDir>$(Platform)\$(Configuration)\</IntDir>
+    <LinkIncremental>false</LinkIncremental>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Midl>
+      <TargetEnvironment>X64</TargetEnvironment>
+    </Midl>
+    <ClCompile>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;PIXITHUMBNAILPROVIDER_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <MinimalRebuild>true</MinimalRebuild>
+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <PrecompiledHeader />
+      <WarningLevel>Level4</WarningLevel>
+      <TreatWarningAsError>false</TreatWarningAsError>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <LanguageStandard>stdcpp17</LanguageStandard>
+    </ClCompile>
+    <Link>
+      <OutputFile>$(OutDir)PixiThumbnailProvider.dll</OutputFile>
+      <ModuleDefinitionFile>PixiThumbnailProvider.def</ModuleDefinitionFile>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <ProgramDatabaseFile>$(OutDir)PixiHandlers.pdb</ProgramDatabaseFile>
+      <SubSystem>Windows</SubSystem>
+      <RandomizedBaseAddress>true</RandomizedBaseAddress>
+      <DataExecutionPrevention>true</DataExecutionPrevention>
+      <ImportLibrary>$(OutDir)PixiThumbnailProvider.lib</ImportLibrary>
+      <TargetMachine>MachineX64</TargetMachine>
+    </Link>
+    <PostBuildEvent>
+      <Command>
+      </Command>
+    </PostBuildEvent>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Midl>
+      <TargetEnvironment>X64</TargetEnvironment>
+    </Midl>
+    <ClCompile>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;PIXITHUMBNAILPROVIDER_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <PrecompiledHeader />
+      <WarningLevel>Level4</WarningLevel>
+      <TreatWarningAsError>false</TreatWarningAsError>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <LanguageStandard>stdcpp17</LanguageStandard>
+    </ClCompile>
+    <Link>
+      <OutputFile>$(OutDir)PixiThumbnailProvider.dll</OutputFile>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Windows</SubSystem>
+      <OptimizeReferences>true</OptimizeReferences>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <RandomizedBaseAddress>true</RandomizedBaseAddress>
+      <DataExecutionPrevention>true</DataExecutionPrevention>
+      <ImportLibrary>$(OutDir)PixiThumbnailProvider.lib</ImportLibrary>
+      <TargetMachine>MachineX64</TargetMachine>
+      <ModuleDefinitionFile>PixiThumbnailProvider.def</ModuleDefinitionFile>
+    </Link>
+    <PostBuildEvent>
+      <Command>
+      </Command>
+    </PostBuildEvent>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <None Include="PixiThumbnailProvider.def" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="Dll.cpp" />
+    <ClCompile Include="PixiThumbnailProvider.cpp" />
+    <ClCompile Include="PngImageProvider.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="PngImageProvider.h" />
+    <ClInclude Include="Utils.h" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 2 - 0
src/PixiThumbnailProvider/PixiThumbnailProvider/PngImageProvider.cpp

@@ -0,0 +1,2 @@
+#include "PngImageProvider.h"
+

+ 142 - 0
src/PixiThumbnailProvider/PixiThumbnailProvider/PngImageProvider.h

@@ -0,0 +1,142 @@
+#pragma once
+#include <shlwapi.h>
+#include <wincodec.h>
+#include <string>
+#include <functional>
+#include <gdiplus.h>
+#include <stdexcept>
+#include "Utils.h"
+
+#pragma comment(lib, "gdiplus.lib")
+#pragma comment(lib, "windowscodecs.lib")
+
+#include <iostream>
+#include <objidl.h>
+#include <gdiplus.h>
+#pragma warning(disable : 4996)
+#pragma warning(disable : 4458)
+
+class PngImageProvider
+{
+  std::function<void(std::wstring)> m_logger;
+
+  HBITMAP HandleFromBitmap(Gdiplus::Bitmap* bmp)
+  {
+    HBITMAP hBitmap = nullptr;
+    bmp->GetHBITMAP(Gdiplus::Color(0xFFFFFFFF), &hBitmap);
+    return hBitmap;
+  }
+
+public:
+  PngImageProvider(std::function<void(std::wstring)> logger)
+  {
+    m_logger = logger;
+  }
+
+  void Save(std::wstring filePath, HBITMAP bitmap)
+  {
+    //auto palette = (HPALETTE)GetStockObject(DEFAULT_PALETTE);
+    auto palette = (HPALETTE)0;
+    auto bmp = Gdiplus::Bitmap::FromHBITMAP(bitmap, palette);
+    Save(filePath, bmp);
+  }
+
+  void Save(std::wstring filePath, Gdiplus::Bitmap* bmp)
+  {
+    CLSID pngClsid;
+    CLSIDFromString(L"{557CF406-1A04-11D3-9A73-0000F81EF32E}", &pngClsid);
+    bmp->Save(filePath.c_str(), &pngClsid, NULL);
+  }
+
+  template<typename T>
+  IStream* StreamFromBytes(std::vector<T> bytes)
+  {
+    return SHCreateMemStream(&bytes[0], (UINT)bytes.size());;
+  }
+
+  template<typename T>
+  HBITMAP LoadPngHandle(std::vector<T> bytes, ULONG_PTR& gdiplusToken)
+  {
+    auto stream = StreamFromBytes(bytes);
+    return LoadPngHandle(stream, gdiplusToken);
+  }
+
+  template<typename T>
+  Gdiplus::Bitmap* LoadPngImage(std::vector<T> bytes, ULONG_PTR& gdiplusToken)
+  {
+    auto stream = StreamFromBytes(bytes);
+    return LoadPngImage(stream, gdiplusToken);
+  }
+
+  std::vector<unsigned char> LoadPixiPreviewBytes(std::string pixiFile)
+  {
+    std::wstring pixiFileW(pixiFile.begin(), pixiFile.end());
+    return LoadPixiPreviewBytes(pixiFileW);
+  }
+
+  std::vector<unsigned char> LoadPixiPreviewBytes(std::wstring pixiFile)
+  {
+    auto streamPos = 0;
+
+    load_bytes<unsigned char>(pixiFile, streamPos, 21);//header
+    streamPos += 21;
+    auto previewHeader = load_bytes<unsigned char>(pixiFile, 21, 4);
+    streamPos += 4;
+
+    const auto previewSize = BytesToInt32(previewHeader, 0, true);
+
+    auto bytes = load_bytes<unsigned char>(pixiFile, streamPos, previewSize);
+    return bytes;
+  }
+
+  HBITMAP LoadPixiBitmapPreviewHandle(std::string pixiFilePath, ULONG_PTR& gdiplusToken)
+  {
+    auto bytes = LoadPixiPreviewBytes(pixiFilePath);
+    return LoadPngHandle(bytes, gdiplusToken);
+  }
+
+  HBITMAP LoadPixiBitmapPreviewHandle(std::wstring pixiFilePath, ULONG_PTR& gdiplusToken)
+  {
+    auto bytes = LoadPixiPreviewBytes(pixiFilePath);
+    return LoadPngHandle(bytes, gdiplusToken);
+  }
+
+  Gdiplus::Bitmap* LoadPixiBitmapPreview(std::string pixiFilePath, ULONG_PTR& gdiplusToken)
+  {
+    auto bytes = LoadPixiPreviewBytes(pixiFilePath);
+    return LoadPngImage(bytes, gdiplusToken);
+  }
+
+private:
+
+  Gdiplus::Bitmap* PngImageProvider::LoadPngImage(IStream* stream, ULONG_PTR& gdiplusToken)
+  {
+    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
+    Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
+    auto bmp = Gdiplus::Bitmap::FromStream(stream);
+    if (!bmp)
+    {
+      m_logger(L" Unable to open image file with Gdiplus.");
+      return nullptr;
+    }
+    //Gdiplus::GdiplusShutdown(gdiplusToken);will make bmp* corrupted
+
+    return bmp;
+  }
+    
+
+  HBITMAP LoadPngHandle(IStream* stream, ULONG_PTR& gdiplusToken)
+  {
+    auto bmp = LoadPngImage(stream, gdiplusToken);
+    if (!bmp)
+    {
+      m_logger(L" Unable to open image file with Gdiplus.");
+      return nullptr;
+    }
+    auto hBitmap = HandleFromBitmap(bmp);
+    //Gdiplus::GdiplusShutdown(gdiplusToken); //would corrupt handle
+    return hBitmap;
+  }
+
+};
+

+ 0 - 0
src/PixiThumbnailProvider/PixiThumbnailProvider/README.md


+ 60 - 0
src/PixiThumbnailProvider/PixiThumbnailProvider/Utils.h

@@ -0,0 +1,60 @@
+#pragma once
+#include <string>
+#include <vector>
+#include <iostream>
+#include <fstream>
+#include <filesystem>
+
+inline int BytesToInt32(std::vector<unsigned char>& input, int startOffset, bool isLittleEndian)
+{
+  if (input.empty()) {
+    std::cerr << "FATAL: Null input byte vector";
+    return 0;
+  }
+  if ((unsigned int)startOffset >= input.size()) {
+    std::cerr << "FATAL: Out of Range";
+    return 0;
+  }
+  if (startOffset > input.size() - 4) {
+    std::cerr << "FATAL: Input byte vector is too small";
+    return 0;
+  }
+
+  // 0x00000000
+  if (isLittleEndian) {       // MSB is loacted in higher address.
+    return (input[startOffset]) | (input[startOffset + 1] << 8) |
+      (input[startOffset + 2] << 16) | (input[startOffset + 3] << 24);
+  }
+  else {                    // MSB is located in lower address.
+    return (input[startOffset] << 24) | (input[startOffset] << 16) |
+      (input[startOffset] << 8) | (input[startOffset]);
+  }
+}
+
+template<typename T>
+std::vector<T> load_bytes(std::wstring const& filepath, int skipBytes = 0, int size = 0)
+{
+  std::ifstream ifs(filepath, std::ios::binary);
+
+  if (!ifs)
+  {
+    const std::string path = std::filesystem::path(filepath).string();
+    throw std::runtime_error(path +": " + std::strerror(errno));
+  }
+
+  ifs.seekg(skipBytes, std::ios::beg);
+
+  if (size == 0)
+    return {};
+
+  std::vector<T> buffer(size);
+
+  if (!ifs.read((char*)buffer.data(), buffer.size()))
+  {
+    const std::string path = std::filesystem::path(filepath).string();
+    throw std::runtime_error(path +": " + std::strerror(errno));
+  }
+
+  return buffer;
+}
+

+ 59 - 0
src/PixiThumbnailProvider/PixiThumbnailProviderTests/ThumbnailProviderTests.cpp

@@ -0,0 +1,59 @@
+#include "pch.h"
+#include "CppUnitTest.h"
+#include "../PixiThumbnailProvider/PngImageProvider.h"
+#include <iostream>
+#include <vector>
+#include <memory>
+#pragma comment(lib, "gdiplus.lib")
+
+using namespace Microsoft::VisualStudio::CppUnitTestFramework;
+
+namespace ThumbnailProviderTests
+{
+  TEST_CLASS(ThumbnailProviderTests)
+  {
+  public:
+
+    static void GetEnvTempPath(std::wstring& input_parameter) {
+      wchar_t* env_var_buffer = nullptr;
+      std::size_t size = 0;
+      if (_wdupenv_s(&env_var_buffer, &size, L"TEMP") == 0 &&
+        env_var_buffer != nullptr) {
+        input_parameter = static_cast<const wchar_t*>(env_var_buffer);
+      }
+    }
+
+    TEST_METHOD(ExtractPngFromPixi)
+    {
+      std::wstring input_parameter;
+      GetEnvTempPath(input_parameter);
+      auto pixiFile = "images\\p1.pixi";
+      
+      PngImageProvider pngBitmapProvider([](std::wstring line) {
+        std::wcout << line;
+        });
+
+      ULONG_PTR gdiplusToken1;
+      auto imageHandle = pngBitmapProvider.LoadPixiBitmapPreviewHandle(pixiFile, gdiplusToken1);
+      pngBitmapProvider.Save(L"images\\fromPixiFileAsHandle.png", imageHandle);
+
+      ULONG_PTR gdiplusToken;
+      auto image = pngBitmapProvider.LoadPixiBitmapPreview(pixiFile, gdiplusToken);
+      Assert::IsNotNull(image);
+      pngBitmapProvider.Save(L"images\\fromPixiFile.png", image);
+
+      //save to a file
+      //SaveBytesAsImage(bytes);
+    }
+    void SaveBytesAsImage()
+    {
+      PngImageProvider pngBitmapProvider([](std::wstring line) {
+        std::wcout << line;
+        });
+      auto pixiFile = "images\\p1.pixi";
+      auto bytes = pngBitmapProvider.LoadPixiPreviewBytes(pixiFile);
+      std::ofstream outfile("images\\p1.png", std::ios::out | std::ios::binary);
+      outfile.write((const char*)&bytes[0], bytes.size());
+    }
+  };
+}

+ 112 - 0
src/PixiThumbnailProvider/PixiThumbnailProviderTests/ThumbnailProviderTests.vcxproj

@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <VCProjectVersion>16.0</VCProjectVersion>
+    <ProjectGuid>{69CEF7E1-53F8-4771-975A-1F059A3B19F8}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>ThumbnailProviderTests</RootNamespace>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+    <ProjectSubType>NativeUnitTestProject</ProjectSubType>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+    <UseOfMfc>false</UseOfMfc>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+    <UseOfMfc>false</UseOfMfc>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="Shared">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <LinkIncremental>false</LinkIncremental>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <SDLCheck>true</SDLCheck>
+      <AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <UseFullPaths>true</UseFullPaths>
+      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+      <LanguageStandard>stdcpp17</LanguageStandard>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalDependencies>Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+    <PostBuildEvent>
+      <Command>xcopy /E /Y "$(ProjectDir)images\*" "$(OutDir)images\"</Command>
+    </PostBuildEvent>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <UseFullPaths>true</UseFullPaths>
+      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+      <LanguageStandard>stdcpp17</LanguageStandard>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalDependencies>Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+    <PostBuildEvent>
+      <Command>xcopy /E /Y "$(ProjectDir)images\*" "$(OutDir)images\"</Command>
+    </PostBuildEvent>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="pch.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="ThumbnailProviderTests.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="pch.h" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 30 - 0
src/PixiThumbnailProvider/PixiThumbnailProviderTests/ThumbnailProviderTests.vcxproj.filters

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="ThumbnailProviderTests.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="pch.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="pch.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+</Project>

BIN
src/PixiThumbnailProvider/PixiThumbnailProviderTests/images/p1.pixi


BIN
src/PixiThumbnailProvider/PixiThumbnailProviderTests/images/sdf.png


+ 5 - 0
src/PixiThumbnailProvider/PixiThumbnailProviderTests/pch.cpp

@@ -0,0 +1,5 @@
+// pch.cpp: source file corresponding to the pre-compiled header
+
+#include "pch.h"
+
+// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.

+ 12 - 0
src/PixiThumbnailProvider/PixiThumbnailProviderTests/pch.h

@@ -0,0 +1,12 @@
+// pch.h: This is a precompiled header file.
+// Files listed below are compiled only once, improving build performance for future builds.
+// This also affects IntelliSense performance, including code completion and many code browsing features.
+// However, files listed here are ALL re-compiled if any one of them is updated between builds.
+// Do not add files here that you will be updating frequently as this negates the performance advantage.
+
+#ifndef PCH_H
+#define PCH_H
+
+// add headers that you want to pre-compile here
+
+#endif //PCH_H

+ 1 - 0
src/PixiThumbnailProvider/UninstallPixiThumbnailProviderServer.bat

@@ -0,0 +1 @@
+C:\Windows\SysWOW64\regsvr32.exe /u PixiThumbnailProvider\x64\Release\PixiThumbnailProvider.dll