main 7c5a6d30077d cached
39 files
82.4 KB
24.1k tokens
35 symbols
1 requests
Download .txt
Repository: jixunmoe/mfcDuDownloadCodeGenerator
Branch: main
Commit: 7c5a6d30077d
Files: 39
Total size: 82.4 KB

Directory structure:
gitextract_vof0guyl/

├── .gitattributes
├── .github/
│   └── workflows/
│       └── msvc.yml
├── .gitignore
├── LICENSE
├── README.MD
├── generator/
│   ├── AdvEdit.cpp
│   ├── AdvEdit.h
│   ├── ClipboardHelper.cpp
│   ├── ClipboardHelper.h
│   ├── DPISupport.cpp
│   ├── DPISupport.h
│   ├── FileItem.cpp
│   ├── FileItem.h
│   ├── Hasher.cpp
│   ├── Hasher.h
│   ├── ListBoxEx.cpp
│   ├── ListBoxEx.h
│   ├── ProgressText.cpp
│   ├── ProgressText.h
│   ├── ReadMe.txt
│   ├── appDlg.cpp
│   ├── appDlg.h
│   ├── base64.cpp
│   ├── base64.h
│   ├── encoding.cpp
│   ├── encoding.h
│   ├── generator.cpp
│   ├── generator.h
│   ├── generator.rc
│   ├── generator.vcxproj
│   ├── generator.vcxproj.filters
│   ├── res/
│   │   └── generator.rc2
│   ├── resource.h
│   ├── stdafx.cpp
│   ├── stdafx.h
│   ├── targetver.h
│   ├── utils.cpp
│   └── utils.h
└── mfcDuDownloadCodeGenerator.sln

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitattributes
================================================
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto

###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs     diff=csharp

###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following 
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln       merge=binary
#*.csproj    merge=binary
#*.vbproj    merge=binary
#*.vcxproj   merge=binary
#*.vcproj    merge=binary
#*.dbproj    merge=binary
#*.fsproj    merge=binary
#*.lsproj    merge=binary
#*.wixproj   merge=binary
#*.modelproj merge=binary
#*.sqlproj   merge=binary
#*.wwaproj   merge=binary

###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg   binary
#*.png   binary
#*.gif   binary

###############################################################################
# diff behavior for common document formats
# 
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the 
# entries below.
###############################################################################
#*.doc   diff=astextplain
#*.DOC   diff=astextplain
#*.docx  diff=astextplain
#*.DOCX  diff=astextplain
#*.dot   diff=astextplain
#*.DOT   diff=astextplain
#*.pdf   diff=astextplain
#*.PDF   diff=astextplain
#*.rtf   diff=astextplain
#*.RTF   diff=astextplain


================================================
FILE: .github/workflows/msvc.yml
================================================
name: MSBuild

on:
  push:
  pull_request:
    branches: [ "main" ]

env:
  # Path to the solution file relative to the root of the project.
  SOLUTION_FILE_PATH: mfcDuDownloadCodeGenerator.sln
  BUILD_CONFIGURATION: Release

permissions:
  contents: read

jobs:
  build:
    strategy:
      matrix:
        build_config:
          - vs2019.x86_64
          - vs2019.static.xp.x86
          - vs2022.x86_64
          - vs2022.static.x86_64

        include:
          - build_config: vs2019.x86_64
            os: windows-2019
          - build_config: vs2019.static.xp.x86
            os: windows-2019
          - build_config: vs2022.x86_64
            os: windows-2022
          - build_config: vs2022.static.x86_64
            os: windows-2022

    runs-on: "${{ matrix.os }}"

    permissions:
      contents: write

    steps:
    - name: 🛎️ checkout
      uses: actions/checkout@v3

    - name: 🏭 prepare MSBuild
      uses: microsoft/setup-msbuild@v1.0.2

    - name: 🏭 prepare msys2
      uses: msys2/setup-msys2@v2
      with:
        update: true
        install: >-
          git
          upx
          zip

    - name: 🔧 build
      working-directory: ${{env.GITHUB_WORKSPACE}}
      # Add additional options to the MSBuild command line here (like platform or verbosity level).
      # See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference
      run: |
        Set-PSDebug -Trace 1

        $config = "${{ matrix.build_config }}"
        if ($config.Contains(".static.")) {
          $env:_CL_ += ' /MT'
          $mfc_type = 'Static'
        } else {
          $env:_CL_ += ' /MD'
          $mfc_type = 'Dynamic'
        }

        $platform = if ($config.EndsWith('x86_64')) { "x64" } else { "x86" }
        $toolset = if ($config.StartsWith('vs2022.')) { "v143" }
          elseif ($config.Contains('.xp.')) { "v141_xp" }
          else { "v142" }

        if ($config.Contains('.xp.')) {
          $env:_CL_ += ' /D__BUILD_FOR_XP=1'
        }

        msbuild /m `
          /p:Configuration=${{ env.BUILD_CONFIGURATION }} `
          /p:Platform=$platform `
          /p:PlatformToolset=$toolset `
          /p:UseOfMfc=$mfc_type `
          ${{env.SOLUTION_FILE_PATH}}
        
        New-Item -ItemType Directory build
        Move-Item -Path ".\$platform\${{ env.BUILD_CONFIGURATION }}\*.exe" `
          -Destination ".\build\"

    - name: 🗜️ rename + optional upx
      shell: msys2 {0}
      run: |
        set -ex

        cd "build"
        if [[ "${{ matrix.build_config }}" =~ ".static." ]]; then
          upx -9 *.exe
        fi
        cp "ducode.exe" "ducode.${{ matrix.build_config }}.exe"

    - name: 🗜️ archive binaries
      uses: actions/upload-artifact@v3
      with:
        name: binaries
        path: build/ducode.${{ matrix.build_config }}.exe

    - name: 📦 package for release
      if: startsWith(github.ref, 'refs/tags/v')
      shell: msys2 {0}
      run: |
        set -ex

        cd "build"
        GIT_VERSION="${{github.ref}}"
        GIT_VERSION="${GIT_VERSION:10}"
        ZIP_NAME="ducode.${{ matrix.build_config }}.${GIT_VERSION}.zip"
        zip -9 "../${ZIP_NAME}" "ducode.exe"

    - name: 📝 draft release
      if: startsWith(github.ref, 'refs/tags/v')
      uses: softprops/action-gh-release@v1
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      with:
        body: "<to be filled>"
        draft: true
        # note you'll typically need to create a personal access token
        # with permissions to create releases in the other repo
        token: ${{ secrets.CUSTOM_GITHUB_TOKEN }}
        files: |
          *.zip


================================================
FILE: .gitignore
================================================
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.

# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates

# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/

# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/

# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

# NUNIT
*.VisualState.xml
TestResult.xml

# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c

# DNX
project.lock.json
project.fragment.lock.json
artifacts/

*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc

# Chutzpah Test files
_Chutzpah*

# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb

# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap

# TFS 2012 Local Workspace
$tf/

# Guidance Automation Toolkit
*.gpState

# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user

# JustCode is a .NET coding add-in
.JustCode

# TeamCity is a build add-in
_TeamCity*

# DotCover is a Code Coverage Tool
*.dotCover

# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*

# MightyMoose
*.mm.*
AutoTest.Net/

# Web workbench (sass)
.sass-cache/

# Installshield output folder
[Ee]xpress/

# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html

# Click-Once directory
publish/

# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
#*.pubxml
*.publishproj

# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/

# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets

# Microsoft Azure Build Output
csx/
*.build.csdef

# Microsoft Azure Emulator
ecf/
rcf/

# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt

# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/

# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs

# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/

# RIA/Silverlight projects
Generated_Code/

# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm

# SQL Server files
*.mdf
*.ldf

# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings

# Microsoft Fakes
FakesAssemblies/

# GhostDoc plugin setting file
*.GhostDoc.xml

# Node.js Tools for Visual Studio
.ntvs_analysis.dat

# Visual Studio 6 build log
*.plg

# Visual Studio 6 workspace options file
*.opt

# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions

# Paket dependency manager
.paket/paket.exe
paket-files/

# FAKE - F# Make
.fake/

# JetBrains Rider
.idea/
*.sln.iml

# CodeRush
.cr/

# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
*.tlog

vs2019_ci_static_xp/


================================================
FILE: LICENSE
================================================
BSD 3-Clause License

Copyright (c) 2020, Jixun Wu
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its
   contributors may be used to endorse or promote products derived from
   this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


================================================
FILE: README.MD
================================================
# mfcDuDownloadCodeGenerator
ڰٶ̵ı׼ȡ

![](https://cdn.jsdelivr.net/gh/JixunMoe/mfcDuDownloadCodeGenerator/imgs/sshot-stdcode.png)

---

ģ

* https://jixun.moe/post/du-code-gen
* https://blog.jixun.moe/du-code-gen


================================================
FILE: generator/AdvEdit.cpp
================================================
// AdvEdit.cpp : implementation file
//

#include "stdafx.h"
#include "AdvEdit.h"

// CAdvEdit

IMPLEMENT_DYNAMIC(CAdvEdit, CEdit)

CAdvEdit::CAdvEdit()
{
}

CAdvEdit::~CAdvEdit()
{
}

void CAdvEdit::Append(const CString& text)
{
	std::lock_guard<std::mutex> guard(mutex);

	auto nLength = GetWindowTextLength();
	SetSel(nLength, nLength);
	ReplaceSel(text);
}

void CAdvEdit::SelectAll()
{
	SetSel(0, GetWindowTextLength(), FALSE);
}

BEGIN_MESSAGE_MAP(CAdvEdit, CEdit)
	ON_WM_KEYDOWN()
END_MESSAGE_MAP()

void CAdvEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	CEdit::OnKeyDown(nChar, nRepCnt, nFlags);

	if (nChar == 'A') {
		BYTE keyState[256] = { 0 };
		GetKeyboardState(keyState);
		bool useControl = (keyState[VK_CONTROL] & 0x80) != 0;
		bool useShift = (keyState[VK_SHIFT] & 0x80) != 0;
		bool useAlt = (keyState[VK_MENU] & 0x80) != 0;

		if (useControl && !useShift && !useAlt) {
			this->SelectAll();
		}
	}
}


================================================
FILE: generator/AdvEdit.h
================================================
#pragma once
#include <mutex>


// CAdvEdit

class CAdvEdit : public CEdit
{
	DECLARE_DYNAMIC(CAdvEdit)
	std::mutex mutex;

public:
	CAdvEdit();
	virtual ~CAdvEdit();
	void Append(const CString &text);
	void SelectAll();

protected:
	DECLARE_MESSAGE_MAP()
public:
	afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
};




================================================
FILE: generator/ClipboardHelper.cpp
================================================
#include "stdafx.h"
#include "ClipboardHelper.h"

void CopyStringToClipboard(CString& str, HWND hWnd) {
	auto pString = static_cast<const TCHAR*>(str);
	auto dwStrByteLen = (str.GetLength() + 1) * sizeof TCHAR;

	HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, dwStrByteLen);
	if (!hMem) return;

	auto pLockedMem = GlobalLock(hMem);
	if (!pLockedMem) {
		GlobalFree(hMem);
		return;
	}
	memcpy(pLockedMem, pString, dwStrByteLen);
	GlobalUnlock(hMem);

	if (OpenClipboard(hWnd)) {
		EmptyClipboard();
#ifndef _UNICODE
		SetClipboardData(CF_TEXT, hMem);
#else
		SetClipboardData(CF_UNICODETEXT, hMem);
#endif
		CloseClipboard();
	}
}


================================================
FILE: generator/ClipboardHelper.h
================================================
#pragma once
#include "stdafx.h"

void CopyStringToClipboard(CString& str, HWND hWnd = nullptr);


================================================
FILE: generator/DPISupport.cpp
================================================
#include "stdafx.h"

#include "DPISupport.h"

#if !__BUILD_FOR_XP
#include <ShellScalingApi.h>
#include <VersionHelpers.h>

#pragma comment(lib, "Shcore")
#endif

