WL
C++ Enum Compilation Errors
PapyrusInterface.cpp
278 lines
txt
PapyrusInterface.h
39 lines
txt
pch.h
62 lines
txt
plugin.cpp
61 lines
txt
ScreenCapture.cpp
958 lines
txt
ScreenCapture.h
92 lines
txt
enum "ScreenCapture::ImageFormat" has no member "JPEG" enum "ScreenCapture::DDSCompression" has no member "BC1" enum "ScreenCapture::DDSCompression" has no member "BC2" enum "ScreenCapture::DDSCompression" has no member "BC3" enum "ScreenCapture::DDSCompression" has no member "BC4" enum "Screen
pasted
enum "ScreenCapture::ImageFormat" has no member "JPEG" enum "ScreenCapture::DDSCompression" has no member "BC1" enum "ScreenCapture::DDSCompression" has no member "BC2" enum "ScreenCapture::DDSCompression" has no member "BC3" enum "ScreenCapture::DDSCompression" has no member "BC4" enum "Screen
pasted
function 'ScreenCapture::ImageFormat ScreenCapture::StringToImageFormat(const std::string &)' already has a body 'JPEG': illegal qualified name in member declaration 'JPEG': undeclared identifier function 'ScreenCapture::DDSCompression ScreenCapture::StringToDDSCompression(const std::string &)' a
pasted
function 'ScreenCapture::ImageFormat ScreenCapture::StringToImageFormat(const std::string &)' already has a body 'JPEG': illegal qualified name in member declaration 'JPEG': undeclared identifier function 'ScreenCapture::DDSCompression ScreenCapture::StringToDDSCompression(const std::string &)' a
pasted
function 'ScreenCapture::ImageFormat ScreenCapture::StringToImageFormat(const std::string &)' already has a body 'JPEG': illegal qualified name in member declaration 'JPEG': undeclared identifier function 'ScreenCapture::DDSCompression ScreenCapture::StringToDDSCompression(const std::string &)' a
pasted
function 'ScreenCapture::ImageFormat ScreenCapture::StringToImageFormat(const std::string &)' already has a body 'JPEG': illegal qualified name in member declaration 'JPEG': undeclared identifier function 'ScreenCapture::DDSCompression ScreenCapture::StringToDDSCompression(const std::string &)' a
pasted
function 'ScreenCapture::ImageFormat ScreenCapture::StringToImageFormat(const std::string &)' already has a body 'JPEG': illegal qualified name in member declaration 'JPEG': undeclared identifier function 'ScreenCapture::DDSCompression ScreenCapture::StringToDDSCompression(const std::string &)' a
pasted
function 'ScreenCapture::ImageFormat ScreenCapture::StringToImageFormat(const std::string &)' already has a body 'JPEG': illegal qualified name in member declaration 'JPEG': undeclared identifier function 'ScreenCapture::DDSCompression ScreenCapture::StringToDDSCompression(const std::string &)' a
pasted
function 'ScreenCapture::ImageFormat ScreenCapture::StringToImageFormat(const std::string &)' already has a body 'JPEG': illegal qualified name in member declaration 'JPEG': undeclared identifier function 'ScreenCapture::DDSCompression ScreenCapture::StringToDDSCompression(const std::string &)' a
pasted
function 'ScreenCapture::ImageFormat ScreenCapture::StringToImageFormat(const std::string &)' already has a body 'JPEG': illegal qualified name in member declaration 'JPEG': undeclared identifier function 'ScreenCapture::DDSCompression ScreenCapture::StringToDDSCompression(const std::string &)' a
pasted
function 'ScreenCapture::ImageFormat ScreenCapture::StringToImageFormat(const std::string &)' already has a body 'JPEG': illegal qualified name in member declaration 'JPEG': undeclared identifier function 'ScreenCapture::DDSCompression ScreenCapture::StringToDDSCompression(const std::string &)' a
pasted
function 'ScreenCapture::ImageFormat ScreenCapture::StringToImageFormat(const std::string &)' already has a body 'JPEG': illegal qualified name in member declaration 'JPEG': undeclared identifier function 'ScreenCapture::DDSCompression ScreenCapture::StringToDDSCompression(const std::string &)' a
pasted
function 'ScreenCapture::ImageFormat ScreenCapture::StringToImageFormat(const std::string &)' already has a body 'JPEG': illegal qualified name in member declaration 'JPEG': undeclared identifier function 'ScreenCapture::DDSCompression ScreenCapture::StringToDDSCompression(const std::string &)' a
pasted
function 'ScreenCapture::ImageFormat ScreenCapture::StringToImageFormat(const std::string &)' already has a body 'JPEG': illegal qualified name in member declaration 'JPEG': undeclared identifier function 'ScreenCapture::DDSCompression ScreenCapture::StringToDDSCompression(const std::string &)' a
pasted
WL
Ok The enumerations are still not right, please review the attached files and correct this problem. function 'ScreenCapture::ImageFormat ScreenCapture::StringToImageFormat(const std::string &)' already has a body 'JPEG': illegal qualified name in member declaration 'JPEG': undeclared identifier function 'ScreenCapture::DDSCompression ScreenCapture::StringToDDSCompression(const std::string &)' already has a body 'BC1': illegal qualified name in member declaration 'BC1': undeclared identifier 'BC2': illegal qualified name in member declaration 'BC2': undeclared identifier 'BC3': illegal qualified name in member declaration 'BC3': undeclared identifier 'BC4': illegal qualified name in member declaration 'BC4': undeclared identifier 'BC5': illegal qualified name in member declaration 'BC5': undeclared identifier 'BC6H': illegal qualified name in member declaration 'BC6H': undeclared identifier 'BC7_SLOW': illegal qualified name in member declaration 'BC7_SLOW': undeclared identifier 'BC7_NORMAL': illegal qualified name in member declaration 'BC7_NORMAL': undeclared identifier 'BC7_FAST': illegal qualified name in member declaration 'BC7_FAST': undeclared identifier 'BC1': illegal qualified name in member declaration 'BC1': undeclared identifier missing type specifier - int assumed. Note: C++ does not support default-int syntax error: missing ';' before identifier 'StringToTiffCompression' syntax error: missing ';' before '{' '{': missing function header (old-style formal list?) 'BC1': illegal qualified name in member declaration 'BC1': undeclared identifier expression did not evaluate to a constant 'BC2': illegal qualified name in member declaration 'BC2': undeclared identifier expression did not evaluate to a constant 'BC3': illegal qualified name in member declaration 'BC3': undeclared identifier expression did not evaluate to a constant 'BC4': illegal qualified name in member declaration 'BC4': undeclared identifier expression did not evaluate to a constant 'BC5': illegal qualified name in member declaration 'BC5': undeclared identifier expression did not evaluate to a constant 'BC6H': illegal qualified name in member declaration 'BC6H': undeclared identifier expression did not evaluate to a constant 'BC7_SLOW': illegal qualified name in member declaration 'BC7_SLOW': undeclared identifier expression did not evaluate to a constant 'BC7_NORMAL': illegal qualified name in member declaration 'BC7_NORMAL': undeclared identifier expression did not evaluate to a constant 'BC7_FAST': illegal qualified name in member declaration 'BC7_FAST': undeclared identifier expression did not evaluate to a constant case expression not constant case expression not constant case expression not constant case expression not constant case expression not constant case expression not constant case expression not constant case expression not constant case expression not constant 'BC7_SLOW': illegal qualified name in member declaration 'BC7_SLOW': undeclared identifier expression did not evaluate to a constant 'BC7_NORMAL': illegal qualified name in member declaration 'BC7_NORMAL': undeclared identifier expression did not evaluate to a constant 'BC7_FAST': illegal qualified name in member declaration 'BC7_FAST': undeclared identifier expression did not evaluate to a constant 'BC6H': illegal qualified name in member declaration 'BC6H': undeclared identifier expression did not evaluate to a constant case expression not constant case expression not constant case expression not constant case expression not constant 'BC6H': illegal qualified name in member declaration 'BC6H': undeclared identifier expression did not evaluate to a constant 'BC7_SLOW': illegal qualified name in member declaration 'BC7_SLOW': undeclared identifier expression did not evaluate to a constant 'BC7_NORMAL': illegal qualified name in member declaration 'BC7_NORMAL': undeclared identifier expression did not evaluate to a constant 'BC7_FAST': illegal qualified name in member declaration 'BC7_FAST': undeclared identifier expression did not evaluate to a constant case expression not constant case expression not constant case expression not constant case expression not constant 'JPEG': illegal qualified name in member declaration 'JPEG': undeclared identifier expression did not evaluate to a constant case expression not constant 'JPEG': illegal qualified name in member declaration 'JPEG': undeclared identifier error count exceeds 100; stopping compilation
Edit
Looking at your code, I can see several issues that need to be fixed. The main problems are:
- Enum mismatches between the header and implementation files
- Duplicate function definitions (inline functions in header are being redefined in the .cpp file)
- Missing enum values that are being referenced
- Struct member name mismatch (
filePathvsfilepath)
Let me provide you with corrected versions of the files:
Fixed ScreenCapture.h
Code
#pragma once #include "PCH.h" #include <string> #include <atomic> namespace ScreenCapture { // Image format enumeration - matches what's used in ScreenCapture.cpp enum class ImageFormat { PNG = 0, JPEG, // Changed
Fixed ScreenCapture.cpp (Key Changes)
Code
// Key changes needed in ScreenCapture.cpp - showing the corrected function implementations // Change 1: Fix the StringToImageFormat function to match header enum ImageFormat StringToImageFormat(const std::string& formatStr) { auto fmt = ToUpper
Now, let me provide the complete corrected ScreenCapture.cpp with all the necessary changes:
F
write_file
Retry
WL
Continue
Edit
F
write_file
Retry
WL
Please provide the fixed screncapture.ccp complete responce as an artifact instead of using file write
Edit
Complete Fixed ScreenCapture.cpp
Code
#include "PCH.h" #include "ScreenCapture.h" #include "logger.h" using Microsoft::WRL::ComPtr; namespace fs = std::filesystem; namespace ScreenCapture { // RAII COM initializer class COMInitializer { public: COMInitializer() : i
Retry
WL
Continue
Edit
Complete Fixed ScreenCapture.cpp
Code ∙ Version 2
// -------------------------------------------------- // Multi-frame (animated) GIF capture // -------------------------------------------------- CaptureResult GIF(const CaptureParams& params) { CaptureResult result;
Now here's a summary of the key issues that were fixed:
Summary of Fixes Applied
1. Enum Mismatches Fixed:
- Changed
ImageFormat::JPGtoImageFormat::JPEGthroughout the code - Added all missing
DDSCompressionenum values:BC1,BC2,BC3,BC4,BC5,BC6H,BC7_SLOW,BC7_NORMAL,BC7_FAST - Renamed
TiffCompressiontoTiffModeand added missing values:CCITT1D,CCITT4,RLE
2. Function Declaration Issues Fixed:
- Removed inline function implementations from the header file
- Changed functions in header to forward declarations only
- Fixed duplicate function definitions error
3. Struct Member Name Fixed:
- Changed
CaptureResult::filePathtoCaptureResult::filepathto match usage in the implementation
4. All Switch Statements Updated:
- Updated all switch statements to use correct enum values
- Fixed all references to use
ImageFormat::JPEGinstead of non-existentImageFormat::JPG
5. Header File Structure:
- Kept only declarations in the header
- All implementations moved to .cpp file
- Proper forward declarations for all functions used
The corrected files should now compile without the enumeration and function redefinition errors you were encountering. The key was ensuring consistency between the header declarations and implementation file, and making sure all enum values referenced in the code actually exist in their respective enum classes.
Retry
Claude can make mistakes. Please double-check responses.
Sonnet 4
v2∙Latest
Copy
Publish
#include "PCH.h" #include "ScreenCapture.h" #include "logger.h" using Microsoft::WRL::ComPtr; namespace fs = std::filesystem; namespace ScreenCapture { // RAII COM initializer class COMInitializer { public: COMInitializer() : initialized_(false) { if (SUCCEEDED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED))) { initialized_ = true; } } ~COMInitializer() { if (initialized_) { CoUninitialize(); } } bool IsInitialized() const { return initialized_; } private: bool initialized_; }; // Utility: convert string to upper-case static std::string ToUpper(std::string s) { std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::toupper(c); }); return s; } // --- Format / parameter parsing --- ImageFormat StringToImageFormat(const std::string& formatStr) { auto fmt = ToUpper(formatStr); if (fmt == "PNG") return ImageFormat::PNG; if (fmt == "JPG" || fmt == "JPEG") return ImageFormat::JPEG; if (fmt == "BMP") return ImageFormat::BMP; if (fmt == "TIF" || fmt == "TIFF") return ImageFormat::TIF; if (fmt == "DDS") return ImageFormat::DDS; if (fmt == "GIF") return ImageFormat::GIF; // Handle legacy GIF_MULTIFRAME references if (fmt == "GIF_MULTIFRAME" || fmt == "GIF_MULTI") return ImageFormat::GIF; // fallback return ImageFormat::PNG; } DDSCompression StringToDDSCompression(const std::string& compStr) { auto s = ToUpper(compStr); if (s == "BC1") return DDSCompression::BC1; if (s == "BC2") return DDSCompression::BC2; if (s == "BC3") return DDSCompression::BC3; if (s == "BC4") return DDSCompression::BC4; if (s == "BC5") return DDSCompression::BC5; if (s == "BC6H" || s == "BC6_H") return DDSCompression::BC6H; if (s == "BC7_SLOW" || s == "BC7SLOW") return DDSCompression::BC7_SLOW; if (s == "BC7_NORMAL" || s == "BC7NORMAL" || s == "BC7") return DDSCompression::BC7_NORMAL; if (s == "BC7_FAST" || s == "BC7FAST") return DDSCompression::BC7_FAST; return DDSCompression::BC1; } TiffMode StringToTiffCompression(const std::string& compStr) { auto s = ToUpper(compStr); if (s == "NONE") return TiffMode::NONE; if (s == "LZW") return TiffMode::LZW; if (s == "CCITT3" || s == "CCITT_1D") return TiffMode::CCITT1D; if (s == "CCITT4") return TiffMode::CCITT4; if (s == "RLE") return TiffMode::RLE; return TiffMode::LZW; } // --- DDS Format and Compression Helpers --- DXGI_FORMAT GetDXGIFormat(DDSCompression compression) { switch (compression) { case DDSCompression::BC1: return DXGI_FORMAT_BC1_UNORM; case DDSCompression::BC2: return DXGI_FORMAT_BC2_UNORM; case DDSCompression::BC3: return DXGI_FORMAT_BC3_UNORM; case DDSCompression::BC4: return DXGI_FORMAT_BC4_UNORM; case DDSCompression::BC5: return DXGI_FORMAT_BC5_UNORM; case DDSCompression::BC6H: return DXGI_FORMAT_BC6H_UF16; case DDSCompression::BC7_SLOW: case DDSCompression::BC7_NORMAL: case DDSCompression::BC7_FAST: return DXGI_FORMAT_BC7_UNORM; default: return DXGI_FORMAT_BC1_UNORM; } } DirectX::TEX_COMPRESS_FLAGS GetCompressionFlags(DDSCompression compression) { switch (compression) { case DDSCompression::BC7_SLOW: return DirectX::TEX_COMPRESS_BC7_USE_3SUBSETS | DirectX::TEX_COMPRESS_PARALLEL; case DDSCompression::BC7_NORMAL: return DirectX::TEX_COMPRESS_PARALLEL; case DDSCompression::BC7_FAST: return DirectX::TEX_COMPRESS_BC7_QUICK | DirectX::TEX_COMPRESS_PARALLEL; case DDSCompression::BC6H: return DirectX::TEX_COMPRESS_PARALLEL; default: return DirectX::TEX_COMPRESS_DEFAULT; } } bool RequiresMultiThreading(DDSCompression compression) { switch (compression) { case DDSCompression::BC6H: case DDSCompression::BC7_SLOW: case DDSCompression::BC7_NORMAL: case DDSCompression::BC7_FAST: return true; default: return false; } } // --- WIC codec selection --- GUID GetWICCodec(ImageFormat format) { switch (format) { case ImageFormat::PNG: return GUID_ContainerFormatPng; case ImageFormat::JPEG: return GUID_ContainerFormatJpeg; case ImageFormat::BMP: return GUID_ContainerFormatBmp; case ImageFormat::TIF: return GUID_ContainerFormatTiff; case ImageFormat::DDS: return GUID_ContainerFormatDds; case ImageFormat::GIF: return GUID_ContainerFormatGif; default: return GUID_ContainerFormatPng; } } // --- Filename generator --- std::wstring GenerateFilename(const std::wstring& basePath, ImageFormat format) { // timestamp YYYYMMDD_HHMMSS auto now = std::chrono::system_clock::now(); std::time_t t = std::chrono::system_clock::to_time_t(now); std::tm tm; localtime_s(&tm, &t); wchar_t buf[32]; wcsftime(buf, 32, L"%Y%m%d_%H%M%S", &tm); // extension std::wstring ext; switch (format) { case ImageFormat::PNG: ext = L".png"; break; case ImageFormat::JPEG: ext = L".jpg"; break; case ImageFormat::BMP: ext = L".bmp"; break; case ImageFormat::TIF: ext = L".tif"; break; case ImageFormat::DDS: ext = L".dds"; break; case ImageFormat::GIF: ext = L".gif"; break; default: ext = L".png"; break; } fs::path p = basePath; p /= std::wstring(L"Screenshot_") + buf + ext; return p.wstring(); } // --- Pixel buffer conversion --- void ConvertRGBAToBGRA(const DirectX::Image* img, uint8_t* dest) { if (!img || !dest) return; const uint8_t* src = img->pixels; size_t count = img->width * img->height; for (size_t i = 0; i < count; ++i) { dest[i*4 + 0] = src[i*4 + 2]; // B dest[i*4 + 1] = src[i*4 + 1]; // G dest[i*4 + 2] = src[i*4 + 0]; // R dest[i*4 + 3] = src[i*4 + 3]; // A } } // --- Desktop duplication setup --- HRESULT SetupDesktopDuplication( ComPtr<ID3D11Device>& device, ComPtr<ID3D11DeviceContext>& context, ComPtr<IDXGIOutputDuplication>& duplication) { // Create D3D11 device + context HRESULT hr = D3D11CreateDevice( nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, nullptr, 0, D3D11_SDK_VERSION, device.GetAddressOf(), nullptr, context.GetAddressOf() ); if (FAILED(hr)) { logger::error("Failed to create D3D11 device: 0x{:x}", static_cast<unsigned>(hr)); return hr; } // QI for DXGI ComPtr<IDXGIDevice> dxgiDevice; hr = device.As(&dxgiDevice); if (FAILED(hr)) { logger::error("Failed to get DXGI device: 0x{:x}", static_cast<unsigned>(hr)); return hr; } ComPtr<IDXGIAdapter> adapter; hr = dxgiDevice->GetAdapter(&adapter); if (FAILED(hr)) { logger::error("Failed to get DXGI adapter: 0x{:x}", static_cast<unsigned>(hr)); return hr; } ComPtr<IDXGIOutput> output; hr = adapter->EnumOutputs(0, &output); if (FAILED(hr)) { logger::error("Failed to enumerate outputs: 0x{:x}", static_cast<unsigned>(hr)); return hr; } ComPtr<IDXGIOutput1> output1; hr = output.As(&output1); if (FAILED(hr)) { logger::error("Failed to get IDXGIOutput1: 0x{:x}", static_cast<unsigned>(hr)); return hr; } hr = output1->DuplicateOutput(device.Get(), duplication.GetAddressOf()); if (FAILED(hr)) { logger::error("Failed to duplicate output: 0x{:x}", static_cast<unsigned>(hr)); } return hr; } // --- Single frame capture via desktop duplication --- HRESULT CaptureSingleFrame( ID3D11Device* pDevice, ID3D11DeviceContext* pContext, IDXGIOutputDuplication* pDuplication, DirectX::ScratchImage& outImage) { if (!pDuplication || !pContext || !pDevice) { logger::error("Invalid parameters for CaptureSingleFrame"); return E_INVALIDARG; } DXGI_OUTDUPL_FRAME_INFO frameInfo; ComPtr<IDXGIResource> desktopRes; // Try to acquire frame with timeout HRESULT hr = pDuplication->AcquireNextFrame(1000, &frameInfo, &desktopRes); if (FAILED(hr)) { if (hr != DXGI_ERROR_WAIT_TIMEOUT) { logger::warn("Failed to acquire frame: 0x{:x}", static_cast<unsigned>(hr)); } return hr; } // Ensure we have frame updates if (frameInfo.LastPresentTime.QuadPart == 0) { pDuplication->ReleaseFrame(); return DXGI_ERROR_WAIT_TIMEOUT; } ComPtr<ID3D11Texture2D> frameTex; hr = desktopRes.As(&frameTex); if (SUCCEEDED(hr)) { // Create a staging texture for CPU access D3D11_TEXTURE2D_DESC desc; frameTex->GetDesc(&desc); desc.Usage = D3D11_USAGE_STAGING; desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; desc.BindFlags = 0; desc.MiscFlags = 0; ComPtr<ID3D11Texture2D> stagingTex; hr = pDevice->CreateTexture2D(&desc, nullptr, &stagingTex); if (SUCCEEDED(hr)) { // Copy frame to staging texture pContext->CopyResource(stagingTex.Get(), frameTex.Get()); // Capture from staging texture using DirectXTex hr = DirectX::CaptureTexture(pDevice, pContext, stagingTex.Get(), outImage); if (FAILED(hr)) { logger::error("Failed to capture texture: 0x{:x}", static_cast<unsigned>(hr)); } } else { logger::error("Failed to create staging texture: 0x{:x}", static_cast<unsigned>(hr)); } } else { logger::error("Failed to get texture from resource: 0x{:x}", static_cast<unsigned>(hr)); } pDuplication->ReleaseFrame(); return hr; } // -------------------------------------------------- // Main entrypoint // -------------------------------------------------- CaptureResult CaptureScreen(const CaptureParams& params) { CaptureResult result; try { logger::info("Starting screen capture - Format: {}, Duration: {}s", static_cast<int>(params.format), params.gifDuration); if (params.format == ImageFormat::GIF && params.gifDuration > 0.0f) { return GIF(params); } COMInitializer comInit; if (!comInit.IsInitialized()) { result.message = "Failed to initialize COM"; logger::error(result.message); return result; } // Setup desktop duplication ComPtr<ID3D11Device> device; ComPtr<ID3D11DeviceContext> context; ComPtr<IDXGIOutputDuplication> duplication; HRESULT hr = SetupDesktopDuplication(device, context, duplication); if (FAILED(hr)) { result.message = "Failed to setup desktop duplication. HRESULT: 0x" + std::to_string(static_cast<unsigned>(hr)); logger::error(result.message); return result; } // Capture single frame DirectX::ScratchImage capture; hr = CaptureSingleFrame(device.Get(), context.Get(), duplication.Get(), capture); if (FAILED(hr)) { result.message = "Failed to capture frame. HRESULT: 0x" + std::to_string(static_cast<unsigned>(hr)); logger::error(result.message); return result; } // Generate filename and save result.filepath = GenerateFilename(params.basePath, params.format); if (params.format == ImageFormat::DDS) { hr = SaveToDDSFile(capture, params, result.filepath); } else { hr = SaveToWICFile(capture, params, result.filepath); } result.success = SUCCEEDED(hr); if (result.success) { result.message = "Screenshot saved successfully to: " + std::string(result.filepath.begin(), result.filepath.end()); logger::info(result.message); } else { result.message = "Failed to save file. HRESULT: 0x" + std::to_string(static_cast<unsigned>(hr)); logger::error(result.message); } } catch (const std::exception& e) { result.success = false; result.message = std::string("Exception: ") + e.what(); logger::error(result.message); } return result; } // -------------------------------------------------- // Single-frame WIC save (PNG, JPG, BMP, TIF, GIF) // -------------------------------------------------- HRESULT SaveToWICFile( const DirectX::ScratchImage& image, const CaptureParams& params, const std::wstring& filepath) { // Validate input const DirectX::Image* img = image.GetImage(0, 0, 0); if (!img) { logger::error("No image data to save"); return E_FAIL; } // Verify we have a supported input format if (img->format != DXGI_FORMAT_R8G8B8A8_UNORM && img->format != DXGI_FORMAT_B8G8R8A8_UNORM) { logger::error("Unsupported image format for WIC save: {}", static_cast<int>(img->format)); return E_INVALIDARG; } // Initialize WIC ComPtr<IWICImagingFactory> wicFactory; HRESULT hr = CoCreateInstance( CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&wicFactory) ); if (FAILED(hr)) { logger::error("Failed to create WIC factory: 0x{:x}", static_cast<unsigned>(hr)); return hr; } // Create encoder for chosen format ComPtr<IWICBitmapEncoder> encoder; GUID container = GetWICCodec(params.format); hr = wicFactory->CreateEncoder(container, nullptr, &encoder); if (FAILED(hr)) { logger::error("Failed to create encoder: 0x{:x}", static_cast<unsigned>(hr)); return hr; } // Create output stream ComPtr<IWICStream> stream; hr = wicFactory->CreateStream(&stream); if (FAILED(hr)) { logger::error("Failed to create stream: 0x{:x}", static_cast<unsigned>(hr)); return hr; } hr = stream->InitializeFromFilename(filepath.c_str(), GENERIC_WRITE); if (FAILED(hr)) { logger::error("Failed to initialize stream: 0x{:x}", static_cast<unsigned>(hr)); return hr; } hr = encoder->Initialize(stream.Get(), WICBitmapEncoderNoCache); if (FAILED(hr)) { logger::error("Failed to initialize encoder: 0x{:x}", static_cast<unsigned>(hr)); return hr; } // For single-frame GIF, set logical screen background color index = 0 if (params.format == ImageFormat::GIF) { ComPtr<IWICMetadataQueryWriter> meta; if (SUCCEEDED(encoder->GetMetadataQueryWriter(&meta))) { PROPVARIANT pv; PropVariantInit(&pv); pv.vt = VT_UI1; pv.bVal = 0; meta->SetMetadataByName(L"/logscrdesc/BackgroundColorIndex", &pv); PropVariantClear(&pv); } } // Create frame ComPtr<IWICBitmapFrameEncode> frame; ComPtr<IPropertyBag2> props; hr = encoder->CreateNewFrame(&frame, &props); if (FAILED(hr)) { logger::error("Failed to create frame: 0x{:x}", static_cast<unsigned>(hr)); return hr; } // Set format-specific properties if (params.format == ImageFormat::JPEG && props) { PROPBAG2 bag = {}; bag.pstrName = const_cast<LPOLESTR>(L"ImageQuality"); VARIANT var; VariantInit(&var); var.vt = VT_R4; var.fltVal = std::max(0.1f, std::min(1.0f, params.jpegQuality / 100.0f)); props->Write(1, &bag, &var); VariantClear(&var); } else if (params.format == ImageFormat::TIF && props) { PROPBAG2 bag = {}; bag.pstrName = const_cast<LPOLESTR>(L"TiffCompressionMethod"); VARIANT var; VariantInit(&var); var.vt = VT_UI1; var.bVal = static_cast<BYTE>(params.tiffMode); props->Write(1, &bag, &var); VariantClear(&var); } hr = frame->Initialize(props.Get()); if (FAILED(hr)) { logger::error("Failed to initialize frame: 0x{:x}", static_cast<unsigned>(hr)); return hr; } UINT width = static_cast<UINT>(img->width); UINT height = static_cast<UINT>(img->height); hr = frame->SetSize(width, height); if (FAILED(hr)) { logger::error("Failed to set frame size: 0x{:x}", static_cast<unsigned>(hr)); return hr; } // Handle GIF differently: must be 8-bit indexed if (params.format == ImageFormat::GIF) { // 1) Convert to BGRA if needed size_t size = width * height * 4; std::vector<uint8_t> bgra(size); if (img->format == DXGI_FORMAT_R8G8B8A8_UNORM) { ConvertRGBAToBGRA(img, bgra.data()); } else { // Already BGRA memcpy(bgra.data(), img->pixels, size); } // 2) Wrap in WICBitmap ComPtr<IWICBitmap> bmp; hr = wicFactory->CreateBitmapFromMemory( width, height, GUID_WICPixelFormat32bppBGRA, width * 4, static_cast<UINT>(size), bgra.data(), &bmp ); if (FAILED(hr)) { logger::error("Failed to create bitmap from memory: 0x{:x}", static_cast<unsigned>(hr)); return hr; } // 3) Convert to 8bpp indexed with better quality settings ComPtr<IWICFormatConverter> conv; hr = wicFactory->CreateFormatConverter(&conv); if (FAILED(hr)) { logger::error("Failed to create format converter: 0x{:x}", static_cast<unsigned>(hr)); return hr; } hr = conv->Initialize( bmp.Get(), GUID_WICPixelFormat8bppIndexed, WICBitmapDitherTypeOrdered8x8, nullptr, 0.0, WICBitmapPaletteTypeMedianCut ); if (FAILED(hr)) { logger::error("Failed to initialize format converter: 0x{:x}", static_cast<unsigned>(hr)); return hr; } // 4) Tell frame that it's 8-bit indexed WICPixelFormatGUID pf = GUID_WICPixelFormat8bppIndexed; hr = frame->SetPixelFormat(&pf); if (FAILED(hr)) { logger::error("Failed to set pixel format: 0x{:x}", static_cast<unsigned>(hr)); return hr; } // 5) Push through the converter hr = frame->WriteSource(conv.Get(), nullptr); if (FAILED(hr)) { logger::error("Failed to write source: 0x{:x}", static_cast<unsigned>(hr)); return hr; } } else { // All other formats: write pixels directly WICPixelFormatGUID pf = GUID_WICPixelFormat32bppBGRA; hr = frame->SetPixelFormat(&pf); if (FAILED(hr)) { logger::error("Failed to set pixel format: 0x{:x}", static_cast<unsigned>(hr)); return hr; } // Convert RGBA → BGRA if needed if (img->format == DXGI_FORMAT_R8G8B8A8_UNORM) { size_t size = width * height * 4; std::vector<uint8_t> bgra(size); ConvertRGBAToBGRA(img, bgra.data()); hr = frame->WritePixels( height, width * 4, static_cast<UINT>(size), bgra.data() ); } else { // Already in correct format hr = frame->WritePixels( height, static_cast<UINT>(img->rowPitch), static_cast<UINT>(img->slicePitch), img->pixels ); } if (FAILED(hr)) { logger::error("Failed to write pixels: 0x{:x}", static_cast<unsigned>(hr)); return hr; } } hr = frame->Commit(); if (FAILED(hr)) { logger::error("Failed to commit frame: 0x{:x}", static_cast<unsigned>(hr)); return hr; } hr = encoder->Commit(); if (FAILED(hr)) { logger::error("Failed to commit encoder: 0x{:x}", static_cast<unsigned>(hr)); } return hr; } // -------------------------------------------------- // DDS save with multi-threaded compression // -------------------------------------------------- HRESULT SaveToDDSFile( const DirectX::ScratchImage& image, const CaptureParams& params, const std::wstring& filepath) { // Validate input const DirectX::Image* img = image.GetImage(0, 0, 0); if (!img) { logger::error("No image data for DDS save"); return E_FAIL; } // Verify we have a supported input format if (img->format != DXGI_FORMAT_R8G8B8A8_UNORM && img->format != DXGI_FORMAT_B8G8R8A8_UNORM) { logger::error("Unsupported image format for DDS save: {}", static_cast<int>(img->format)); return E_INVALIDARG; } DXGI_FORMAT targetFormat = GetDXGIFormat(params.ddsMode); DirectX::TEX_COMPRESS_FLAGS flags = GetCompressionFlags(params.ddsMode); // Set up multi-threading for supported formats if (RequiresMultiThreading(params.ddsMode)) { unsigned int threadCount = std::max(1u, std::thread::hardware_concurrency()); logger::info("Using {} threads for DDS compression", threadCount); } try { DirectX::ScratchImage compressed; // Convert input format if needed (BC6H requires different handling) if (params.ddsMode == DDSCompression::BC6H) { // BC6H requires HDR format input - convert from SDR DirectX::ScratchImage hdrImage; HRESULT hr = DirectX::Convert( *img, DXGI_FORMAT_R16G16B16A16_FLOAT, DirectX::TEX_FILTER_DEFAULT, DirectX::TEX_THRESHOLD_DEFAULT, hdrImage ); if (FAILED(hr)) { logger::error("Failed to convert to HDR format: 0x{:x}", static_cast<unsigned>(hr)); return hr; } // Compress HDR image hr = DirectX::Compress( hdrImage.GetImages(), hdrImage.GetImageCount(), hdrImage.GetMetadata(), targetFormat, flags, DirectX::TEX_THRESHOLD_DEFAULT, compressed ); if (FAILED(hr)) { logger::error("Failed to compress HDR texture: 0x{:x}", static_cast<unsigned>(hr)); return hr; } } else { // Standard compression for BC1-BC5, BC7 DirectX::TexMetadata metadata; metadata.width = img->width; metadata.height = img->height; metadata.depth = 1; metadata.arraySize = 1; metadata.mipLevels = 1; metadata.miscFlags = 0; metadata.miscFlags2 = 0; metadata.format = img->format; metadata.dimension = DirectX::TEX_DIMENSION_TEXTURE2D; HRESULT hr = DirectX::Compress( img, 1, metadata, targetFormat, flags, DirectX::TEX_THRESHOLD_DEFAULT, compressed ); if (FAILED(hr)) { logger::error("Failed to compress texture: 0x{:x}", static_cast<unsigned>(hr)); return hr; } } // Save to file HRESULT hr = DirectX::SaveToDDSFile( compressed.GetImages(), compressed.GetImageCount(), compressed.GetMetadata(), DirectX::DDS_FLAGS_NONE, filepath.c_str() ); if (FAILED(hr)) { logger::error("Failed to save DDS file: 0x{:x}", static_cast<unsigned>(hr)); return hr; } logger::info("DDS file saved successfully"); return S_OK; } catch (const std::exception& e) { logger::error("DDS compression failed: {}", e.what()); return E_FAIL; } } // -------------------------------------------------- // Multi-frame (animated) GIF capture // -------------------------------------------------- CaptureResult GIF(const CaptureParams& params) { CaptureResult result; try { logger::info("Starting multi-frame GIF: {}s @10FPS", params.gifDuration); COMInitializer comInit; if (!comInit.IsInitialized()) { result.message = "Failed to initialize COM for GIF"; logger::error(result.message); return result; } // WIC factory & stream ComPtr<IWICImagingFactory> wicFactory; HRESULT hr = CoCreateInstance( CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&wicFactory) ); if (FAILED(hr)) { result.message = "Failed to create WIC factory for GIF"; logger::error(result.message); return result; } result.filepath = GenerateFilename(params.basePath, params.format); ComPtr<IWICStream> stream; hr = wicFactory->CreateStream(&stream); if (FAILED(hr)) { result.message = "Failed to create WIC stream for GIF"; logger::error(result.message); return result; } hr = stream->InitializeFromFilename(result.filepath.c_str(), GENERIC_WRITE); if (FAILED(hr)) { result.message = "Failed to initialize GIF stream"; logger::error(result.message); return result; } // GIF encoder ComPtr<IWICBitmapEncoder> encoder; hr = wicFactory->CreateEncoder(GUID_ContainerFormatGif, nullptr, &encoder); if (FAILED(hr)) { result.message = "Failed to create GIF encoder"; logger::error(result.message); return result; } hr = encoder->Initialize(stream.Get(), WICBitmapEncoderNoCache); if (FAILED(hr)) { result.message = "Failed to initialize GIF encoder"; logger::error(result.message); return result; } // Set infinite loop extension ComPtr<IWICMetadataQueryWriter> meta; if (SUCCEEDED(encoder->GetMetadataQueryWriter(&meta))) { // Application extension for infinite loop PROPVARIANT pv; PropVariantInit(&pv); // Set application identifier const char* appId = "NETSCAPE2.0"; pv.vt = VT_UI1 | VT_VECTOR; pv.caub.cElems = static_cast<ULONG>(strlen(appId)); pv.caub.pElems = reinterpret_cast<BYTE*>(const_cast<char*>(appId)); meta->SetMetadataByName(L"/appext/Application", &pv); PropVariantClear(&pv); // Set loop data (0x00, 0x00 = infinite loop) BYTE loopData[] = { 0x01, 0x00, 0x00 }; PropVariantInit(&pv); pv.vt = VT_UI1 | VT_VECTOR; pv.caub.cElems = sizeof(loopData); pv.caub.pElems = loopData; meta->SetMetadataByName(L"/appext/Data", &pv); PropVariantClear(&pv); } // Desktop duplication setup ComPtr<ID3D11Device> device; ComPtr<ID3D11DeviceContext> context; ComPtr<IDXGIOutputDuplication> duplication; HRESULT setupHr = SetupDesktopDuplication(device, context, duplication); if (FAILED(setupHr)) { result.message = "Failed to setup desktop duplication for GIF"; logger::error(result.message); return result; } // Timing calculations const float fps = 10.0f; const int totalFrames = static_cast<int>(std::ceil(params.gifDuration * fps)); const int delayCs = std::max(1, static_cast<int>(std::round((1.0f / fps) * 100.0f))); int successCount = 0; auto startTime = std::chrono::steady_clock::now(); for (int i = 0; i < totalFrames; ++i) { // Check for cancellation if (params.cancelFlag && params.cancelFlag->load()) { logger::info("GIF capture cancelled at frame {}", i); break; } // Capture frame DirectX::ScratchImage imgScratch; HRESULT capHr = CaptureSingleFrame( device.Get(), context.Get(), duplication.Get(), imgScratch ); if (FAILED(capHr)) { logger::warn("Skip frame {} (HRESULT: 0x{:x})", i, static_cast<unsigned>(capHr)); continue; } auto img = imgScratch.GetImage(0, 0, 0); if (!img) { logger::warn("No image data for frame {}", i); continue; } // Create frame encode ComPtr<IWICBitmapFrameEncode> frame; ComPtr<IPropertyBag2> frameProps; if (FAILED(encoder->CreateNewFrame(&frame, &frameProps))) { logger::warn("Failed to create frame {}", i); continue; } // Set per-frame delay if (frameProps) { PROPBAG2 bag = {}; bag.pstrName = const_cast<LPOLESTR>(L"Delay"); VARIANT var; VariantInit(&var); var.vt = VT_UI2; var.uiVal = static_cast<USHORT>(delayCs); frameProps->Write(1, &bag, &var); VariantClear(&var); } if (FAILED(frame->Initialize(frameProps.Get()))) { logger::warn("Failed to initialize frame {}", i); continue; } if (FAILED(frame->SetSize(static_cast<UINT>(img->width), static_cast<UINT>(img->height)))) { logger::warn("Failed to set frame size for frame {}", i); continue; } // Convert RGBA → BGRA if needed size_t sz = img->width * img->height * 4; std::vector<uint8_t> bgra(sz); if (img->format == DXGI_FORMAT_R8G8B8A8_UNORM) { ConvertRGBAToBGRA(img, bgra.data()); } else { memcpy(bgra.data(), img->pixels, sz); } // Wrap BGRA in WICBitmap ComPtr<IWICBitmap> bmp; if (FAILED(wicFactory->CreateBitmapFromMemory( static_cast<UINT>(img->width), static_cast<UINT>(img->height), GUID_WICPixelFormat32bppBGRA, static_cast<UINT>(img->width * 4), static_cast<UINT>(sz), bgra.data(), &bmp))) { logger::warn("Failed to create bitmap for frame {}", i); continue; } // Convert to 8bpp indexed ComPtr<IWICFormatConverter> conv; if (FAILED(wicFactory->CreateFormatConverter(&conv))) { logger::warn("Failed to create format converter for frame {}", i); continue; } if (FAILED(conv->Initialize( bmp.Get(), GUID_WICPixelFormat8bppIndexed, WICBitmapDitherTypeOrdered8x8, nullptr, 0.0, WICBitmapPaletteTypeMedianCut ))) { logger::warn("Failed to initialize converter for frame {}", i); continue; } // Set frame pixel format WICPixelFormatGUID pf = GUID_WICPixelFormat8bppIndexed; if (FAILED(frame->SetPixelFormat(&pf))) { logger::warn("Failed to set pixel format for frame {}", i); continue; } // Write source (palette + pixels) if (FAILED(frame->WriteSource(conv.Get(), nullptr))) { logger::warn("Failed to write source for frame {}", i); continue; } if (FAILED(frame->Commit())) { logger::warn("Failed to commit frame {}", i); continue; } ++successCount; // Maintain timing auto expectedTime = startTime + std::chrono::milliseconds(static_cast<long long>((i + 1) * 1000 / fps)); auto now = std::chrono::steady_clock::now(); if (expectedTime > now) { std::this_thread::sleep_for(expectedTime - now); } } // Finalize HRESULT commitHr = encoder->Commit(); result.success = SUCCEEDED(commitHr) && successCount > 0; if (result.success) { result.message = "Animated GIF saved with " + std::to_string(successCount) + " frames"; logger::info(result.message); } else { result.message = "Failed to create GIF. Frames captured: " + std::to_string(successCount); logger::error(result.message); } } catch (const std::exception& e) { result.success = false; result.message = std::string("GIF Exception: ") + e.what(); logger::error("GIF exception: {}", e.what()); } return result; } } // namespace ScreenCapture