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://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
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
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\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.