uint32_t DPISupport::GetWindowDPI(HWND hWnd) {
  UINT xdpi = 0;
  UINT ydpi = 0;

#if !__BUILD_FOR_XP
  // Windows 8.1 or higher
  if (IsWindows8Point1OrGreater()) {
    HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
    LRESULT success =
        GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &xdpi, &ydpi);
    return success == S_OK ? ydpi : 96;
  }
#endif

  HDC hDC = GetDC(hWnd);
  ydpi = static_cast<UINT>(GetDeviceCaps(hDC, LOGPIXELSY));
  ReleaseDC(hWnd, hDC);
  return ydpi;
}


================================================
FILE: generator/DPISupport.h
================================================
#pragma once

#include <Windows.h>
#include <cstdint>

namespace DPISupport {
	uint32_t GetWindowDPI(HWND hWnd);
}


================================================
FILE: generator/FileItem.cpp
================================================
#include "stdafx.h"
#include "FileItem.h"
#include "encoding.h"
#include "base64.h"
#include "resource.h"

CFileItem::CFileItem()
{
}


CFileItem::~CFileItem()
{
	SAFE_DELETE(m_pDirectory);
	SAFE_DELETE(m_pFilename);
	SAFE_DELETE(m_pFirstHash);
	SAFE_DELETE(m_pFullHash);

	if (m_hIcon)
	{
		DestroyIcon(m_hIcon);
		m_hIcon = nullptr;
	}
}

bool CFileItem::Done() const
{
	return m_pFullHash != nullptr;
}

CString CFileItem::GetSizeString() const
{
	CString str;
	if (m_nSize == 0) {
		str = TEXT("0");
		return str;
	}

	TCHAR sizes[][6] = {
		_T("B"),
		_T("KB"),
		_T("MB"),
		_T("GB"),
		_T("TB"),
		_T("PB")
	};

	auto power = log(double(m_nSize)) / log(1024);
	auto unit = int(floor(power));
	auto r = m_nSize / pow(1024, unit);

	str.Format(_T("%.2f %s"), r, sizes[unit]);
	return str;
}

CString CFileItem::BDLink() const
{
	CString result;
	CString dlCode = this->DownloadCode();
	utf8_str str = {};
	ToUTF8(str, dlCode.GetBuffer());
	if (str.str == nullptr) {
		BOOL _ = result.LoadStringW(IDS_ERROR_ENCODE_FAIL);
		return result;
	}

	// ʹ strlen ַСֹ base64 仯ݺ NUL ֽ
	wchar_t* encoded = base64_encode(reinterpret_cast<unsigned char*>(str.str), strlen(str.str));
	free(str.str);

	if (encoded == nullptr) {
		BOOL _ = result.LoadStringW(IDS_ERROR_ENCODE_FAIL);
		return result;
	}

	// ƴӵַ
	result.Append(_T("https://pan.baidu.com/#bdlink="));
	result.Append(encoded);

	free(encoded);
	return result;
}

CString CFileItem::DownloadCode() const
{
	CString str;
	if (Done())
	{
		str.Format(_T("%s#%s#%llu#%s"),
			m_pFullHash->GetString(),
			m_pFirstHash->GetString(),
			m_nSize,
			m_pFilename->GetString()
		);
	} else
	{
		str.Format(_T("%s#%s#%llu#%s\r\n"),
			_T("<md5(file)>"),
			_T("<md5(256kb)>"),
			m_nSize,
			m_pFilename->GetString()
		);
	}
	return str;
}


================================================
FILE: generator/FileItem.h
================================================
#pragma once
class CFileItem
{
public:
	CString* m_pDirectory = nullptr;
	CString* m_pFilename = nullptr;
	HICON m_hIcon = nullptr;
	uint64_t m_nSize = 0;

	CString* m_pFirstHash = nullptr;
	CString* m_pFullHash = nullptr;

public:
	CFileItem();
	~CFileItem();

	bool Done() const;
	CString GetSizeString() const;

	CString BDLink() const;
	CString DownloadCode() const;
};



================================================
FILE: generator/Hasher.cpp
================================================
#include "stdafx.h"
#include "Hasher.h"


bool Hasher::Init()
{
	auto bSuccess = false;

	if (CryptAcquireContext(&m_hCryptProv, nullptr, nullptr, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
	{
		bSuccess = CryptCreateHash(m_hCryptProv, this->m_alg, NULL, NULL, &m_phHash);

		if (bSuccess) return bSuccess;
	}
	Cleanup();

	if (CryptAcquireContext(&m_hCryptProv, nullptr, nullptr, PROV_RSA_FULL, NULL))
	{
		bSuccess = CryptCreateHash(m_hCryptProv, this->m_alg, NULL, NULL, &m_phHash);

		if (bSuccess) return bSuccess;
	}
	Cleanup();

	if (CryptAcquireContext(&m_hCryptProv, nullptr, nullptr, PROV_RSA_FULL, CRYPT_NEWKEYSET))
	{
		bSuccess = CryptCreateHash(m_hCryptProv, this->m_alg, NULL, NULL, &m_phHash);

		if (bSuccess) return bSuccess;
	}
	Cleanup();

	return bSuccess;
}

Hasher::Hasher(ALG_ID alg)
{
	this->m_alg = alg;
}


Hasher::~Hasher()
{
}

void Hasher::Cleanup()
{
	if (m_hKey)
	{
		CryptDestroyKey(m_hKey);
		m_hKey = NULL;
	}

	if (m_phHash)
	{
		CryptDestroyHash(m_phHash);
		m_phHash = NULL;
	}

	if (m_hCryptProv)
	{
		CryptReleaseContext(m_hCryptProv, NULL);
		m_hCryptProv = NULL;
	}
}


CString* Hasher::GetHashStr()
{
	DWORD dwDataLen;
	auto r = new CString("");
	if (CryptGetHashParam(this->m_phHash, HP_HASHVAL, nullptr, &dwDataLen, 0))
	{
		BYTE* d = new BYTE[dwDataLen];
		CryptGetHashParam(this->m_phHash, HP_HASHVAL, d, &dwDataLen, 0);
		for(DWORD i = 0; i < dwDataLen; i++)
		{
			r->AppendFormat(_T("%X%X"), d[i] >> 4, d[i] & 0x0F);
		}
		delete[] d;
	}
	Cleanup();

	return r;
}

void Hasher::Feed(char* str, int n) const
{
	CryptHashData(m_phHash, LPBYTE(str), n, NULL);
}


================================================
FILE: generator/Hasher.h
================================================
#pragma once
#include <Wincrypt.h>

class Hasher
{
	HCRYPTPROV m_hCryptProv = NULL;
	HCRYPTHASH m_phHash = NULL;
	HCRYPTKEY m_hKey = NULL;
	ALG_ID m_alg = NULL;

public:
	bool Init();
	Hasher(ALG_ID alg);
	~Hasher();

	void Cleanup();

	CString* GetHashStr();
	void Feed(char* str, int i) const;
};



================================================
FILE: generator/ListBoxEx.cpp
================================================
// ListBoxEx.cpp : implementation file
//

#include "stdafx.h"
#include "ListBoxEx.h"
#include "resource.h"
#include "Hasher.h"
#include "ClipboardHelper.h"
#include "DPISupport.h"

#include <fstream>      // std::ifstream

#define BD_FILE_HEADER_SIZE (256 * 1024)
constexpr double icon_base_dimention = 36.0;

// CListBoxEx

IMPLEMENT_DYNAMIC(CListBoxEx, CListBox)
HICON CListBoxEx::m_hIconTick = nullptr;
CString CListBoxEx::m_sPlaceholder;
HFONT CListBoxEx::m_systemFont;
CListBoxEx::CListBoxEx()
{
	// init guard
	if (m_hIconTick == nullptr)
	{
		m_hIconTick = static_cast<HICON>(LoadImage(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDI_ICON_TICK), IMAGE_ICON, 16, 16, 0));
		int _ = m_sPlaceholder.LoadStringW(IDS_LIST_PLACEHOLDER);

		NONCLIENTMETRICS metrics = {};
		metrics.cbSize = sizeof(metrics);
		SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0);
		m_systemFont = CreateFontIndirect(&metrics.lfCaptionFont);
		CString placeholder;
	}
}

CListBoxEx::~CListBoxEx()
{
}


BEGIN_MESSAGE_MAP(CListBoxEx, CListBox)
	ON_WM_VKEYTOITEM_REFLECT()
	ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
	ON_WM_PAINT()
END_MESSAGE_MAP()



// CListBoxEx message handlers
void CListBoxEx::GetVisibleRange(int& s, int& e)
{
	auto maxIndex = this->GetCount() - 1;
	e = s = GetTopIndex();
	RECT rect;
	this->GetClientRect(&rect);
	auto height = rect.bottom - rect.top;
	auto currentHeight = 0;

	while(e < maxIndex)
	{
		currentHeight += GetItemHeight(e);
		if (currentHeight >= height) break;
		e++;
	}
}

bool CListBoxEx::ItemIsVisible(int nIndex)
{
	int s, e;
	GetVisibleRange(s, e);
	return s <= nIndex && nIndex <= e;
}

bool CListBoxEx::RedrawIfVisible(int i)
{
	RECT rectItem;
	if (this->GetItemRect(i, &rectItem) != LB_ERR)
	{
		if (rectItem.bottom < 0) return false;

		RECT rectCtrl;
		this->GetClientRect(&rectCtrl);

		if (rectItem.top <= rectCtrl.bottom - rectCtrl.top)
		{
			this->InvalidateRect(&rectItem, FALSE);
			return true;
		}
	}

	return false;
}


// 4MB Buffer 
#define BUF_SIZE (1024*1024*4)
void CListBoxEx::ProcessFiles(f_proc_file_callback cb, void* extra)
{
	std::lock_guard<std::mutex> guard(mutex);
	m_bStop = false;

	auto c = GetCount();
	char* buffer = new char[BUF_SIZE];
	Hasher hash(CALG_MD5);
	for(auto i = 0; i < c; i++)
	{
		auto data = reinterpret_cast<CFileItem*>(GetItemData(i));
		if (data->Done())
		{
			cb(ProcType::INC_FILE, 0, data, extra);
			continue;
		}

		auto path(*data->m_pDirectory + _T("\\") + *data->m_pFilename);
		std::ifstream is(path, std::ifstream::binary);

		if (!is)
		{
			cb(ProcType::ERR_FILE, 0, nullptr, extra);
			is.close();
			break;
		}

		is.read(buffer, BD_FILE_HEADER_SIZE);
		hash.Init();
		hash.Feed(buffer, int(is.gcount()));
		data->m_pFirstHash = hash.GetHashStr();

		// 已经读完了?
		if (is.eof()) {
			is.close();

			// 更新完整哈希
			data->m_pFullHash = new CString(*data->m_pFirstHash);

			// 重绘 + 通知
			this->RedrawIfVisible(i);
			cb(ProcType::INC_FILE, 0, data, extra);
			continue;
		}

		is.seekg(0, SEEK_SET);
		hash.Init();
		double step = double(BUF_SIZE) / data->m_nSize;
		double prog = 0;
		
		do
		{
			if (m_bStop)
			{
				is.close();
				delete[] buffer;
				return;
			}

			is.read(buffer, BUF_SIZE);

			auto eof = is.eof();
			if (!eof && is.fail())
			{
#ifdef _DEBUG
				CString str;
				str.Format(_T("state: %x (goodbit: 0, eof: 1, fail: 2, badbit: 4)\n"), is.rdstate());
				OutputDebugString(str);
#endif
				cb(ProcType::ERR_FILE, 0, nullptr, extra);
				break;
			}

			hash.Feed(buffer, eof ? int(is.gcount()) : BUF_SIZE);

			if (eof)
			{
				data->m_pFullHash = hash.GetHashStr();

				if (this->RedrawIfVisible(i))
				{
#ifdef _DEBUG
					OutputDebugString(_T("Redraw item.\n"));
#endif

				}
				cb(ProcType::INC_FILE, 0, data, extra);
				break;
			}
			prog += step;
			cb(ProcType::FILE_PROG, prog, data, extra);
		} while (true);
		is.close();
	}

	delete[] buffer;
}

