Login Page - Create Account

Support Board


Date/Time: Fri, 17 Jan 2025 21:32:13 +0000



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

View Count: 74

[2025-01-17 01:24:25]
User719512 - Posts: 287
Hello Sierra Chart Engineering,

The ARM version of Sierra is not in sync for the current version nor pre-release.
Installed v2732 and v2733 and Sierra for ARM64 is still v 2728.
Is it possible to update your build/release process to release both x64 and ARM64 with the same versions all the time?

Second, related to your previous cleanup of extraneous log messages for _ARM64 when running x64, can the extraneous messages for x64 dlls when running Sierra ARM64 builds be addressed as well? I have included a sample log file with some comments prefixed with "^^^" below.

Similar to how the x64 version now disregards messages for ARM64 and does not try to load "_ARM64.dll" files, the corresponding change for ARM64 seems appropriate where Sierra for ARM64 should disregard and/or not load "_64.dll" files when using "Add Custom Study".

Example log file from SierraChart_ARM64.exe:

2025-01-17 00:30:53.221 | Software version: 2728 64-bit

^^^ downloaded v2732 and v2733, and ARM version is not in sync with the x64 version

...
2025-01-17 00:31:05.140 | Found DLL: C:\SierraChart\Data\OrderFlowLabs.com.autoplot.dll
2025-01-17 00:31:05.140 | Found DLL: C:\SierraChart\Data\OrderFlowLabs.com.free.dll
2025-01-17 00:31:05.140 | Found DLL: C:\SierraChart\Data\OrderFlowLabs.com.dll
2025-01-17 00:31:05.156 | OrderFlowLabs.com.autoplot_64.dll loading error. Windows error code 193: %1 is not a valid Win32 application.

^^^ Sierra loads _ARM64 version of this dll

2025-01-17 00:31:05.159 | OrderFlowLabs.com.beta_64.dll loading error. Windows error code 193: %1 is not a valid Win32 application.
2025-01-17 00:31:05.159 | InternalVersionNumberToFileNameMap is empty for OrderFlowLabs.com.beta
2025-01-17 00:31:05.159 | Closest match search for: C:\SierraChart\Data\OrderFlowLabs.com.beta.dll returned empty result. *

^^^ an _ARM64 version of this dll is NOT present on the machine which gives 2 extra messages in this case.

2025-01-17 00:31:05.167 | OrderFlowLabs.com_64.dll loading error. Windows error code 193: %1 is not a valid Win32 application.

^^^ Sierra loads _ARM64 version of this dll

2025-01-17 00:31:05.172 | OrderFlowLabs.com.free_64.dll loading error. Windows error code 193: %1 is not a valid Win32 application.

^^^ Sierra loads _ARM64 version of this dll


Since Sierra has a naming convention for its DLLs, name filtering/regex is probably sufficient rather than reading the IMAGE_DOS_HEADER, dosHeader.e_lfanew, PE Header and IMAGE_FILE_HEADER which has the Machine information.

Thanks for taking a look at this.
[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;
}

To post a message in this thread, you need to log in with your Sierra Chart account:

Login

Login Page - Create Account