Login Page - Create Account

Support Board


Date/Time: Sat, 18 Jan 2025 00:38:51 +0000



Post From: Sierra ARM64 version lag and extra x64 log messages on SierraChart_ARM64.exe

[2025-01-17 18:37:34]
User719512 - Posts: 287
This message is to add clarity around reading the "source of truth" for determining the machine type rather than relying on the file name.
I am certain the Sierra Engineering team know all this, so this post is aimed at the aspiring developers who were curious about reading machine information from a dll (or exe).

This is a POC (proof of concept) demo app that shows machine information for dll or exe files. Could also be refactored into a library of course for other usage.


#include <windows.h>
#include <filesystem>
#include <iostream>
#include <regex>
#include <string>
#include <vector>

namespace fs = std::filesystem;

bool GetDLLArchitecture(const std::wstring& dllPath, WORD& machineType) {
HANDLE file = CreateFile(dllPath.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
if (file == INVALID_HANDLE_VALUE) {
std::wcerr << L"Failed to open file: " << dllPath << std::endl;
return false;
}

// Read the DOS header
IMAGE_DOS_HEADER dosHeader;
DWORD bytesRead;
if (!ReadFile(file, &dosHeader, sizeof(dosHeader), &bytesRead, nullptr) || bytesRead != sizeof(dosHeader)) {
std::wcerr << L"Failed to read DOS header from: " << dllPath << std::endl;
CloseHandle(file);
return false;
}

if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE) {
std::wcerr << L"Invalid DOS signature in: " << dllPath << std::endl;
CloseHandle(file);
return false;
}

if (SetFilePointer(file, dosHeader.e_lfanew, nullptr, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
std::wcerr << L"Failed to seek to PE header in: " << dllPath << std::endl;
CloseHandle(file);
return false;
}

DWORD peSignature;
if (!ReadFile(file, &peSignature, sizeof(peSignature), &bytesRead, nullptr) || bytesRead != sizeof(peSignature)) {
std::wcerr << L"Failed to read PE signature from: " << dllPath << std::endl;
CloseHandle(file);
return false;
}

if (peSignature != IMAGE_NT_SIGNATURE) {
std::wcerr << L"Invalid PE signature in: " << dllPath << std::endl;
CloseHandle(file);
return false;
}

IMAGE_FILE_HEADER fileHeader;
if (!ReadFile(file, &fileHeader, sizeof(fileHeader), &bytesRead, nullptr) || bytesRead != sizeof(fileHeader)) {
std::wcerr << L"Failed to read File Header from: " << dllPath << std::endl;
CloseHandle(file);
return false;
}

machineType = fileHeader.Machine;
CloseHandle(file);
return true;
}

std::wstring GetArchitectureName(WORD machineType) {
switch (machineType) {
case IMAGE_FILE_MACHINE_ARM64: return L"ARM64";
case IMAGE_FILE_MACHINE_AMD64: return L"x64";
case IMAGE_FILE_MACHINE_I386: return L"x86";
default: return L"Unknown";
}
}

void ProcessDLL(const std::wstring& dllPath) {
WORD machineType;
if (GetDLLArchitecture(dllPath, machineType)) {
std::wcout << L"Architecture of " << dllPath << L": " << GetArchitectureName(machineType) << std::endl;
}
else {
std::wcerr << L"Failed to determine architecture of: " << dllPath << std::endl;
}
}

void ProcessDirectory(const std::wstring& directory, const std::wstring& pattern = L"*.dll") {
std::wregex regex;
bool useRegex = false;

// Convert wildcard pattern to a regex if it contains '*'
if (pattern.find(L'*') != std::wstring::npos) {
std::wstring regexPattern = std::regex_replace(pattern, std::wregex(L"\\*"), L".*");
regex.assign(regexPattern, std::regex_constants::icase);
useRegex = true;
}

// Iterate over files in the directory
for (const auto& entry : fs::directory_iterator(directory)) {
if (entry.is_regular_file()) {
const auto& path = entry.path();
const std::wstring filename = path.filename().wstring();

// Match filename with the wildcard pattern
if (useRegex) {
if (std::regex_match(filename, regex)) {
ProcessDLL(path.wstring());
}
}
else {
if (filename == pattern) {
ProcessDLL(path.wstring());
}
}
}
}
}

int wmain(int argc, wchar_t* argv[]) {
if (argc == 2 || argc == 3) {
std::wstring input(argv[1]);

// Check for wildcard usage
if (argc == 3) {
std::wstring pattern(argv[2]);
if (fs::is_directory(input)) {
ProcessDirectory(input, pattern);
}
else {
std::wcerr << L"Invalid input: Wildcard requires a valid directory\n";
}
}
else if (fs::is_regular_file(input)) {
ProcessDLL(input);
}
else if (fs::is_directory(input)) {
ProcessDirectory(input); // Default to *.dll
}
else {
std::wcerr << L"Invalid input: " << input << std::endl;
}
}
else {
std::wcout << L"Usage:\n"
<< L" <program> <dll-file> Process a single DLL file\n"
<< L" <program> <directory> [pattern] Process DLLs matching a wildcard pattern\n";
}

return 0;
}