void CListBoxEx::StopProcessing()
{
	m_bStop = true;
	{
		std::lock_guard<std::mutex> guard(mutex); 
	}
}

void CListBoxEx::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
	uint32_t dpi = DPISupport::GetWindowDPI(GetSafeHwnd());
	auto dpi_scale = static_cast<double>(dpi) / 96.0;

	auto icon_height = static_cast<uint32_t>(dpi_scale * icon_base_dimention);
	auto icon_top_margin = static_cast<uint32_t>(dpi_scale * 8);

	lpMeasureItemStruct->itemHeight = icon_height + icon_top_margin * 2;
}

void CListBoxEx::DrawItemData(LPDRAWITEMSTRUCT lpDrawItemStruct, CFileItem* pItem)
{
	uint32_t dpi = DPISupport::GetWindowDPI(GetSafeHwnd());
	auto dpi_scale = static_cast<double>(dpi) / 96.0;

	auto icon_width = static_cast<uint32_t>(dpi_scale * icon_base_dimention);
	auto icon_height = static_cast<uint32_t>(dpi_scale * icon_base_dimention);
	auto icon_tick_width = static_cast<uint32_t>(dpi_scale * 16.0);
	auto icon_tick_height = static_cast<uint32_t>(dpi_scale * 16.0);
	auto icon_right_margin = static_cast<uint32_t>(dpi_scale * 8.0);
	auto item_padding = static_cast<uint32_t>(dpi_scale * 4.0);
	auto text_line_margin = static_cast<uint32_t>(dpi_scale * 2.0);

	auto pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
	pDC->SetBkMode(TRANSPARENT);

	CRect rectItem(lpDrawItemStruct->rcItem);
	rectItem.DeflateRect(item_padding, item_padding, item_padding, item_padding);
	CRect rectIcon(rectItem.left, rectItem.top, rectItem.left + icon_width, rectItem.top + icon_height);
	CRect rectIconTick(
		rectIcon.left,
		rectIcon.top + icon_height - icon_tick_height,
		rectIcon.left + icon_tick_width,
		rectItem.top + icon_height - icon_tick_height
	);
	CRect rectText(rectIcon.right + icon_right_margin, rectItem.top, rectItem.right - icon_right_margin * 2, rectItem.bottom);

	auto action = lpDrawItemStruct->itemAction;
	auto state = lpDrawItemStruct->itemState;

	bool selected = (state & ODS_SELECTED) && (action & (ODA_SELECT | ODA_DRAWENTIRE));
	bool redraw = (action & ODA_DRAWENTIRE) || (!(state & ODS_SELECTED) && (action & ODA_SELECT));

	auto textColour = selected ? m_textSelected : m_text;
	auto descTextColour = selected ? m_descTextSelected : m_descText;

	CBrush brushBackground(selected ? m_bgSelected : m_bgClear);
	CBrush brushText(textColour);
	CBrush brushDescText(descTextColour);

	if (selected || redraw)
	{
		CString str;
		pDC->FillRect(&lpDrawItemStruct->rcItem, &brushBackground);
		pDC->DrawIcon(rectIcon.left, rectIcon.top, pItem->m_hIcon);

		if (pItem->m_pFullHash)
		{
			DrawIconEx(*pDC, rectIconTick.left, rectIconTick.top, m_hIconTick, icon_tick_width, icon_tick_height, NULL, nullptr, DI_NORMAL);
		}

		auto rect = rectText;
		pDC->SetTextColor(textColour);
		rect.OffsetRect(text_line_margin, 0);

		str.SetString(*pItem->m_pFilename);
		pDC->DrawText(str, str.GetLength(), rect, DT_LEFT | DT_SINGLELINE | DT_END_ELLIPSIS);
		rect.OffsetRect(0, text_line_margin + pDC->GetTextExtent(str).cy);


		str.Format(IDS_DIR, *pItem->m_pDirectory);
		pDC->SetTextColor(descTextColour);
		pDC->DrawText(str, str.GetLength(), rect, DT_LEFT | DT_SINGLELINE | DT_END_ELLIPSIS);
		rect.OffsetRect(0, text_line_margin + pDC->GetTextExtent(str).cy);

		str.Format(IDS_FILE_SIZE, pItem->GetSizeString());
		pDC->DrawText(str, str.GetLength(), rect, DT_LEFT | DT_SINGLELINE);
		rect.OffsetRect(0, text_line_margin + pDC->GetTextExtent(str).cy);
	}
}

void CListBoxEx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
	auto pData = GetItemDataPtr(lpDrawItemStruct->itemID);
	if (pData != (void*)-1) {
		this->DrawItemData(lpDrawItemStruct, reinterpret_cast<CFileItem*>(pData));
	}

}

uint64_t FileSize(const wchar_t* name)
{
	auto hFile = CreateFileW(
		name, GENERIC_READ, FILE_SHARE_READ, nullptr, 
		OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr
	);
	if (hFile == INVALID_HANDLE_VALUE) {
		return 0; // could not open file
	}
	LARGE_INTEGER fs_large = {0};
	if (!GetFileSizeEx(hFile, &fs_large)) {
		// get file size failed
		fs_large.QuadPart = 0;
	}
	CloseHandle(hFile);

	return static_cast<uint64_t>(fs_large.QuadPart);
}

int CListBoxEx::AddItem(const CString& srcDir, const CString& filename)
{
 	std::lock_guard<std::mutex> guard(this->mutex);

	auto fullPath(srcDir + _T("\\") + filename);
	auto fSize = FileSize(fullPath);

	auto index = this->AddString(_T(""));
	auto data = new CFileItem();
	data->m_pDirectory = new CString(srcDir);
	data->m_pFilename = new CString(filename);

	SHFILEINFO shfi = {};
	SHGetFileInfo(fullPath, FILE_ATTRIBUTE_NORMAL, &shfi, sizeof(SHFILEINFO),
		SHGFI_USEFILEATTRIBUTES | SHGFI_ICON | SHGFI_SHELLICONSIZE);

	data->m_hIcon = shfi.hIcon;
	data->m_nSize = fSize;

	SetItemData(index, DWORD_PTR(data));

	return 0;
}

void CListBoxEx::CopySelectedHashes()
{
	CString str;

	for (int i = 0; i < GetCount(); i++)
	{
		if (GetSel(i))
		{
			str.AppendFormat(L"%s\r\n", reinterpret_cast<CFileItem*>(GetItemData(i))->DownloadCode().GetString());
		}
	}

	CopyStringToClipboard(str);
}

int CListBoxEx::VKeyToItem(UINT nKey, UINT nIndex)
{
	// Returns –2 for no further action,
	// –1 for default action, or
	// a nonnegative number to specify an index of a
	// list box item on which to perform the default action for the keystroke.

	if(mutex.try_lock())
	{
		switch (nKey)
		{
		case 'E':
			for (int i = 0; i < GetCount(); i++)
				SetSel(i, false);

			mutex.unlock();
			return -2;

		case 'C':
			this->CopySelectedHashes();
			mutex.unlock();
			return -2;

		case 'D':
		case VK_DELETE:
			for (int i = GetCount() - 1; i >= 0; i--)
			{
				if (GetSel(i))
				{
					DeleteString(i);
					SetSel(i, true);
				}
			}

			mutex.unlock();
			return -2;

		}
		mutex.unlock();
		return -1;
	}

	return -1;
}


void CListBoxEx::PreSubclassWindow()
{
	CListBox::PreSubclassWindow();
	EnableToolTips(TRUE);
}

INT_PTR CListBoxEx::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
{
	RECT itemRect;
	BOOL isOutside = FALSE;
	int row = ItemFromPoint(point, isOutside);
	if (row == -1 || isOutside)
		return -1;

	GetItemRect(row, &itemRect);

	pTI->rect = itemRect;
	pTI->hwnd = m_hWnd;
	pTI->uId = row;
	pTI->lpszText = LPSTR_TEXTCALLBACK;
	return pTI->uId;
}

BOOL CListBoxEx::OnToolTipText(UINT id, NMHDR * pNMHDR, LRESULT * pResult)
{
	auto pToolTip = AfxGetModuleThreadState()->m_pToolTip;
	if (pToolTip) pToolTip->SetMaxTipWidth(SHRT_MAX);

	auto ptText = reinterpret_cast<LPTOOLTIPTEXTW>(pNMHDR);

	auto pItem = reinterpret_cast<CFileItem*>(this->GetItemData(static_cast<int>(pNMHDR->idFrom)));

	CString str;
	str.Format(IDS_FILE_INFO,
		*pItem->m_pFilename,
		*pItem->m_pDirectory,
		 pItem->GetSizeString());


	auto strW = static_cast<const TCHAR*>(str);
	auto memSize = str.GetLength() * sizeof TCHAR + (2 * sizeof TCHAR);
	auto lpszText = (TCHAR*)calloc(memSize, 1);
	if (!lpszText) {
		return FALSE;
	}

	memcpy(lpszText, strW, memSize);

	ptText->lpszText = lpszText;

	*pResult = 0;

	return TRUE;

}

void CListBoxEx::OnPaint()
{
	if (GetCount() == 0) {
		CPaintDC dc(this);

		CRect rect;
		this->GetClientRect(rect);
		dc.SetTextColor(m_descText);
		dc.SelectObject(m_systemFont);
		dc.DrawText(m_sPlaceholder, m_sPlaceholder.GetLength(), rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
	}
	else {
		Default();
	}
}


================================================
FILE: generator/ListBoxEx.h
================================================
#pragma once
#include <mutex>

#include "FileItem.h"

// CListBoxEx

enum class ProcType
{
	FILE_PROG,
	INC_FILE,
	ERR_FILE
};

typedef void(*f_proc_file_callback) (ProcType type, double progress, CFileItem* pItem, void* extra);
class CListBoxEx : public CListBox
{
	DECLARE_DYNAMIC(CListBoxEx)
private:
	std::mutex mutex;
	static HICON m_hIconTick;
	static CString m_sPlaceholder;
	static HFONT m_systemFont;
	bool m_bStop = false;

public:
	CListBoxEx();
	virtual ~CListBoxEx();

	COLORREF m_bgSelected = RGB(204, 232, 255); // #cce8ff
	COLORREF m_bgClear    = RGB(255, 255, 255);
	COLORREF m_text = RGB(0, 0, 0);
	COLORREF m_textSelected = RGB(0, 0, 0);
	COLORREF m_descText = RGB(109, 109, 109);
	COLORREF m_descTextSelected = RGB(109, 109, 109);

protected:
	DECLARE_MESSAGE_MAP()

public:
	void GetVisibleRange(int& s, int& e);
	bool ItemIsVisible(int nIndex);
	bool RedrawIfVisible(int i);
	void ProcessFiles(f_proc_file_callback cb, void* extra);
	void StopProcessing();

	afx_msg void OnPaint();
	virtual void MeasureItem(LPMEASUREITEMSTRUCT /*lpMeasureItemStruct*/);
	virtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/);
	virtual void PreSubclassWindow();

	void DrawItemData(LPDRAWITEMSTRUCT lpDrawItemStruct, CFileItem* pItem);

	int AddItem(const CString& srcDir, const CString& filename);
	void CopySelectedHashes();
	int VKeyToItem(UINT /*nKey*/, UINT /*nIndex*/);
	virtual INT_PTR OnToolHitTest(CPoint point, TOOLINFO* pTI) const;
	BOOL OnToolTipText(UINT id, NMHDR* pNMHDR, LRESULT* pResult);
};




================================================
FILE: generator/ProgressText.cpp
================================================
// ProgressText.cpp : implementation file
//

#include "stdafx.h"

#include "generator.h"
#include "ProgressText.h"
#include "DPISupport.h"

void inline shrink(CRect* rect) {
	rect->left++;
	rect->top++;
	rect->right--;
	rect->bottom--;
}

// CProgressText

IMPLEMENT_DYNAMIC(CProgressText, CProgressCtrl)

CProgressText::CProgressText()
{
	Init();
}

CProgressText::~CProgressText()
{
	SAFE_DELETE(text);
}

