Как можно получить нужное значение в разных версиях Windows?

Привет! Приведенный ниже код позволяет удобно получать и группировать значения для работы приложения в разных версиях Windows: 

```cpp
#include <iostream>
#include <cstdint>

namespace Offsets {
    namespace W1709 {
        struct FirstStruct {
            static constexpr std::uintptr_t somefield = 0x0;
            static constexpr std::uintptr_t someOtherField = 0x8;
        };
        struct AnotherStruct {
            static constexpr std::uintptr_t somefield = 0x4;
        };
    }

    namespace W22h2 {
        struct FirstStruct {
            static constexpr std::uintptr_t somefield = 0x10;
            static constexpr std::uintptr_t someOtherField = 0x18;
        };
        struct AnotherStruct {
            static constexpr std::uintptr_t somefield = 0x14;
        };
    }
}

int main() {
    using namespace Offsets;

    // Прямой доступ к смещениям по конкретной версии и категории структуры
    std::cout << "W1709 FirstStruct::somefield offset: 0x"
        << std::hex << W1709::FirstStruct::somefield << std::endl;

    std::cout << "W22h2 FirstStruct::SomeOtherField offset: 0x"
        << std::hex << W22h2::FirstStruct::someOtherField << std::endl;

    std::cout << "W1709 AnotherStruct::someOtherField offset: 0x"
        << std::hex << W1709::AnotherStruct::somefield << std::endl;

    return 0;
}
```

Однако у данного подхода есть один недостаток: он работает только на этапе компиляции, что делает невозможным использование динамического указания версии Windows, например, таким образом:

```cpp
std::string winVer = "W22h2";
std::cout << std::hex << winVer::AnotherStruct::somefield << std::endl;
```

Как можно обойти это ограничение?
  • 31 октября 2024 г. 16:33
Ответы на вопрос 2
К сожалению, в C++ нельзя динамически выбирать атрибуты структуры на этапе выполнения, поскольку все пространства имен и структуры компилируются на этапе компиляции. Однако вы можете использовать различные подходы, чтобы достичь похожего результата. Один из самых распространенных способов — использовать динамическое связывание и полиморфизм. 

Вот один из возможных подходов с использованием классов и указателей или ссылок:

1. Определите абстрактный базовый класс с виртуальными функциями, которые будут возвращать нужные смещения. 
2. Создайте производные классы для разных версий Windows, переопределяющие функции базового класса.

```cpp
#include <iostream>
#include <memory>
#include <string>

class OffsetsBase {
public:
    virtual ~OffsetsBase() = default;

    virtual std::uintptr_t getFirstStructSomeField() const = 0;
    virtual std::uintptr_t getFirstStructSomeOtherField() const = 0;
    virtual std::uintptr_t getAnotherStructSomeField() const = 0;
};

class OffsetsW1709 : public OffsetsBase {
public:
    std::uintptr_t getFirstStructSomeField() const override {
        return 0x0;
    }
    
    std::uintptr_t getFirstStructSomeOtherField() const override {
        return 0x8;
    }

    std::uintptr_t getAnotherStructSomeField() const override {
        return 0x4;
    }
};

class OffsetsW22h2 : public OffsetsBase {
public:
    std::uintptr_t getFirstStructSomeField() const override {
        return 0x10;
    }
    
    std::uintptr_t getFirstStructSomeOtherField() const override {
        return 0x18;
    }

    std::uintptr_t getAnotherStructSomeField() const override {
        return 0x14;
    }
};

std::unique_ptr<OffsetsBase> createOffsets(const std::string& version) {
    if (version == "W1709") {
        return std::make_unique<OffsetsW1709>();
    } else if (version == "W22h2") {
        return std::make_unique<OffsetsW22h2>();
    }

    return nullptr; // Обработка для незнакомой версии
}

int main() {
    std::string winVer = "W22h2"; // Замените это значение для другого теста
    auto offsets = createOffsets(winVer);

    if (offsets) {
        std::cout << "Offsets for version " << winVer << ":" << std::endl;
        std::cout << "FirstStruct::somefield offset: 0x" 
                  << std::hex << offsets->getFirstStructSomeField() << std::endl;
        std::cout << "FirstStruct::someOtherField offset: 0x" 
                  << std::hex << offsets->getFirstStructSomeOtherField() << std::endl;
        std::cout << "AnotherStruct::somefield offset: 0x" 
                  << std::hex << offsets->getAnotherStructSomeField() << std::endl;
    } else {
        std::cout << "Unknown Windows version!" << std::endl;
    }

    return 0;
}
```

### Объяснение кода:
1. **Абстрактный класс** `OffsetsBase` объявляет виртуальные методы для получения смещений.
2. **Производные классы** `OffsetsW1709` и `OffsetsW22h2` реализуют методы, возвращающие конкретные смещения для каждой версии Windows.
3. **Функция `createOffsets`** принимает строку, определяющую версию Windows, и возвращает указатель на соответствующий экземпляр (или nullptr, если версия неизвестна).
4. В `main` вы можете выбрать нужную версию Windows и получить соответствующие значения через виртуальные методы.

Этот подход обеспечивает гибкость и позволяет динамически определять смещения в зависимости от версии Windows.
Заведите, например enum со всеми версиями виндоуз и занумеруйте их. Смещения ваши раскладывайте не по неймспейсам, а массиве. Во время исполнения через winapi получайте версию винды и приводите ее к значению в вашем энуме. Его используйте как индекс в массиве.
Похожие вопросы