void CProgressText::Init()
{
	text = new CString("");

	progressForegroundBrush = new CBrush(progressForegroundColour);
	progressBackgroundBrush = new CBrush(progressBackgroundColour);
	componentBorderBrush = new CBrush(componentBorderColour);

	font = new CFont();
}

void CProgressText::SetCurrent(uint current)
{
	this->current = current;
	this->SetPos(this->current);
	this->UpdateText();
}

void CProgressText::SetMax(uint max)
{
	this->max = max;
	this->SetRange32(0, max);
	this->UpdateText();
}

void CProgressText::Increase()
{
	this->current++;
	this->SetPos(this->current);
	this->UpdateText();
}

void CProgressText::Reset()
{
	this->current = 0;
	this->max = 0;
	this->SetPos(0);
	this->UpdateText();
	this->RedrawWindow();
}

void CProgressText::UpdateText() {
	if (this->max == 0) {
		this->percent = 0;
		this->text->SetString(_T(""));
	}
	else
	{
		this->percent = double(this->current) / double(this->max);
		this->text->Format(_T("%d / %d (%.2f%%)"), this->current, this->max, this->percent * 100);
	}
}


BEGIN_MESSAGE_MAP(CProgressText, CProgressCtrl)
	ON_WM_PAINT()
	ON_WM_ERASEBKGND()
END_MESSAGE_MAP()



// CProgressText message handlers




void CProgressText::OnPaint()
{
	CPaintDC dc(this); // device context for painting
					   // Do not call CProgressCtrl::OnPaint() for painting messages

	double dpi_scale = double(DPISupport::GetWindowDPI(GetSafeHwnd())) / 96.0;

	CRect rect;
	GetClientRect(&rect);

	CDC memDC;
	memDC.CreateCompatibleDC(&dc);
	memDC.SetMapMode(dc.GetMapMode());
	memDC.SetViewportOrg(dc.GetViewportOrg());
	memDC.IntersectClipRect(rect);

	CBitmap bmp;
	bmp.CreateCompatibleBitmap(&dc, rect.Width(), rect.Height());
	auto pOldBmp = memDC.SelectObject(&bmp);

	memDC.SetBkMode(TRANSPARENT);

	// 绘制一圈边框
	memDC.SelectObject(GetStockObject(DC_PEN));
	memDC.SetDCPenColor(this->componentBorderColour);
	memDC.Rectangle(rect);

	// 绘制四方形
	{
		auto rectProgress = rect;
		shrink(&rectProgress);
		memDC.FillRect(rectProgress, this->progressBackgroundBrush);

		rectProgress.right = rectProgress.left + LONG(rectProgress.Width() * this->percent);
		memDC.FillRect(rectProgress, this->progressForegroundBrush);
	}

	auto font_height = static_cast<uint32_t>((rect.Height() - 4) * dpi_scale * 0.75);
	font->DeleteObject();
	VERIFY(font->CreateFont(
		font_height,               // nHeight
		0,                         // nWidth
		0,                         // nEscapement
		0,                         // nOrientation
		FW_NORMAL,                 // nWeight
		FALSE,                     // bItalic
		FALSE,                     // bUnderline
		0,                         // cStrikeOut
		ANSI_CHARSET,              // nCharSet
		OUT_DEFAULT_PRECIS,        // nOutPrecision
		CLIP_DEFAULT_PRECIS,       // nClipPrecision
		DEFAULT_QUALITY,           // nQuality
		DEFAULT_PITCH | FF_SWISS,  // nPitchAndFamily
		_T("Consolas")));          // lpszFacename

	auto def_font = memDC.SelectObject(font);
	auto size = memDC.GetTextExtent(*text);
	auto x = rect.right - size.cx - 8;
	auto y = (rect.Height() - size.cy) / 2;
	memDC.TextOut(x, y, *text, this->text->GetLength());
	memDC.SelectObject(def_font);

	// 拷贝图片
	dc.BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &memDC, rect.left, rect.top, SRCCOPY);

	// 还原选择的对象
	memDC.SelectObject(pOldBmp);
}

// ReSharper disable once CppMemberFunctionMayBeStatic
// ReSharper disable once CppMemberFunctionMayBeConst
BOOL CProgressText::OnEraseBkgnd(CDC* pDC)
{
	return TRUE;
}


================================================
FILE: generator/ProgressText.h
================================================
#pragma once

// CProgressText

class CProgressText : public CProgressCtrl
{
	CFont* font;
	COLORREF progressForegroundColour = RGB(62, 231, 152);
	COLORREF progressBackgroundColour = RGB(0xE6, 0xE6, 0xE6);
	COLORREF componentBorderColour = RGB(0xBC, 0xBC, 0xBC);

	CBrush* progressForegroundBrush;
	CBrush* progressBackgroundBrush;
	CBrush* componentBorderBrush;
	void Init();

	DECLARE_DYNAMIC(CProgressText)
	uint current = 0;
	uint max = 0;
	CString* text;
	double percent = 0;

public:
	CProgressText();
	virtual ~CProgressText();
	void SetCurrent(uint current);
	void SetMax(uint max);
	void Increase();
	void Reset();

protected:
	DECLARE_MESSAGE_MAP()
	void UpdateText();

public:
	afx_msg void OnPaint();
	afx_msg BOOL OnEraseBkgnd(CDC* pDC);
};




================================================
FILE: generator/ReadMe.txt
================================================
================================================================================
    MICROSOFT FOUNDATION CLASS LIBRARY : generator Project Overview
===============================================================================

The application wizard has created this generator application for
you.  This application not only demonstrates the basics of using the Microsoft
Foundation Classes but is also a starting point for writing your application.

This file contains a summary of what you will find in each of the files that
make up your generator application.

generator.vcxproj
    This is the main project file for VC++ projects generated using an application wizard.
    It contains information about the version of Visual C++ that generated the file, and
    information about the platforms, configurations, and project features selected with the
    application wizard.

generator.vcxproj.filters
    This is the filters file for VC++ projects generated using an Application Wizard. 
    It contains information about the assciation between the files in your project 
    and the filters. This association is used in the IDE to show grouping of files with
    similar extensions under a specific node (for e.g. ".cpp" files are associated with the
    "Source Files" filter).

generator.h
    This is the main header file for the application.  It includes other
    project specific headers (including Resource.h) and declares the
    CApp application class.

generator.cpp
    This is the main application source file that contains the application
    class CApp.

generator.rc
    This is a listing of all of the Microsoft Windows resources that the
    program uses.  It includes the icons, bitmaps, and cursors that are stored
    in the RES subdirectory.  This file can be directly edited in Microsoft
    Visual C++. Your project resources are in 1033.

res\generator.ico
    This is an icon file, which is used as the application's icon.  This
    icon is included by the main resource file generator.rc.

res\generator.rc2
    This file contains resources that are not edited by Microsoft
    Visual C++. You should place all resources not editable by
    the resource editor in this file.


/////////////////////////////////////////////////////////////////////////////

The application wizard creates one dialog class:

appDlg.h, appDlg.cpp - the dialog
    These files contain your CAppDlg class.  This class defines
    the behavior of your application's main dialog.  The dialog's template is
    in generator.rc, which can be edited in Microsoft Visual C++.

/////////////////////////////////////////////////////////////////////////////

Help Support:

hlp\generator.hhp
    This file is a help project file. It contains the data needed to
    compile the help files into a .chm file.

hlp\generator.hhc
    This file lists the contents of the help project.

hlp\generator.hhk
    This file contains an index of the help topics.

hlp\afxcore.htm
    This file contains the standard help topics for standard MFC
    commands and screen objects. Add your own help topics to this file.

makehtmlhelp.bat
    This file is used by the build system to compile the help files.

hlp\Images\*.gif
    These are bitmap files required by the standard help file topics for
    Microsoft Foundation Class Library standard commands.


/////////////////////////////////////////////////////////////////////////////

Other standard files:

StdAfx.h, StdAfx.cpp
    These files are used to build a precompiled header (PCH) file
    named generator.pch and a precompiled types file named StdAfx.obj.

Resource.h
    This is the standard header file, which defines new resource IDs.
    Microsoft Visual C++ reads and updates this file.

generator.manifest
	Application manifest files are used by Windows XP to describe an applications
	dependency on specific versions of Side-by-Side assemblies. The loader uses this
	information to load the appropriate assembly from the assembly cache or private
	from the application. The Application manifest  maybe included for redistribution
	as an external .manifest file that is installed in the same folder as the application
	executable or it may be included in the executable in the form of a resource.
/////////////////////////////////////////////////////////////////////////////

Other notes:

The application wizard uses "TODO:" to indicate parts of the source code you
should add to or customize.

If your application uses MFC in a shared DLL, you will need
to redistribute the MFC DLLs. If your application is in a language
other than the operating system's locale, you will also have to
redistribute the corresponding localized resources MFC100XXX.DLL.
For more information on both of these topics, please see the section on
redistributing Visual C++ applications in MSDN documentation.

/////////////////////////////////////////////////////////////////////////////


================================================
FILE: generator/appDlg.cpp
================================================

// appDlg.cpp : implementation file
//

#include "stdafx.h"
#include "generator.h"
#include "appDlg.h"
#include "afxdialogex.h"
#include "utils.h"
#include "base64.h"
#include "ClipboardHelper.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CAboutDlg dialog used for App About

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// Dialog Data
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_ABOUTBOX };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
	DECLARE_MESSAGE_MAP()
public:
//	void AddFile(CString& srcDir, CString& filename);
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CAppDlg dialog



CAppDlg::CAppDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(IDD_GENERATOR_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CAppDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_PROG_FILE, m_progFile);
	DDX_Control(pDX, IDC_PROG_ALL, m_progAll);
	DDX_Control(pDX, IDC_LIST_FILES, m_listFiles);
	DDX_Control(pDX, IDC_EDIT_OUTPUT, m_editOutput);
	DDX_Control(pDX, IDC_CHK_RECURSIVE, m_chkRecursive);
	DDX_Control(pDX, IDC_CHK_URL, m_chkUrl);
	DDX_Control(pDX, IDC_SYSLINK_BLOG, m_linkBlog);
	DDX_Control(pDX, IDC_BTN_ADD_DIR, m_btnAddDir);
	DDX_Control(pDX, IDC_BTN_ADD_FILE, m_btnAddFile);
	DDX_Control(pDX, IDC_BTN_CLEAR, m_btnClear);
	DDX_Control(pDX, IDC_BTN_COPY, m_btnCopy);
	DDX_Control(pDX, IDC_BTN_GENERATE, m_btnGenerate);
}

// NM_CLICK = -2
constexpr UINT NM_CLICK_WITHOUT_WARNING = UINT(-2);

BEGIN_MESSAGE_MAP(CAppDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BTN_GENERATE, &CAppDlg::OnBnClickedGenerate)
	ON_BN_CLICKED(IDC_BTN_ADD_DIR, &CAppDlg::OnClickedBtnAddDir)
	ON_BN_CLICKED(IDC_BTN_ADD_FILE, &CAppDlg::OnClickedBtnAddFile)
	ON_BN_CLICKED(IDC_BTN_CLEAR, &CAppDlg::OnBnClickedBtnClear)
	ON_WM_DROPFILES()
	ON_NOTIFY(NM_CLICK_WITHOUT_WARNING, IDC_SYSLINK_BLOG, &CAppDlg::OnClickSyslinkBlog)
	ON_BN_CLICKED(IDC_BTN_COPY, &CAppDlg::OnBnClickedBtnCopy)
END_MESSAGE_MAP()


// CAppDlg message handlers

BOOL CAppDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	AppendVersionNumber();

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);		// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	CRegKey reg;
	if (reg.Open(HKEY_CURRENT_USER, _T("Software\\Jixun.Moe\\DuGenerator"), KEY_READ) == ERROR_SUCCESS)
	{
		DWORD dwLang;
		if (reg.QueryDWORDValue(_T("LANG_ID"), dwLang) == ERROR_SUCCESS)
		{
			SetThreadUILanguage(LANGID(dwLang));
		}

		reg.Close();
	}

	std::ignore = m_ofn_file_title.LoadString(IDS_PICK_FILE);
	std::ignore = m_ofn_dir_title.LoadString(IDS_PICK_DIR);

	m_progFile.SetRange(0, 10000);

	// 初始化目录选择
	std::ignore = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);

	m_editOutput.SetLimitText(0);

#if _DEBUG
	{
		char buffer[32];
		sprintf_s(buffer, sizeof(buffer), "text limit: 0x%08x\n", m_editOutput.GetLimitText());
		OutputDebugStringA(buffer);
	}
#endif

	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CAppDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CAppDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CAppDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

void WINAPI _thread_process_file(CAppDlg* app)
{
	app->ProcessFiles();
}


void CAppDlg::OnBnClickedGenerate()
{
	CreateThread(nullptr, 0, LPTHREAD_START_ROUTINE(_thread_process_file), this, 0, nullptr);
}

void cb_add_file(const CString &srcDir, const CString &filename, void* extra)
{
	static_cast<CAppDlg*>(extra)->AddFile(srcDir, filename);
}

void CAppDlg::OnClickedBtnAddDir()
{
	auto dirs = OpenDirectoryDialog(m_ofn_dir_title, GetSafeHwnd());
	for(auto& dir : dirs)
	{
		EnumFiles(*dir, BST_CHECKED == m_chkRecursive.GetCheck(), cb_add_file, this);
		delete dir;
	}
}


void CAppDlg::OnClickedBtnAddFile()
{
	auto v = OpenFileDialog(this->m_ofn_file_title, GetSafeHwnd());
	for(auto file : v)
	{
		CString path(*file);
		auto pos = path.ReverseFind(_T('\\'));
		m_listFiles.AddItem(path.Left(pos), path.Right(path.GetLength() - pos - 1));
		delete file;
	}
}

void CAppDlg::AddFile(const CString& srcDir, const CString& filename)
{
	m_listFiles.AddItem(srcDir, filename);
}

void _proc_file_callback(ProcType type, double progress, CFileItem* lpItem, void* extra)
{
	static_cast<CAppDlg*>(extra)->ProcFile(type, progress, lpItem);
}

void CAppDlg::ProcessFiles()
{
	std::lock_guard<std::mutex> guard(mutex);

	OutputDebugString(_T("Begin read file..."));
	m_progAll.SetMax(m_listFiles.GetCount());
	m_progAll.SetCurrent(0);
	m_progFile.SetPos(0);
	
	m_btnAddDir.EnableWindow(FALSE);
	m_btnAddFile.EnableWindow(FALSE);
	m_btnCopy.EnableWindow(FALSE);
	m_btnClear.EnableWindow(FALSE);
	m_btnGenerate.EnableWindow(FALSE);

	m_listFiles.ProcessFiles(_proc_file_callback, this);

	m_btnAddDir.EnableWindow(TRUE);
	m_btnAddFile.EnableWindow(TRUE);
	m_btnCopy.EnableWindow(TRUE);
	m_btnClear.EnableWindow(TRUE);
	m_btnGenerate.EnableWindow(TRUE);
}

void CAppDlg::AddHashEntry(CFileItem* data)
{
	if (m_editOutput.GetWindowTextLengthW() > 0) {
		m_editOutput.Append(_T("\r\n"));
	}

	if (m_chkUrl.GetCheck() == BST_CHECKED) {
		m_editOutput.Append(data->BDLink());
	}
	else {
		m_editOutput.Append(data->DownloadCode());
	}
}

void CAppDlg::ProcFile(ProcType proc, double progress, CFileItem* lp_item)
{
	switch(proc)
	{
	case ProcType::FILE_PROG: 
		m_progFile.SetPos(int(progress * 10000));
		break;

	case ProcType::INC_FILE:
		m_progFile.SetPos(0);
		m_progAll.Increase();
		AddHashEntry(lp_item);
		break;

	case ProcType::ERR_FILE:
		OutputDebugString(_T("Failed to process file.\n"));
		m_progAll.Increase(); 
		break;

	default: ;
	}
}

void CAppDlg::RealExit()
{
	m_listFiles.StopProcessing();

	// TODO: Clean up.

	CDialogEx::OnCancel();
}

void CAppDlg::AppendVersionNumber()
{
	CString csEntry;
	HMODULE hLib = AfxGetResourceHandle();

	HRSRC hVersion = FindResource(hLib, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION);
	if (hVersion == nullptr) return;

	HGLOBAL hGlobal = LoadResource(hLib, hVersion);
	if (hGlobal == nullptr) {
		FreeResource(hVersion);
		return;
	}

	LPVOID versionInfo = LockResource(hGlobal);
	if (versionInfo == nullptr) {
		UnlockResource(hGlobal);
		FreeResource(hVersion);
		return;
	}

	LPVOID lpBuffer = nullptr;
	UINT dwCharCount = 0;

	if (VerQueryValue(versionInfo, L"\\StringFileInfo\\080004B0\\FileVersion", &lpBuffer, &dwCharCount)) {
		CString strTitle;
		GetWindowText(strTitle);

		auto strVersionString = new TCHAR[dwCharCount + 1];
		memcpy(strVersionString, lpBuffer, dwCharCount * sizeof(TCHAR));
		strVersionString[dwCharCount] = 0;

		auto pLastDot = _tcsrchr(strVersionString, _T('.'));
		if (pLastDot != nullptr) {
			*pLastDot = 0;
		}

		strTitle += _T(" (v");
		strTitle += strVersionString;
		strTitle += _T(")");
		SetWindowText(strTitle);

		delete[] strVersionString;
	}

	UnlockResource(hGlobal);
	FreeResource(hVersion);
}

DWORD WINAPI _thread_stop_process(void* param)
{
	static_cast<CAppDlg*>(param)->RealExit();
	return 0;
}

void CAppDlg::OnCancel()
{
	// 若为 ESC 导致的关闭窗口,无视它。
	if ((GetKeyState(VK_ESCAPE) & 0x8000) != 0) {
		return;
	}

	CreateThread(nullptr, 0, _thread_stop_process, this, 0, nullptr);
}


void CAppDlg::OnBnClickedBtnClear()
{
	m_listFiles.ResetContent();
	m_progAll.Reset();
	m_editOutput.SetWindowText(_T(""));
}


void CAppDlg::OnDropFiles(HDROP hDropInfo)
{
	CString path;

	int nFilesDropped = DragQueryFile(hDropInfo, 0xFFFFFFFF, nullptr, 0);

	for (int i = 0; i<nFilesDropped; i++)
	{
		DWORD nBuffer = DragQueryFile(hDropInfo, i, nullptr, 0) + sizeof TCHAR;

		DragQueryFile(hDropInfo, i, path.GetBuffer(nBuffer), nBuffer);
		path.ReleaseBuffer();

		auto isDir = (GetFileAttributes(path) | FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY;
		if (isDir)
		{
			EnumFiles(path, BST_CHECKED == m_chkRecursive.GetCheck(), cb_add_file, this);
		} else
		{
			auto pos = path.ReverseFind(_T('\\'));
			m_listFiles.AddItem(path.Left(pos), path.Right(path.GetLength() - pos - 1));
		}

		OutputDebugString(path.GetString());
		OutputDebugString(_T("\r\n"));
	}

	DragFinish(hDropInfo);
	CDialogEx::OnDropFiles(hDropInfo);
}


// ReSharper disable once CppMemberFunctionMayBeStatic
// ReSharper disable once CppMemberFunctionMayBeConst
void CAppDlg::OnClickSyslinkBlog(NMHDR *pNMHDR, LRESULT *pResult)
{
	ShellExecute(nullptr, _T("open"), PNMLINK(pNMHDR)->item.szUrl, nullptr, nullptr, SW_SHOWNORMAL);
	*pResult = 0;
}


// ReSharper disable once CppMemberFunctionMayBeConst
void CAppDlg::OnBnClickedBtnCopy()
{
	CString str;
	m_editOutput.GetWindowText(str);
	CopyStringToClipboard(str, GetSafeHwnd());
}


================================================
FILE: generator/appDlg.h
================================================

// appDlg.h : header file
//

#pragma once

#include "ProgressText.h"
#include "AdvEdit.h"
#include "ListBoxEx.h"
#include "afxwin.h"
#include "afxcmn.h"

// CAppDlg dialog
class CAppDlg : public CDialogEx
{
	CString m_ofn_file_title;
	CString m_ofn_dir_title;

	std::mutex mutex;

// Construction
public:
	CAppDlg(CWnd* pParent = NULL);	// standard constructor
	void AddFile(const CString& srcDir, const CString& filename);
	void ProcessFiles();
	void AddHashEntry(CFileItem* lp_item);
	void ProcFile(ProcType proc, double progress, CFileItem* lp_item);
	void RealExit();
	void AppendVersionNumber();
	std::vector<CString*> files;

// Dialog Data
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_GENERATOR_DIALOG };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support


// Implementation
protected:
	HICON m_hIcon;

	// Generated message map functions
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:
	afx_msg void OnBnClickedGenerate();
	// Current file Progress
	CProgressCtrl m_progFile;
	CProgressText m_progAll;
	CListBoxEx m_listFiles;
	CAdvEdit m_editOutput;
	afx_msg void OnClickedBtnAddDir();
	afx_msg void OnClickedBtnAddFile();
	virtual void OnCancel();
	afx_msg void OnBnClickedBtnClear();
	afx_msg void OnDropFiles(HDROP hDropInfo);
	CButton m_chkRecursive;
	CButton m_chkUrl;
	CLinkCtrl m_linkBlog;
	afx_msg void OnClickSyslinkBlog(NMHDR *pNMHDR, LRESULT *pResult);
	afx_msg void OnBnClickedBtnCopy();
	CButton m_btnAddDir;
	CButton m_btnAddFile;
	CButton m_btnClear;
	CButton m_btnCopy;
	CButton m_btnGenerate;
};


================================================
FILE: generator/base64.cpp
================================================
/*
* Base64 encoding/decoding (RFC1341)
* Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/

// Change log:
// 2016-12-12 - Gaspard Petit : Slightly modified to return a std::string 
//                              instead of a buffer allocated with malloc.
// 2020-12-08 - Jixun: Taken from StackOverflow and adapted to project.
//                     source: https://stackoverflow.com/a/41094722

#include "stdafx.h"
#include "base64.h"

static const wchar_t base64_table[] = L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

/**
* base64_encode - Base64 encode
* @src:     Data to be encoded
* @len:     Length of the data to be encoded
* @out_len: Pointer to output length variable, or %NULL if not used
* Returns:  Allocated buffer of out_len bytes of encoded data,
*           or empty string on failure
*/
wchar_t* base64_encode(const unsigned char* src, size_t len)
{
    const unsigned char* end, * in;

    size_t olen;

    olen = 4 * ((len + 2) / 3); /* 3-byte blocks to 4-byte */

    if (olen < len)
        return nullptr;

    wchar_t* out = (wchar_t*)calloc(olen + 1, sizeof(wchar_t));
    if (out == nullptr) {
        return nullptr;
    }

    end = src + len;
    in = src;
    auto pos = out;
    while (end - in >= 3) {
        *pos++ = base64_table[in[0] >> 2];
        *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
        *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
        *pos++ = base64_table[in[2] & 0x3f];
        in += 3;
    }

    if (end - in) {
        *pos++ = base64_table[in[0] >> 2];
        if (end - in == 1) {
            *pos++ = base64_table[(in[0] & 0x03) << 4];
            *pos++ = L'=';
        }
        else {
            *pos++ = base64_table[((in[0] & 0x03) << 4) |
                (in[1] >> 4)];
            *pos++ = base64_table[(in[1] & 0x0f) << 2];
        }
        *pos++ = L'=';
    }

    return out;
}


================================================
FILE: generator/base64.h
================================================
#pragma once
#include <string>

wchar_t* base64_encode(const unsigned char* src, size_t len);


================================================
FILE: generator/encoding.cpp
================================================
#include "stdafx.h"
#include "encoding.h"

void ToUTF8(utf8_str& output, wchar_t* input)
{
	size_t out_size = WideCharToMultiByte(CP_UTF8, 0, input, -1, nullptr, 0, NULL, NULL);
	output.str = (char*)calloc(out_size + 1, sizeof(char));
	output.size = out_size;
	WideCharToMultiByte(CP_UTF8, 0, input, -1, output.str, static_cast<int>(out_size), NULL, NULL);
}


================================================
FILE: generator/encoding.h
================================================
#pragma once

struct utf8_str {
	char* str;
	size_t size;
};

void ToUTF8(utf8_str& output, wchar_t* input);


================================================
FILE: generator/generator.cpp
================================================

// generator.cpp : Defines the class behaviors for the application.
//

#include "stdafx.h"
#include "generator.h"
#include "appDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CApp

BEGIN_MESSAGE_MAP(CApp, CWinApp)
	ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()


// CApp construction

CApp::CApp()
{
	// support Restart Manager
	m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;

	// TODO: add construction code here,
	// Place all significant initialization in InitInstance
}


// The one and only CApp object

CApp theApp;


// CApp initialization

BOOL CApp::InitInstance()
{
	// InitCommonControlsEx() is required on Windows XP if an application
	// manifest specifies use of ComCtl32.dll version 6 or later to enable
	// visual styles.  Otherwise, any window creation will fail.
	INITCOMMONCONTROLSEX InitCtrls;
	InitCtrls.dwSize = sizeof(InitCtrls);
	// Set this to include all the common control classes you want to use
	// in your application.
	InitCtrls.dwICC = ICC_WIN95_CLASSES;
	InitCommonControlsEx(&InitCtrls);

	CWinApp::InitInstance();


	// Create the shell manager, in case the dialog contains
	// any shell tree view or shell list view controls.
	CShellManager *pShellManager = new CShellManager;

	// Activate "Windows Native" visual manager for enabling themes in MFC controls
	CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));

	// Standard initialization
	// If you are not using these features and wish to reduce the size
	// of your final executable, you should remove from the following
	// the specific initialization routines you do not need
	// Change the registry key under which our settings are stored
	// TODO: You should modify this string to be something appropriate
	// such as the name of your company or organization
	SetRegistryKey(_T("Local AppWizard-Generated Applications"));

	CAppDlg dlg;
	m_pMainWnd = &dlg;
	INT_PTR nResponse = dlg.DoModal();
	if (nResponse == IDOK)
	{
		// TODO: Place code here to handle when the dialog is
		//  dismissed with OK
	}
	else if (nResponse == IDCANCEL)
	{
		// TODO: Place code here to handle when the dialog is
		//  dismissed with Cancel
	}
	else if (nResponse == -1)
	{
		TRACE(traceAppMsg, 0, "Warning: dialog creation failed, so application is terminating unexpectedly.\n");
		TRACE(traceAppMsg, 0, "Warning: if you are using MFC controls on the dialog, you cannot #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS.\n");
	}

	// Delete the shell manager created above.
	if (pShellManager != NULL)
	{
		delete pShellManager;
	}

#if !defined(_AFXDLL) && !defined(_AFX_NO_MFC_CONTROLS_IN_DIALOGS)
	ControlBarCleanUp();
#endif

	// Since the dialog has been closed, return FALSE so that we exit the
	//  application, rather than start the application's message pump.
	return FALSE;
}



================================================
FILE: generator/generator.h
================================================

// generator.h : main header file for the PROJECT_NAME application
//

#pragma once

#ifndef __AFXWIN_H__
	#error "include 'stdafx.h' before including this file for PCH"
#endif

#include "resource.h"		// main symbols


// CApp:
// See generator.cpp for the implementation of this class
//

class CApp : public CWinApp
{
public:
	CApp();

// Overrides
public:
	virtual BOOL InitInstance();

// Implementation

	DECLARE_MESSAGE_MAP()
};

extern CApp theApp;


================================================
FILE: generator/generator.vcxproj
================================================
<?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|Win32">
      <Configuration>Debug</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|Win32">
      <Configuration>Release</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <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>15.0</VCProjectVersion>
    <ProjectGuid>{52BE8E83-C47E-469F-92B7-F078C51C0EBD}</ProjectGuid>
    <RootNamespace>generator</RootNamespace>
    <Keyword>MFCProj</Keyword>
    <ProjectName>ducode</ProjectName>
    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>v143</PlatformToolset>
    <CharacterSet>Unicode</CharacterSet>
    <UseOfMfc>Static</UseOfMfc>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>v143</PlatformToolset>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <CharacterSet>Unicode</CharacterSet>
    <UseOfMfc>Dynamic</UseOfMfc>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>v143</PlatformToolset>
    <CharacterSet>Unicode</CharacterSet>
    <UseOfMfc>Static</UseOfMfc>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>v143</PlatformToolset>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <CharacterSet>Unicode</CharacterSet>
    <UseOfMfc>Dynamic</UseOfMfc>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
  <ImportGroup Label="ExtensionSettings">
  </ImportGroup>
  <ImportGroup Label="Shared">
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <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|Win32'">
    <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)'=='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|Win32'">
    <LinkIncremental>true</LinkIncremental>
    <OutDir>$(SolutionDir)$(PlatformTarget)\$(Configuration)\</OutDir>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <LinkIncremental>true</LinkIncremental>
    <OutDir>$(SolutionDir)$(PlatformTarget)\$(Configuration)\</OutDir>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <LinkIncremental>false</LinkIncremental>
    <OutDir>$(SolutionDir)$(PlatformTarget)\$(Configuration)\</OutDir>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <LinkIncremental>false</LinkIncremental>
    <OutDir>$(SolutionDir)$(PlatformTarget)\$(Configuration)\</OutDir>
  </PropertyGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <ClCompile>
      <PrecompiledHeader>Use</PrecompiledHeader>
      <WarningLevel>Level3</WarningLevel>
      <Optimization>Disabled</Optimization>
      <PreprocessorDefinitions>WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <SDLCheck>true</SDLCheck>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <AdditionalDependencies>Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
    </Link>
    <Midl>
      <MkTypLibCompatible>false</MkTypLibCompatible>
      <ValidateAllParameters>true</ValidateAllParameters>
      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    </Midl>
    <ResourceCompile>
      <Culture>0x0409</Culture>
      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
    </ResourceCompile>
    <Manifest>
      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
    </Manifest>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <ClCompile>
      <PrecompiledHeader>Use</PrecompiledHeader>
      <WarningLevel>Level3</WarningLevel>
      <Optimization>Disabled</Optimization>
      <PreprocessorDefinitions>_WINDOWS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <SDLCheck>true</SDLCheck>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <AdditionalDependencies>Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
    </Link>
    <Midl>
      <MkTypLibCompatible>false</MkTypLibCompatible>
      <ValidateAllParameters>true</ValidateAllParameters>
      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    </Midl>
    <ResourceCompile>
      <Culture>0x0409</Culture>
      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
    </ResourceCompile>
    <Manifest>
      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
    </Manifest>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <PrecompiledHeader>Use</PrecompiledHeader>
      <Optimization>MaxSpeed</Optimization>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <SDLCheck>true</SDLCheck>
      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <OptimizeReferences>true</OptimizeReferences>
      <AdditionalDependencies>Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
    </Link>
    <Midl>
      <MkTypLibCompatible>false</MkTypLibCompatible>
      <ValidateAllParameters>true</ValidateAllParameters>
      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    </Midl>
    <ResourceCompile>
      <Culture>0x0409</Culture>
      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
    </ResourceCompile>
    <Manifest>
      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
    </Manifest>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <PrecompiledHeader>Use</PrecompiledHeader>
      <Optimization>MaxSpeed</Optimization>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <PreprocessorDefinitions>_WINDOWS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <SDLCheck>true</SDLCheck>
      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <OptimizeReferences>true</OptimizeReferences>
      <AdditionalDependencies>Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
    </Link>
    <Midl>
      <MkTypLibCompatible>false</MkTypLibCompatible>
      <ValidateAllParameters>true</ValidateAllParameters>
      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    </Midl>
    <ResourceCompile>
      <Culture>0x0409</Culture>
      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
    </ResourceCompile>
    <Manifest>
      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
    </Manifest>
  </ItemDefinitionGroup>
  <ItemGroup>
    <Text Include="ReadMe.txt" />
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="AdvEdit.h" />
    <ClInclude Include="appDlg.h" />
    <ClInclude Include="ClipboardHelper.h" />
    <ClInclude Include="DPISupport.h" />
    <ClInclude Include="encoding.h" />
    <ClInclude Include="FileItem.h" />
    <ClInclude Include="generator.h" />
    <ClInclude Include="Hasher.h" />
    <ClInclude Include="base64.h" />
    <ClInclude Include="ListBoxEx.h" />
    <ClInclude Include="ProgressText.h" />
    <ClInclude Include="Resource.h" />
    <ClInclude Include="stdafx.h" />
    <ClInclude Include="targetver.h" />
    <ClInclude Include="utils.h" />
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="AdvEdit.cpp" />
    <ClCompile Include="appDlg.cpp" />
    <ClCompile Include="base64.cpp" />
    <ClCompile Include="ClipboardHelper.cpp" />
    <ClCompile Include="DPISupport.cpp" />
    <ClCompile Include="encoding.cpp" />
    <ClCompile Include="FileItem.cpp" />
    <ClCompile Include="generator.cpp" />
    <ClCompile Include="Hasher.cpp" />
    <ClCompile Include="ListBoxEx.cpp" />
    <ClCompile Include="ProgressText.cpp" />
    <ClCompile Include="stdafx.cpp">
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
    </ClCompile>
    <ClCompile Include="utils.cpp" />
  </ItemGroup>
  <ItemGroup>
    <ResourceCompile Include="generator.rc" />
  </ItemGroup>
  <ItemGroup>
    <None Include="res\generator.rc2" />
  </ItemGroup>
  <ItemGroup>
    <Image Include="res\generator.ico" />
    <Image Include="res\tick.ico" />
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  <ImportGroup Label="ExtensionTargets">
  </ImportGroup>
</Project>

================================================
FILE: generator/generator.vcxproj.filters
================================================
<?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;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;hm;inl;inc;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>
    <Filter Include="Components">
      <UniqueIdentifier>{d8e86c5e-c09b-40e0-9359-225308efac4d}</UniqueIdentifier>
    </Filter>
  </ItemGroup>
  <ItemGroup>
    <Text Include="ReadMe.txt" />
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="generator.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="appDlg.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="stdafx.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="targetver.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="Resource.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="utils.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="Hasher.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="FileItem.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="base64.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="encoding.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="AdvEdit.h">
      <Filter>Components</Filter>
    </ClInclude>
    <ClInclude Include="ProgressText.h">
      <Filter>Components</Filter>
    </ClInclude>
    <ClInclude Include="ListBoxEx.h">
      <Filter>Components</Filter>
    </ClInclude>
    <ClInclude Include="ClipboardHelper.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="DPISupport.h">
      <Filter>Header Files</Filter>
    </ClInclude>
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="AdvEdit.cpp">
      <Filter>Components</Filter>
    </ClCompile>
    <ClCompile Include="ListBoxEx.cpp">
      <Filter>Components</Filter>
    </ClCompile>
    <ClCompile Include="ProgressText.cpp">
      <Filter>Components</Filter>
    </ClCompile>
    <ClCompile Include="appDlg.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="base64.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="encoding.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="FileItem.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="generator.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="Hasher.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="stdafx.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="utils.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="ClipboardHelper.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="DPISupport.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
  </ItemGroup>
  <ItemGroup>
    <ResourceCompile Include="generator.rc">
      <Filter>Resource Files</Filter>
    </ResourceCompile>
  </ItemGroup>
  <ItemGroup>
    <None Include="res\generator.rc2">
      <Filter>Resource Files</Filter>
    </None>
  </ItemGroup>
  <ItemGroup>
    <Image Include="res\generator.ico">
      <Filter>Resource Files</Filter>
    </Image>
    <Image Include="res\tick.ico">
      <Filter>Resource Files</Filter>
    </Image>
  </ItemGroup>
</Project>

================================================
FILE: generator/resource.h
================================================
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by generator.rc
//
#define IDM_ABOUTBOX                    0x0010
#define IDD_ABOUTBOX                    100
#define IDS_ABOUTBOX                    101
#define IDD_GENERATOR_DIALOG            102
#define IDS_PICK_FILE                   102
#define IDS_PICK_DIR                    103
#define IDS_DIR                         104
#define IDS_FILE_SIZE                   105
#define IDS_FILE_INFO                   106
#define IDS_LIST_PLACEHOLDER            107
#define IDS_ERROR_ENCODE_FAIL           108
#define IDR_MAINFRAME                   128
#define IDI_ICON_TICK                   131
#define IDC_LIST_FILES                  1000
#define IDC_EDIT_OUTPUT                 1001
#define IDC_PROG_FILE                   1002
#define IDC_PROG_ALL                    1003
#define IDC_BTN_ADD_DIR                 1004
#define IDC_BTN_ADD_FILE                1005
#define IDC_SYSLINK_BLOG                1006
#define IDC_LB_STATUS                   1007
#define IDC_BTN_CLEAR                   1008
#define IDC_CHK_RECURSIVE               1009
#define IDC_BTN_COPY                    1010
#define IDC_GENERATE                    1011
#define IDC_BTN_GENERATE                1011
#define IDC_CHK_URL                     1012

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        132
#define _APS_NEXT_COMMAND_VALUE         32771
#define _APS_NEXT_CONTROL_VALUE         1013
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif


================================================
FILE: generator/stdafx.cpp
================================================

// stdafx.cpp : source file that includes just the standard includes
// generator.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information

#include "stdafx.h"




================================================
FILE: generator/stdafx.h
================================================

// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently,
// but are changed infrequently

#pragma once

#ifndef VC_EXTRALEAN
#define VC_EXTRALEAN            // Exclude rarely-used stuff from Windows headers
#endif

#include "targetver.h"

#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS      // some CString constructors will be explicit

// turns off MFC's hiding of some common and often safely ignored warning messages
#define _AFX_ALL_WARNINGS

#include <afxwin.h>         // MFC core and standard components
#include <afxext.h>         // MFC extensions





#ifndef _AFX_NO_OLE_SUPPORT
#include <afxdtctl.h>           // MFC support for Internet Explorer 4 Common Controls
#endif
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h>             // MFC support for Windows Common Controls
#endif // _AFX_NO_AFXCMN_SUPPORT

#include <afxcontrolbars.h>     // MFC support for ribbons and control bars









#ifdef _UNICODE
#if defined _M_IX86
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_X64
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#else
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif
#endif


#ifndef uint
#define uint unsigned int
#endif

#include <vector>

#if _MSC_VER < 1930
// less than vs2022, use the full Windows.h header
#include <Windows.h>
#else
// Other: use a subset of the headers.
#include <minwinbase.h>
#include <fileapi.h>
#endif
#include "afxcmn.h"
#include "afxwin.h"


#define SAFE_DELETE(a)       \
	if( (a) != nullptr ) {   \
		delete (a);          \
	}                        \
	(a) = nullptr;


================================================
FILE: generator/targetver.h
================================================
#pragma once

// Including SDKDDKVer.h defines the highest available Windows platform.

// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.

#include <SDKDDKVer.h>


================================================
FILE: generator/utils.cpp
================================================
#include "stdafx.h"
#include "utils.h"

std::vector<CString*> OldStyleFileDialog(const CString& title, HWND hwnd)
{
	std::vector<CString*> v;
	CString str;
	OPENFILENAME ofn = {0};
	ofn.lStructSize = sizeof ofn;
	ofn.lpstrTitle = title;
	ofn.hwndOwner = hwnd;
	ofn.lpstrFile = str.GetBuffer(1024);
	ofn.nMaxFile = 1024;
	if (GetOpenFileName(&ofn))
	{
		v.push_back(new CString(str));
	}
	str.ReleaseBuffer();

	return v;
}

inline std::vector<CString*> OldStyleDirectoryDialog(CString &title, HWND hWnd)
{
	std::vector<CString*> v;
	BROWSEINFO bi;
	ZeroMemory(&bi, sizeof bi);
	bi.hwndOwner = hWnd;
	// bi.lpfn = cb_set_initial;
	bi.lpszTitle = title;
	bi.ulFlags = BIF_EDITBOX | BIF_NEWDIALOGSTYLE;

	TCHAR szPath[1024];
	if (SHGetPathFromIDList(SHBrowseForFolder(&bi), szPath))
	{
		v.push_back(new CString(szPath));
	}
	return v;
}

DWORD OpenFileDialog(CString &title, HWND hWnd, DWORD flag, std::vector<CString*> &v)
{
	IFileOpenDialog* pFileOpen;
	do
	{
		if (FAILED(CoCreateInstance(CLSID_FileOpenDialog,
			nullptr,
			CLSCTX_INPROC_SERVER,
			IID_PPV_ARGS(&pFileOpen))))
		{
			return 1;
		}

		FILEOPENDIALOGOPTIONS fos;
		if (FAILED(pFileOpen->GetOptions(&fos))) break;
		fos |= flag | FOS_ALLOWMULTISELECT | FOS_FORCEFILESYSTEM;
		if (FAILED(pFileOpen->SetOptions(fos))) break;
		if (FAILED(pFileOpen->SetTitle(title))) break;
		if (FAILED(pFileOpen->Show(hWnd))) break;

		IShellItem* pShellItem;
		pFileOpen->GetResult(&pShellItem);

		IShellItemArray* pResults;
		if (FAILED(pFileOpen->GetResults(&pResults))) break;
		DWORD dwCount;
		if (FAILED(pResults->GetCount(&dwCount))) break;


		v.clear();
		for (uint i = 0; i < dwCount; i++)
		{
			IShellItem* pItem;
			pResults->GetItemAt(i, &pItem);

			TCHAR* filePath;
			pItem->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &filePath);

			v.push_back(new CString(filePath));

			CoTaskMemFree(filePath);
			pItem->Release();
		}

		if (pFileOpen) pFileOpen->Release();
		return 0;
	} while (false);

	if (pFileOpen) pFileOpen->Release();
	return 0;
}

std::vector<CString*> OpenDirectoryDialog(CString &title, HWND hWnd)
{
	std::vector<CString*> r;
	auto err = OpenFileDialog(title, hWnd, FOS_PICKFOLDERS, r);
	if (err == 1) return OldStyleDirectoryDialog(title, hWnd);
	return r;
}

std::vector<CString*> OpenFileDialog(CString &title, HWND hWnd)
{
	std::vector<CString*> r;
	auto err = OpenFileDialog(title, hWnd, 0, r);
	if (err == 1) return OldStyleFileDialog(title, hWnd);
	return r;
}


void EnumFiles(const CString& srcDir, bool recursive, f_file_callback cb, void* extra) {
	auto dir(srcDir);
	if (dir.Right(1).Compare(_T("\\")) == 0)
	{
		dir.AppendChar(_T('*'));
	}
	else
	{
		dir.Append(_T("\\*"));
	}

	WIN32_FIND_DATA ffd;
	auto hFind = FindFirstFile(dir, &ffd);
	if (hFind == INVALID_HANDLE_VALUE)
	{
		return;
	}

	do
	{
		if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
		{
			if (recursive)
			{
				if (_tcscmp(ffd.cFileName, _T(".")) != 0
					&& _tcscmp(ffd.cFileName, _T("..")) != 0)
				{
#if _DEBUG
					CString str;
					str.Format(_T("enter dir: %s\n"), ffd.cFileName);
					OutputDebugString(str);
#endif
					EnumFiles(srcDir + _T("\\") + ffd.cFileName, recursive, cb, extra);
				}
			}
		}
		else
		{
#if _DEBUG
			CString str;
			str.Format(_T("add file: %s\n"), ffd.cFileName);
			OutputDebugString(str);
#endif
			cb(srcDir, ffd.cFileName, extra);
		}
	} while (FindNextFile(hFind, &ffd) != 0);
	FindClose(hFind);
}


================================================
FILE: generator/utils.h
================================================
#pragma once

std::vector<CString*> OpenFileDialog(CString &title, HWND hWnd);
std::vector<CString*> OpenDirectoryDialog(CString &title, HWND hWnd);

typedef void(*f_file_callback) (const CString &strDir, const CString &strName, void* extra);
void EnumFiles(const CString& srcDir, bool recursive, f_file_callback cb, void* extra = nullptr);


================================================
FILE: mfcDuDownloadCodeGenerator.sln
================================================

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.3.32922.545
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ducode", "generator\generator.vcxproj", "{52BE8E83-C47E-469F-92B7-F078C51C0EBD}"
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|x64 = Debug|x64
		Debug|x86 = Debug|x86
		Release|x64 = Release|x64
		Release|x86 = Release|x86
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{52BE8E83-C47E-469F-92B7-F078C51C0EBD}.Debug|x64.ActiveCfg = Debug|x64
		{52BE8E83-C47E-469F-92B7-F078C51C0EBD}.Debug|x64.Build.0 = Debug|x64
		{52BE8E83-C47E-469F-92B7-F078C51C0EBD}.Debug|x86.ActiveCfg = Debug|Win32
		{52BE8E83-C47E-469F-92B7-F078C51C0EBD}.Debug|x86.Build.0 = Debug|Win32
		{52BE8E83-C47E-469F-92B7-F078C51C0EBD}.Release|x64.ActiveCfg = Release|x64
		{52BE8E83-C47E-469F-92B7-F078C51C0EBD}.Release|x64.Build.0 = Release|x64
		{52BE8E83-C47E-469F-92B7-F078C51C0EBD}.Release|x86.ActiveCfg = Release|Win32
		{52BE8E83-C47E-469F-92B7-F078C51C0EBD}.Release|x86.Build.0 = Release|Win32
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
	GlobalSection(ExtensibilityGlobals) = postSolution
		SolutionGuid = {BC2322A7-E814-48A2-93F3-2D9DF1A6A0A4}
	EndGlobalSection
EndGlobal
Download .txt
gitextract_vof0guyl/

├── .gitattributes
├── .github/
│   └── workflows/
│       └── msvc.yml
├── .gitignore
├── LICENSE
├── README.MD
├── generator/
│   ├── AdvEdit.cpp
│   ├── AdvEdit.h
│   ├── ClipboardHelper.cpp
│   ├── ClipboardHelper.h
│   ├── DPISupport.cpp
│   ├── DPISupport.h
│   ├── FileItem.cpp
│   ├── FileItem.h
│   ├── Hasher.cpp
│   ├── Hasher.h
│   ├── ListBoxEx.cpp
│   ├── ListBoxEx.h
│   ├── ProgressText.cpp
│   ├── ProgressText.h
│   ├── ReadMe.txt
│   ├── appDlg.cpp
│   ├── appDlg.h
│   ├── base64.cpp
│   ├── base64.h
│   ├── encoding.cpp
│   ├── encoding.h
│   ├── generator.cpp
│   ├── generator.h
│   ├── generator.rc
│   ├── generator.vcxproj
│   ├── generator.vcxproj.filters
│   ├── res/
│   │   └── generator.rc2
│   ├── resource.h
│   ├── stdafx.cpp
│   ├── stdafx.h
│   ├── targetver.h
│   ├── utils.cpp
│   └── utils.h
└── mfcDuDownloadCodeGenerator.sln
Download .txt
SYMBOL INDEX (35 symbols across 19 files)

FILE: generator/AdvEdit.h
  function class (line 7) | class CAdvEdit : public CEdit

FILE: generator/ClipboardHelper.cpp
  function CopyStringToClipboard (line 4) | void CopyStringToClipboard(CString& str, HWND hWnd) {

FILE: generator/DPISupport.h
  function namespace (line 6) | namespace DPISupport {

FILE: generator/FileItem.cpp
  function CString (line 31) | CString CFileItem::GetSizeString() const
  function CString (line 56) | CString CFileItem::BDLink() const
  function CString (line 84) | CString CFileItem::DownloadCode() const

FILE: generator/FileItem.h
  function class (line 2) | class CFileItem

FILE: generator/Hasher.cpp
  function CString (line 68) | CString* Hasher::GetHashStr()

FILE: generator/Hasher.h
  function class (line 4) | class Hasher

FILE: generator/ListBoxEx.cpp
  function FileSize (line 296) | uint64_t FileSize(const wchar_t* name)
  function INT_PTR (line 406) | INT_PTR CListBoxEx::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
  function BOOL (line 423) | BOOL CListBoxEx::OnToolTipText(UINT id, NMHDR * pNMHDR, LRESULT * pResult)

FILE: generator/ListBoxEx.h
  function ProcType (line 8) | enum class ProcType

FILE: generator/ProgressText.cpp
  function shrink (line 10) | void inline shrink(CRect* rect) {
  function BOOL (line 168) | BOOL CProgressText::OnEraseBkgnd(CDC* pDC)

FILE: generator/ProgressText.h
  function class (line 5) | class CProgressText : public CProgressCtrl

FILE: generator/appDlg.cpp
  class CAboutDlg (line 19) | class CAboutDlg : public CDialogEx
  function BOOL (line 98) | BOOL CAppDlg::OnInitDialog()
  function HCURSOR (line 186) | HCURSOR CAppDlg::OnQueryDragIcon()
  function _thread_process_file (line 191) | void WINAPI _thread_process_file(CAppDlg* app)
  function cb_add_file (line 202) | void cb_add_file(const CString &srcDir, const CString &filename, void* e...
  function _proc_file_callback (line 235) | void _proc_file_callback(ProcType type, double progress, CFileItem* lpIt...
  function DWORD (line 359) | DWORD WINAPI _thread_stop_process(void* param)

FILE: generator/appDlg.h
  function class (line 14) | class CAppDlg : public CDialogEx

FILE: generator/base64.cpp
  function wchar_t (line 28) | wchar_t* base64_encode(const unsigned char* src, size_t len)

FILE: generator/encoding.cpp
  function ToUTF8 (line 4) | void ToUTF8(utf8_str& output, wchar_t* input)

FILE: generator/encoding.h
  type utf8_str (line 3) | struct utf8_str {

FILE: generator/generator.cpp
  function BOOL (line 40) | BOOL CApp::InitInstance()

FILE: generator/generator.h
  function class (line 18) | class CApp : public CWinApp

FILE: generator/utils.cpp
  function OldStyleFileDialog (line 4) | std::vector<CString*> OldStyleFileDialog(const CString& title, HWND hwnd)
  function OldStyleDirectoryDialog (line 23) | inline std::vector<CString*> OldStyleDirectoryDialog(CString &title, HWN...
  function DWORD (line 41) | DWORD OpenFileDialog(CString &title, HWND hWnd, DWORD flag, std::vector<...
  function OpenDirectoryDialog (line 93) | std::vector<CString*> OpenDirectoryDialog(CString &title, HWND hWnd)
  function OpenFileDialog (line 101) | std::vector<CString*> OpenFileDialog(CString &title, HWND hWnd)
  function EnumFiles (line 110) | void EnumFiles(const CString& srcDir, bool recursive, f_file_callback cb...
Condensed preview — 39 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (92K chars).
[
  {
    "path": ".gitattributes",
    "chars": 2518,
    "preview": "###############################################################################\n# Set default behavior to automatically "
  },
  {
    "path": ".github/workflows/msvc.yml",
    "chars": 3632,
    "preview": "name: MSBuild\n\non:\n  push:\n  pull_request:\n    branches: [ \"main\" ]\n\nenv:\n  # Path to the solution file relative to the "
  },
  {
    "path": ".gitignore",
    "chars": 4335,
    "preview": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User"
  },
  {
    "path": "LICENSE",
    "chars": 1516,
    "preview": "BSD 3-Clause License\n\nCopyright (c) 2020, Jixun Wu\nAll rights reserved.\n\nRedistribution and use in source and binary for"
  },
  {
    "path": "README.MD",
    "chars": 212,
    "preview": "# mfcDuDownloadCodeGenerator\nڰٶ̵ı׼ȡ\n\n![](https://cdn.jsdelivr.net/gh/JixunMoe/mfcDuDownloadCodeGenerator/imgs/sshot-stdc"
  },
  {
    "path": "generator/AdvEdit.cpp",
    "chars": 931,
    "preview": "// AdvEdit.cpp : implementation file\n//\n\n#include \"stdafx.h\"\n#include \"AdvEdit.h\"\n\n// CAdvEdit\n\nIMPLEMENT_DYNAMIC(CAdvEd"
  },
  {
    "path": "generator/AdvEdit.h",
    "chars": 333,
    "preview": "#pragma once\n#include <mutex>\n\n\n// CAdvEdit\n\nclass CAdvEdit : public CEdit\n{\n\tDECLARE_DYNAMIC(CAdvEdit)\n\tstd::mutex mute"
  },
  {
    "path": "generator/ClipboardHelper.cpp",
    "chars": 627,
    "preview": "#include \"stdafx.h\"\n#include \"ClipboardHelper.h\"\n\nvoid CopyStringToClipboard(CString& str, HWND hWnd) {\n\tauto pString = "
  },
  {
    "path": "generator/ClipboardHelper.h",
    "chars": 97,
    "preview": "#pragma once\n#include \"stdafx.h\"\n\nvoid CopyStringToClipboard(CString& str, HWND hWnd = nullptr);\n"
  },
  {
    "path": "generator/DPISupport.cpp",
    "chars": 673,
    "preview": "#include \"stdafx.h\"\n\n#include \"DPISupport.h\"\n\n#if !__BUILD_FOR_XP\n#include <ShellScalingApi.h>\n#include <VersionHelpers."
  },
  {
    "path": "generator/DPISupport.h",
    "chars": 115,
    "preview": "#pragma once\n\n#include <Windows.h>\n#include <cstdint>\n\nnamespace DPISupport {\n\tuint32_t GetWindowDPI(HWND hWnd);\n}\n"
  },
  {
    "path": "generator/FileItem.cpp",
    "chars": 1783,
    "preview": "#include \"stdafx.h\"\n#include \"FileItem.h\"\n#include \"encoding.h\"\n#include \"base64.h\"\n#include \"resource.h\"\n\nCFileItem::CF"
  },
  {
    "path": "generator/FileItem.h",
    "chars": 375,
    "preview": "#pragma once\nclass CFileItem\n{\npublic:\n\tCString* m_pDirectory = nullptr;\n\tCString* m_pFilename = nullptr;\n\tHICON m_hIcon"
  },
  {
    "path": "generator/Hasher.cpp",
    "chars": 1604,
    "preview": "#include \"stdafx.h\"\n#include \"Hasher.h\"\n\n\nbool Hasher::Init()\n{\n\tauto bSuccess = false;\n\n\tif (CryptAcquireContext(&m_hC"
  },
  {
    "path": "generator/Hasher.h",
    "chars": 300,
    "preview": "#pragma once\n#include <Wincrypt.h>\n\nclass Hasher\n{\n\tHCRYPTPROV m_hCryptProv = NULL;\n\tHCRYPTHASH m_phHash = NULL;\n\tHCRYPT"
  },
  {
    "path": "generator/ListBoxEx.cpp",
    "chars": 11114,
    "preview": "// ListBoxEx.cpp : implementation file\n//\n\n#include \"stdafx.h\"\n#include \"ListBoxEx.h\"\n#include \"resource.h\"\n#include \"H"
  },
  {
    "path": "generator/ListBoxEx.h",
    "chars": 1524,
    "preview": "#pragma once\n#include <mutex>\n\n#include \"FileItem.h\"\n\n// CListBoxEx\n\nenum class ProcType\n{\n\tFILE_PROG,\n\tINC_FILE,\n\tERR_F"
  },
  {
    "path": "generator/ProgressText.cpp",
    "chars": 3877,
    "preview": "// ProgressText.cpp : implementation file\n//\n\n#include \"stdafx.h\"\n\n#include \"generator.h\"\n#include \"ProgressText.h\"\n#in"
  },
  {
    "path": "generator/ProgressText.h",
    "chars": 757,
    "preview": "#pragma once\n\n// CProgressText\n\nclass CProgressText : public CProgressCtrl\n{\n\tCFont* font;\n\tCOLORREF progressForegroundC"
  },
  {
    "path": "generator/ReadMe.txt",
    "chars": 4922,
    "preview": "================================================================================\n    MICROSOFT FOUNDATION CLASS LIBRARY "
  },
  {
    "path": "generator/appDlg.cpp",
    "chars": 9893,
    "preview": "\n// appDlg.cpp : implementation file\n//\n\n#include \"stdafx.h\"\n#include \"generator.h\"\n#include \"appDlg.h\"\n#include \"afxdi"
  },
  {
    "path": "generator/appDlg.h",
    "chars": 1686,
    "preview": "\n// appDlg.h : header file\n//\n\n#pragma once\n\n#include \"ProgressText.h\"\n#include \"AdvEdit.h\"\n#include \"ListBoxEx.h\"\n#incl"
  },
  {
    "path": "generator/base64.cpp",
    "chars": 2022,
    "preview": "/*\n* Base64 encoding/decoding (RFC1341)\n* Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>\n*\n* This software may be dist"
  },
  {
    "path": "generator/base64.h",
    "chars": 94,
    "preview": "#pragma once\n#include <string>\n\nwchar_t* base64_encode(const unsigned char* src, size_t len);\n"
  },
  {
    "path": "generator/encoding.cpp",
    "chars": 359,
    "preview": "#include \"stdafx.h\"\n#include \"encoding.h\"\n\nvoid ToUTF8(utf8_str& output, wchar_t* input)\n{\n\tsize_t out_size = WideCharTo"
  },
  {
    "path": "generator/encoding.h",
    "chars": 109,
    "preview": "#pragma once\n\nstruct utf8_str {\n\tchar* str;\n\tsize_t size;\n};\n\nvoid ToUTF8(utf8_str& output, wchar_t* input);\n"
  },
  {
    "path": "generator/generator.cpp",
    "chars": 2825,
    "preview": "\n// generator.cpp : Defines the class behaviors for the application.\n//\n\n#include \"stdafx.h\"\n#include \"generator.h\"\n#inc"
  },
  {
    "path": "generator/generator.h",
    "chars": 457,
    "preview": "\n// generator.h : main header file for the PROJECT_NAME application\n//\n\n#pragma once\n\n#ifndef __AFXWIN_H__\n\t#error \"incl"
  },
  {
    "path": "generator/generator.vcxproj",
    "chars": 12234,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.micros"
  },
  {
    "path": "generator/generator.vcxproj.filters",
    "chars": 4067,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuil"
  },
  {
    "path": "generator/resource.h",
    "chars": 1597,
    "preview": "//{{NO_DEPENDENCIES}}\n// Microsoft Visual C++ generated include file.\n// Used by generator.rc\n//\n#define IDM_ABOUTBOX   "
  },
  {
    "path": "generator/stdafx.cpp",
    "chars": 203,
    "preview": "\n// stdafx.cpp : source file that includes just the standard includes\n// generator.pch will be the pre-compiled header\n/"
  },
  {
    "path": "generator/stdafx.h",
    "chars": 2070,
    "preview": "\n// stdafx.h : include file for standard system include files,\n// or project specific include files that are used freque"
  },
  {
    "path": "generator/targetver.h",
    "chars": 306,
    "preview": "#pragma once\n\n// Including SDKDDKVer.h defines the highest available Windows platform.\n\n// If you wish to build your app"
  },
  {
    "path": "generator/utils.cpp",
    "chars": 3420,
    "preview": "#include \"stdafx.h\"\n#include \"utils.h\"\n\nstd::vector<CString*> OldStyleFileDialog(const CString& title, HWND hwnd)\n{\n\tst"
  },
  {
    "path": "generator/utils.h",
    "chars": 341,
    "preview": "#pragma once\n\nstd::vector<CString*> OpenFileDialog(CString &title, HWND hWnd);\nstd::vector<CString*> OpenDirectoryDialog"
  },
  {
    "path": "mfcDuDownloadCodeGenerator.sln",
    "chars": 1412,
    "preview": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.3.3292"
  }
]

// ... and 2 more files (download for full content)

About this extraction

This page contains the full source code of the jixunmoe/mfcDuDownloadCodeGenerator GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 39 files (82.4 KB), approximately 24.1k tokens, and a symbol index with 35 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!