mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-05-16 18:12:10 +00:00
Refactor folder (#10475)
Move many third-party components' source codes from the src folder to a new folder called deps_src. The goal is to make the code structure clearer and easier to navigate.
This commit is contained in:
388
src/dev-utils/BaseException.cpp
Normal file
388
src/dev-utils/BaseException.cpp
Normal file
@@ -0,0 +1,388 @@
|
||||
#include "BaseException.h"
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <mutex>
|
||||
|
||||
static std::string g_log_folder;
|
||||
static std::atomic<int> g_crash_log_count = 0;
|
||||
static std::mutex g_dump_mutex;
|
||||
|
||||
CBaseException::CBaseException(HANDLE hProcess, WORD wPID, LPCTSTR lpSymbolPath, PEXCEPTION_POINTERS pEp):
|
||||
CStackWalker(hProcess, wPID, lpSymbolPath)
|
||||
{
|
||||
if (NULL != pEp)
|
||||
{
|
||||
m_pEp = new EXCEPTION_POINTERS;
|
||||
CopyMemory(m_pEp, pEp, sizeof(EXCEPTION_POINTERS));
|
||||
}
|
||||
output_file = new boost::nowide::ofstream();
|
||||
std::time_t t = std::time(0);
|
||||
std::tm* now_time = std::localtime(&t);
|
||||
std::stringstream buf;
|
||||
|
||||
if (!g_log_folder.empty()) {
|
||||
buf << std::put_time(now_time, "crash_%a_%b_%d_%H_%M_%S_") <<g_crash_log_count++ <<".log";
|
||||
auto log_folder = (boost::filesystem::path(g_log_folder) / "log").make_preferred();
|
||||
if (!boost::filesystem::exists(log_folder)) {
|
||||
boost::filesystem::create_directory(log_folder);
|
||||
}
|
||||
auto crash_log_path = boost::filesystem::path(log_folder / buf.str()).make_preferred();
|
||||
std::string log_filename = crash_log_path.string();
|
||||
output_file->open(log_filename, std::ios::out | std::ios::app);
|
||||
}
|
||||
}
|
||||
|
||||
CBaseException::~CBaseException(void)
|
||||
{
|
||||
if (output_file) {
|
||||
output_file->close();
|
||||
delete output_file;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//BBS set crash log folder
|
||||
void CBaseException::set_log_folder(std::string log_folder)
|
||||
{
|
||||
g_log_folder = log_folder;
|
||||
}
|
||||
|
||||
void CBaseException::OutputString(LPCTSTR lpszFormat, ...)
|
||||
{
|
||||
TCHAR szBuf[2048] = _T("");
|
||||
va_list args;
|
||||
va_start(args, lpszFormat);
|
||||
_vsntprintf_s(szBuf, 2048, lpszFormat, args);
|
||||
va_end(args);
|
||||
|
||||
//WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), szBuf, _tcslen(szBuf), NULL, NULL);
|
||||
|
||||
//output it to the current directory of binary
|
||||
std::string output_str = textconv_helper::T2A_(szBuf);
|
||||
*output_file << output_str;
|
||||
output_file->flush();
|
||||
}
|
||||
|
||||
void CBaseException::ShowLoadModules()
|
||||
{
|
||||
LoadSymbol();
|
||||
LPMODULE_INFO pHead = GetLoadModules();
|
||||
LPMODULE_INFO pmi = pHead;
|
||||
|
||||
TCHAR szBuf[MAX_COMPUTERNAME_LENGTH] = _T("");
|
||||
DWORD dwSize = MAX_COMPUTERNAME_LENGTH;
|
||||
GetUserName(szBuf, &dwSize);
|
||||
OutputString(_T("Current User:%s\r\n"), szBuf);
|
||||
OutputString(_T("BaseAddress:\tSize:\tName\tPath\tSymbolPath\tVersion\r\n"));
|
||||
while (NULL != pmi)
|
||||
{
|
||||
OutputString(_T("%08x\t%d\t%s\t%s\t%s\t%s\r\n"), (unsigned long)(pmi->ModuleAddress), pmi->dwModSize, pmi->szModuleName, pmi->szModulePath, pmi->szSymbolPath, pmi->szVersion);
|
||||
pmi = pmi->pNext;
|
||||
}
|
||||
|
||||
FreeModuleInformations(pHead);
|
||||
}
|
||||
|
||||
void CBaseException::ShowCallstack(HANDLE hThread, const CONTEXT* context)
|
||||
{
|
||||
OutputString(_T("Show CallStack:\n"));
|
||||
LPSTACKINFO phead = StackWalker(hThread, context);
|
||||
|
||||
// Show RVA of each call stack, so we can locate the symbol using pdb file
|
||||
// To show the symbol, load the <szFaultingModule> in WinDBG with pdb file, then type the following commands:
|
||||
// > lm which gives you the start address of each module, as well as module names
|
||||
// > !dh <module name> list all module headers. Find the <virtual address> of the section given by
|
||||
// the <section> output in the crash log
|
||||
// > ln <module start address> + <section virtual address> + <offset> reveals the debug symbol
|
||||
OutputString(_T("\nLogical Address:\n"));
|
||||
TCHAR szFaultingModule[MAX_PATH];
|
||||
DWORD section, offset;
|
||||
for (LPSTACKINFO ps = phead; ps != nullptr; ps = ps->pNext) {
|
||||
if (GetLogicalAddress((PVOID) ps->szFncAddr, szFaultingModule, sizeof(szFaultingModule), section, offset)) {
|
||||
OutputString(_T("0x%X 0x%X:0x%X %s\n"), ps->szFncAddr, section, offset, szFaultingModule);
|
||||
} else {
|
||||
OutputString(_T("0x%X Unknown\n"), ps->szFncAddr);
|
||||
}
|
||||
}
|
||||
|
||||
FreeStackInformations(phead);
|
||||
}
|
||||
|
||||
void CBaseException::ShowExceptionResoult(DWORD dwExceptionCode)
|
||||
{
|
||||
OutputString(_T("Exception Code :%08x "), dwExceptionCode);
|
||||
// BBS: to be checked
|
||||
#if 1
|
||||
switch (dwExceptionCode)
|
||||
{
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
{
|
||||
//OutputString(_T("ACCESS_VIOLATION(%s)\r\n"), _T("<22><>д<EFBFBD>Ƿ<EFBFBD><C7B7>ڴ<EFBFBD>"));
|
||||
OutputString(_T("ACCESS_VIOLATION\r\n"));
|
||||
}
|
||||
return ;
|
||||
case EXCEPTION_DATATYPE_MISALIGNMENT:
|
||||
{
|
||||
//OutputString(_T("DATATYPE_MISALIGNMENT(%s)\r\n"), _T("<22>߳<EFBFBD><DFB3><EFBFBD>ͼ<EFBFBD>ڲ<EFBFBD>֧<EFBFBD>ֶ<EFBFBD><D6B6><EFBFBD><EFBFBD>Ӳ<EFBFBD><D3B2><EFBFBD>϶<EFBFBD>дδ<D0B4><CEB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"));
|
||||
OutputString(_T("DATATYPE_MISALIGNMENT\r\n"));
|
||||
}
|
||||
return ;
|
||||
case EXCEPTION_BREAKPOINT:
|
||||
{
|
||||
//OutputString(_T("BREAKPOINT(%s)\r\n"), _T("<22><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>ϵ<EFBFBD>"));
|
||||
OutputString(_T("BREAKPOINT\r\n"));
|
||||
}
|
||||
return ;
|
||||
case EXCEPTION_SINGLE_STEP:
|
||||
{
|
||||
//OutputString(_T("SINGLE_STEP(%s)\r\n"), _T("<22><><EFBFBD><EFBFBD>")); //һ<><D2BB><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD>
|
||||
OutputString(_T("SINGLE_STEP\r\n"));
|
||||
}
|
||||
return ;
|
||||
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
|
||||
{
|
||||
//OutputString(_T("ARRAY_BOUNDS_EXCEEDED(%s)\r\n"), _T("<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Խ<EFBFBD><D4BD>"));
|
||||
OutputString(_T("ARRAY_BOUNDS_EXCEEDED\r\n"));
|
||||
}
|
||||
return ;
|
||||
case EXCEPTION_FLT_DENORMAL_OPERAND:
|
||||
{
|
||||
//OutputString(_T("FLT_DENORMAL_OPERAND(%s)\r\n"), _T("<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>棬<EFBFBD><E6A3AC><EFBFBD><EFBFBD><EFBFBD>ĸ<EFBFBD><C4B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><DEB7><EFBFBD>ʾ")); //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
OutputString(_T("FLT_DENORMAL_OPERAND\r\n"));
|
||||
}
|
||||
return ;
|
||||
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
|
||||
{
|
||||
//OutputString(_T("FLT_DIVIDE_BY_ZERO(%s)\r\n"), _T("<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0<EFBFBD><30><EFBFBD><EFBFBD>"));
|
||||
OutputString(_T("FLT_DIVIDE_BY_ZERO\r\n"));
|
||||
}
|
||||
return ;
|
||||
case EXCEPTION_FLT_INEXACT_RESULT:
|
||||
{
|
||||
//OutputString(_T("FLT_INEXACT_RESULT(%s)\r\n"), _T("<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ľ<EFBFBD><C4BD><EFBFBD><EFBFBD><DEB7><EFBFBD>ʾ")); //<2F><EFBFBD><DEB7><EFBFBD>ʾһ<CABE><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̫С<CCAB><D0A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD>ķ<EFBFBD>Χ, <20><><EFBFBD><EFBFBD>֮<EFBFBD><D6AE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ľ<EFBFBD><C4BD><EFBFBD>쳣
|
||||
OutputString(_T("FLT_INEXACT_RESULT\r\n"));
|
||||
}
|
||||
return ;
|
||||
case EXCEPTION_FLT_INVALID_OPERATION:
|
||||
{
|
||||
//OutputString(_T("FLT_INVALID_OPERATION(%s)\r\n"), _T("<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>쳣"));
|
||||
OutputString(_T("FLT_INVALID_OPERATION\r\n"));
|
||||
}
|
||||
return ;
|
||||
case EXCEPTION_FLT_OVERFLOW:
|
||||
{
|
||||
//OutputString(_T("FLT_OVERFLOW(%s)\r\n"), _T("<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ<EFBFBD><D3A6><EFBFBD>͵<EFBFBD><CDB5><EFBFBD><EFBFBD>ֵ"));
|
||||
OutputString(_T("FLT_OVERFLOW\r\n"));
|
||||
}
|
||||
return ;
|
||||
case EXCEPTION_FLT_STACK_CHECK:
|
||||
{
|
||||
//OutputString(_T("STACK_CHECK(%s)\r\n"), _T("ջԽ<D5BB><D4BD><EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"));
|
||||
OutputString(_T("STACK_CHECK\r\n"));
|
||||
}
|
||||
return ;
|
||||
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||||
{
|
||||
//OutputString(_T("INT_DIVIDE_BY_ZERO(%s)\r\n"), _T("<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0<EFBFBD>쳣"));
|
||||
OutputString(_T("INT_DIVIDE_BY_ZERO\r\n"));
|
||||
}
|
||||
return ;
|
||||
case EXCEPTION_INVALID_HANDLE:
|
||||
{
|
||||
//OutputString(_T("INVALID_HANDLE(%s)\r\n"), _T("<22><><EFBFBD><EFBFBD><EFBFBD>Ч"));
|
||||
OutputString(_T("INVALID_HANDLE\r\n"));
|
||||
}
|
||||
return ;
|
||||
case EXCEPTION_PRIV_INSTRUCTION:
|
||||
{
|
||||
//OutputString(_T("PRIV_INSTRUCTION(%s)\r\n"), _T("<22>߳<EFBFBD><DFB3><EFBFBD>ͼִ<CDBC>е<EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD>ģʽ<C4A3><CABD>֧<EFBFBD>ֵ<EFBFBD>ָ<EFBFBD><D6B8>"));
|
||||
OutputString(_T("PRIV_INSTRUCTION\r\n"));
|
||||
}
|
||||
return ;
|
||||
case EXCEPTION_IN_PAGE_ERROR:
|
||||
{
|
||||
//OutputString(_T("IN_PAGE_ERROR(%s)\r\n"), _T("<22>߳<EFBFBD><DFB3><EFBFBD>ͼ<EFBFBD><CDBC><EFBFBD><EFBFBD>δ<EFBFBD><CEB4><EFBFBD>ص<EFBFBD><D8B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD>ҳ<EFBFBD><D2B3><EFBFBD>߲<EFBFBD><DFB2>ܼ<EFBFBD><DCBC>ص<EFBFBD><D8B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD>ҳ"));
|
||||
OutputString(_T("IN_PAGE_ERROR\r\n"));
|
||||
}
|
||||
return ;
|
||||
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
||||
{
|
||||
//OutputString(_T("ILLEGAL_INSTRUCTION(%s)\r\n"), _T("<22>߳<EFBFBD><DFB3><EFBFBD>ͼִ<CDBC><D6B4><EFBFBD><EFBFBD>Чָ<D0A7><D6B8>"));
|
||||
OutputString(_T("ILLEGAL_INSTRUCTION\r\n"));
|
||||
}
|
||||
return ;
|
||||
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
|
||||
{
|
||||
//OutputString(_T("NONCONTINUABLE_EXCEPTION(%s)\r\n"), _T("<22>߳<EFBFBD><DFB3><EFBFBD>ͼ<EFBFBD><CDBC>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD>ɼ<EFBFBD><C9BC><EFBFBD>ִ<EFBFBD>е<EFBFBD><D0B5>쳣<EFBFBD><ECB3A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD><D6B4>"));
|
||||
OutputString(_T("NONCONTINUABLE_EXCEPTION\r\n"));
|
||||
}
|
||||
return ;
|
||||
case EXCEPTION_STACK_OVERFLOW:
|
||||
{
|
||||
//OutputString(_T("STACK_OVERFLOW(%s)\r\n"), _T("ջ<><D5BB><EFBFBD>"));
|
||||
OutputString(_T("STACK_OVERFLOW\r\n"));
|
||||
}
|
||||
return ;
|
||||
case EXCEPTION_INVALID_DISPOSITION:
|
||||
{
|
||||
//OutputString(_T("INVALID_DISPOSITION(%s)\r\n"), _T("<22>쳣<EFBFBD><ECB3A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>쳣<EFBFBD><ECB3A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>Ч<EFBFBD><D0A7><EFBFBD><EFBFBD>")); //ʹ<>ø<C3B8><DFBC><EFBFBD><EFBFBD>Ա<EFBFBD>д<EFBFBD>ij<EFBFBD><C4B3><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>쳣
|
||||
OutputString(_T("INVALID_DISPOSITION\r\n"));
|
||||
}
|
||||
return ;
|
||||
case EXCEPTION_FLT_UNDERFLOW:
|
||||
{
|
||||
//OutputString(_T("FLT_UNDERFLOW(%s)\r\n"), _T("<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8>С<EFBFBD><D0A1><EFBFBD><EFBFBD>Ӧ<EFBFBD><D3A6><EFBFBD>͵<EFBFBD><CDB5><EFBFBD>Сֵ"));
|
||||
OutputString(_T("FLT_UNDERFLOW\r\n"));
|
||||
}
|
||||
return ;
|
||||
case EXCEPTION_INT_OVERFLOW:
|
||||
{
|
||||
//OutputString(_T("INT_OVERFLOW(%s)\r\n"), _T("<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Խ<EFBFBD><D4BD>"));
|
||||
OutputString(_T("INT_OVERFLOW\r\n"));
|
||||
}
|
||||
return ;
|
||||
}
|
||||
|
||||
TCHAR szBuffer[512] = { 0 };
|
||||
|
||||
FormatMessage( FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE,
|
||||
GetModuleHandle( _T("NTDLL.DLL") ),
|
||||
dwExceptionCode, 0, szBuffer, sizeof( szBuffer ), 0 );
|
||||
|
||||
OutputString(_T("%s"), szBuffer);
|
||||
OutputString(_T("\r\n"));
|
||||
#endif
|
||||
}
|
||||
|
||||
LONG WINAPI CBaseException::UnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo )
|
||||
{
|
||||
if (pExceptionInfo->ExceptionRecord->ExceptionCode < 0x80000000
|
||||
//BBS: Load project on computers with SDC may trigger this exception (in ShowModal()),
|
||||
// It's not fatal and should be ignored, or there will be lots of meaningless crash logs
|
||||
|| pExceptionInfo->ExceptionRecord->ExceptionCode==0xe0434352)
|
||||
//BBS: ignore the exception when copy preset
|
||||
//|| pExceptionInfo->ExceptionRecord->ExceptionCode==0xe06d7363)
|
||||
{
|
||||
//BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": got an ExceptionCode %1%, skip it!") % pExceptionInfo->ExceptionRecord->ExceptionCode;
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
g_dump_mutex.lock();
|
||||
CBaseException base(GetCurrentProcess(), GetCurrentProcessId(), NULL, pExceptionInfo);
|
||||
base.ShowExceptionInformation();
|
||||
g_dump_mutex.unlock();
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
LONG WINAPI CBaseException::UnhandledExceptionFilter2(PEXCEPTION_POINTERS pExceptionInfo )
|
||||
{
|
||||
CBaseException base(GetCurrentProcess(), GetCurrentProcessId(), NULL, pExceptionInfo);
|
||||
base.ShowExceptionInformation();
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
BOOL CBaseException::GetLogicalAddress(
|
||||
PVOID addr, PTSTR szModule, DWORD len, DWORD& section, DWORD& offset )
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
|
||||
if ( !VirtualQuery( addr, &mbi, sizeof(mbi) ) )
|
||||
return FALSE;
|
||||
|
||||
DWORD_PTR hMod = (DWORD_PTR)mbi.AllocationBase;
|
||||
|
||||
if ( !GetModuleFileName( (HMODULE)hMod, szModule, len ) )
|
||||
return FALSE;
|
||||
|
||||
if (!hMod)
|
||||
return FALSE;
|
||||
|
||||
PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hMod;
|
||||
PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS)(hMod + pDosHdr->e_lfanew);
|
||||
PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION( pNtHdr );
|
||||
|
||||
DWORD_PTR rva = (DWORD_PTR)addr - hMod;
|
||||
|
||||
//<2F><><EFBFBD>㵱ǰ<E3B5B1><C7B0>ַ<EFBFBD>ڵڼ<DAB5><DABC><EFBFBD><EFBFBD><EFBFBD>
|
||||
for (unsigned i = 0; i < pNtHdr->FileHeader.NumberOfSections; i++, pSection++ )
|
||||
{
|
||||
DWORD sectionStart = pSection->VirtualAddress;
|
||||
DWORD sectionEnd = sectionStart + max(pSection->SizeOfRawData, pSection->Misc.VirtualSize);
|
||||
|
||||
if ( (rva >= sectionStart) && (rva <= sectionEnd) )
|
||||
{
|
||||
section = i+1;
|
||||
offset = rva - sectionStart;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE; // Should never get here!
|
||||
}
|
||||
|
||||
void CBaseException::ShowRegistorInformation(PCONTEXT pCtx)
|
||||
{
|
||||
#if defined(_M_IX86) // Intel Only!
|
||||
OutputString( _T("\nRegisters:\r\n") );
|
||||
|
||||
OutputString(_T("EAX:%08X\r\nEBX:%08X\r\nECX:%08X\r\nEDX:%08X\r\nESI:%08X\r\nEDI:%08X\r\n"),
|
||||
pCtx->Eax, pCtx->Ebx, pCtx->Ecx, pCtx->Edx, pCtx->Esi, pCtx->Edi );
|
||||
|
||||
OutputString( _T("CS:EIP:%04X:%08X\r\n"), pCtx->SegCs, pCtx->Eip );
|
||||
OutputString( _T("SS:ESP:%04X:%08X EBP:%08X\r\n"),pCtx->SegSs, pCtx->Esp, pCtx->Ebp );
|
||||
OutputString( _T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"), pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs );
|
||||
OutputString( _T("Flags:%08X\r\n"), pCtx->EFlags );
|
||||
#elif defined(_M_X64)
|
||||
OutputString(_T("\nRegisters:\r\n"));
|
||||
|
||||
OutputString(_T("RAX:%016llX\r\nRBX:%016llX\r\nRCX:%016llX\r\nRDX:%016llX\r\nRSI:%016llX\r\nRDI:%016llX\r\n"),
|
||||
pCtx->Rax, pCtx->Rbx, pCtx->Rcx, pCtx->Rdx, pCtx->Rsi, pCtx->Rdi );
|
||||
|
||||
OutputString(_T("R8:%016llX\r\nR9:%016llX\r\nR10:%016llX\r\nR11:%016llX\r\nR12:%016llX\r\nR13:%016llX\r\nR14:%016llX\r\nR15:%016llX\r\n"),
|
||||
pCtx->R8, pCtx->R9, pCtx->R10, pCtx->R11, pCtx->R12, pCtx->R13, pCtx->R14, pCtx->R15 );
|
||||
|
||||
OutputString(_T("CS:RIP:%04X:%016llX\r\n"), pCtx->SegCs, pCtx->Rip);
|
||||
OutputString(_T("SS:RSP:%04X:%016llX RBP:%016llX\r\n"), pCtx->SegSs, pCtx->Rsp, pCtx->Rbp);
|
||||
OutputString(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"), pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs);
|
||||
OutputString(_T("Flags:%08X\r\n"), pCtx->EFlags);
|
||||
#endif
|
||||
|
||||
OutputString( _T("\r\n") );
|
||||
}
|
||||
|
||||
void CBaseException::STF(unsigned int ui, PEXCEPTION_POINTERS pEp)
|
||||
{
|
||||
CBaseException base(GetCurrentProcess(), GetCurrentProcessId(), NULL, pEp);
|
||||
throw base;
|
||||
}
|
||||
|
||||
void CBaseException::ShowExceptionInformation()
|
||||
{
|
||||
OutputString(_T("Exceptions:\r\n"));
|
||||
ShowExceptionResoult(m_pEp->ExceptionRecord->ExceptionCode);
|
||||
|
||||
OutputString(_T("Exception Flag :0x%x "), m_pEp->ExceptionRecord->ExceptionFlags);
|
||||
OutputString(_T("NumberParameters :%ld \n"), m_pEp->ExceptionRecord->NumberParameters);
|
||||
for (int i = 0; i < m_pEp->ExceptionRecord->NumberParameters; i++)
|
||||
{
|
||||
OutputString(_T("Param %d :0x%x \n"), i, m_pEp->ExceptionRecord->ExceptionInformation[i]);
|
||||
}
|
||||
OutputString(_T("Context :%p \n"), m_pEp->ContextRecord);
|
||||
OutputString(_T("ContextFlag : 0x%x, EFlags: 0x%x \n"), m_pEp->ContextRecord->ContextFlags, m_pEp->ContextRecord->EFlags);
|
||||
|
||||
TCHAR szFaultingModule[MAX_PATH];
|
||||
DWORD section, offset;
|
||||
GetLogicalAddress(m_pEp->ExceptionRecord->ExceptionAddress, szFaultingModule, sizeof(szFaultingModule), section, offset );
|
||||
OutputString( _T("Fault address: 0x%X 0x%X:0x%X %s\r\n"), m_pEp->ExceptionRecord->ExceptionAddress, section, offset, szFaultingModule );
|
||||
|
||||
ShowRegistorInformation(m_pEp->ContextRecord);
|
||||
|
||||
ShowCallstack(GetCurrentThread(), m_pEp->ContextRecord);
|
||||
}
|
||||
31
src/dev-utils/BaseException.h
Normal file
31
src/dev-utils/BaseException.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
#include <boost/nowide/cstdio.hpp>
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#include "stackwalker.h"
|
||||
#include <eh.h>
|
||||
|
||||
class CBaseException : public CStackWalker
|
||||
{
|
||||
public:
|
||||
CBaseException(HANDLE hProcess = GetCurrentProcess(), WORD wPID = GetCurrentProcessId(), LPCTSTR lpSymbolPath = NULL, PEXCEPTION_POINTERS pEp = NULL);
|
||||
~CBaseException(void);
|
||||
virtual void OutputString(LPCTSTR lpszFormat, ...);
|
||||
virtual void ShowLoadModules();
|
||||
virtual void ShowCallstack(HANDLE hThread = GetCurrentThread(), const CONTEXT* context = NULL);
|
||||
virtual void ShowExceptionResoult(DWORD dwExceptionCode);
|
||||
virtual BOOL GetLogicalAddress(PVOID addr, PTSTR szModule, DWORD len, DWORD& section, DWORD& offset );
|
||||
virtual void ShowRegistorInformation(PCONTEXT pCtx);
|
||||
virtual void ShowExceptionInformation();
|
||||
static LONG WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo);
|
||||
static LONG WINAPI UnhandledExceptionFilter2(PEXCEPTION_POINTERS pExceptionInfo);
|
||||
static void STF(unsigned int ui, PEXCEPTION_POINTERS pEp);
|
||||
//BBS set crash log folder
|
||||
static void set_log_folder(std::string log_folder);
|
||||
protected:
|
||||
PEXCEPTION_POINTERS m_pEp;
|
||||
boost::nowide::ofstream *output_file;
|
||||
};
|
||||
|
||||
#define SET_DEFULTER_HANDLER() SetUnhandledExceptionFilter(CBaseException::UnhandledExceptionFilter)
|
||||
|
||||
#define SET_DEFAUL_EXCEPTION() _set_se_translator(CBaseException::STF)
|
||||
50
src/dev-utils/CMakeLists.txt
Normal file
50
src/dev-utils/CMakeLists.txt
Normal file
@@ -0,0 +1,50 @@
|
||||
|
||||
option(SLIC3R_ENC_CHECK "Verify encoding of source files" 1)
|
||||
|
||||
if (IS_CROSS_COMPILE)
|
||||
# Force disable due to cross compilation. This fact is already printed on cli for users
|
||||
set(SLIC3R_ENC_CHECK OFF CACHE BOOL "" FORCE)
|
||||
endif ()
|
||||
|
||||
if (SLIC3R_ENC_CHECK)
|
||||
add_executable(encoding-check encoding-check.cpp)
|
||||
|
||||
# A global no-op target which depends on all encodings checks,
|
||||
# and on which in turn all checked targets depend.
|
||||
# This is done to make encoding checks the first thing to be
|
||||
# performed before actually compiling any sources of the checked targets
|
||||
# to make the check fail as early as possible.
|
||||
add_custom_target(global-encoding-check
|
||||
ALL
|
||||
DEPENDS encoding-check
|
||||
)
|
||||
endif()
|
||||
|
||||
# Function that adds source file encoding check to a target
|
||||
# using the above encoding-check binary
|
||||
|
||||
function(encoding_check TARGET)
|
||||
if (SLIC3R_ENC_CHECK)
|
||||
# Obtain target source files
|
||||
get_target_property(T_SOURCES ${TARGET} SOURCES)
|
||||
|
||||
# Define top-level encoding check target for this ${TARGET}
|
||||
add_custom_target(encoding-check-${TARGET}
|
||||
DEPENDS encoding-check ${T_SOURCES}
|
||||
COMMENT "Checking source files encodings for target ${TARGET}"
|
||||
)
|
||||
|
||||
# Add checking of each source file as a subcommand of encoding-check-${TARGET}
|
||||
foreach(file ${T_SOURCES})
|
||||
add_custom_command(TARGET encoding-check-${TARGET}
|
||||
COMMAND $<TARGET_FILE:encoding-check> ${TARGET} ${file}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
endforeach()
|
||||
|
||||
# This adds dependency on encoding-check-${TARGET} to ${TARET}
|
||||
# via the global-encoding-check
|
||||
add_dependencies(global-encoding-check encoding-check-${TARGET})
|
||||
add_dependencies(${TARGET} global-encoding-check)
|
||||
endif()
|
||||
endfunction()
|
||||
173
src/dev-utils/OrcaSlicer_profile_validator.cpp
Normal file
173
src/dev-utils/OrcaSlicer_profile_validator.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
#include "libslic3r/Preset.hpp"
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "libslic3r/Print.hpp"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
using namespace Slic3r;
|
||||
namespace po = boost::program_options;
|
||||
|
||||
void generate_custom_presets(PresetBundle* preset_bundle, AppConfig& app_config)
|
||||
{
|
||||
struct cus_preset
|
||||
{
|
||||
std::string name;
|
||||
std::string parent_name;
|
||||
};
|
||||
// create user presets
|
||||
auto createCustomPrinters = [&](Preset::Type type) {
|
||||
std::vector<cus_preset> custom_preset;
|
||||
PresetCollection* collection = nullptr;
|
||||
if (type == Preset::TYPE_PRINT)
|
||||
collection = &preset_bundle->prints;
|
||||
else if (type == Preset::TYPE_FILAMENT)
|
||||
collection = &preset_bundle->filaments;
|
||||
else if (type == Preset::TYPE_PRINTER)
|
||||
collection = &preset_bundle->printers;
|
||||
else
|
||||
return;
|
||||
custom_preset.reserve(collection->size());
|
||||
for (auto& parent : collection->get_presets()) {
|
||||
if (!parent.is_system)
|
||||
continue;
|
||||
auto new_name = parent.name + "_orca_test";
|
||||
if (parent.vendor)
|
||||
new_name = parent.vendor->name + "_" + new_name;
|
||||
custom_preset.push_back({new_name, parent.name});
|
||||
}
|
||||
for (auto p : custom_preset) {
|
||||
// Creating a new preset.
|
||||
auto parent = collection->find_preset(p.parent_name);
|
||||
auto vendor = collection->get_preset_with_vendor_profile(*parent);
|
||||
if (type == Preset::TYPE_FILAMENT) {
|
||||
parent->config.set_key_value("filament_start_gcode",
|
||||
new ConfigOptionStrings({"this_is_orca_test_filament_start_gcode_mock"}));
|
||||
parent->config.set_key_value("filament_notes", new ConfigOptionString(vendor.vendor->name));
|
||||
} else if (type == Preset::TYPE_PRINT) {
|
||||
parent->config.set_key_value("filename_format", new ConfigOptionString("this_is_orca_test_filename_format_mock"));
|
||||
parent->config.set_key_value("notes", new ConfigOptionString(vendor.vendor->name));
|
||||
} else if (type == Preset::TYPE_PRINTER) {
|
||||
parent->config.set_key_value("machine_start_gcode", new ConfigOptionString("this_is_orca_test_machine_start_gcode_mock"));
|
||||
parent->config.set_key_value("printer_notes", new ConfigOptionString(vendor.vendor->name));
|
||||
}
|
||||
|
||||
collection->save_current_preset(p.name, false, false, parent);
|
||||
|
||||
}
|
||||
};
|
||||
createCustomPrinters(Preset::TYPE_PRINTER);
|
||||
createCustomPrinters(Preset::TYPE_FILAMENT);
|
||||
createCustomPrinters(Preset::TYPE_PRINT);
|
||||
|
||||
std::string user_sub_folder = DEFAULT_USER_FOLDER_NAME;
|
||||
const std::string dir_user_presets = data_dir() + "/" + PRESET_USER_DIR + "/" + user_sub_folder;
|
||||
|
||||
fs::path user_folder(data_dir() + "/" + PRESET_USER_DIR);
|
||||
if (!fs::exists(user_folder))
|
||||
fs::create_directory(user_folder);
|
||||
|
||||
fs::path folder(dir_user_presets);
|
||||
if (!fs::exists(folder))
|
||||
fs::create_directory(folder);
|
||||
std::vector<std::string> need_to_delete_list; // store setting ids of preset
|
||||
|
||||
preset_bundle->prints.save_user_presets(dir_user_presets, PRESET_PRINT_NAME, need_to_delete_list);
|
||||
preset_bundle->filaments.save_user_presets(dir_user_presets, PRESET_FILAMENT_NAME, need_to_delete_list);
|
||||
preset_bundle->printers.save_user_presets(dir_user_presets, PRESET_PRINTER_NAME, need_to_delete_list);
|
||||
|
||||
std::cout << "Custom presets generated successfully" << std::endl;
|
||||
}
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
po::options_description desc("Orca Profile Validator\nUsage");
|
||||
// clang-format off
|
||||
desc.add_options()("help,h", "help")
|
||||
#ifdef __APPLE__
|
||||
("path,p", po::value<std::string>()->default_value("../../../../../../../resources/profiles"), "profile folder")
|
||||
#else
|
||||
("path,p", po::value<std::string>()->default_value("../../../resources/profiles"), "profile folder")
|
||||
#endif
|
||||
("vendor,v", po::value<std::string>()->default_value(""), "Vendor name. Optional, all profiles present in the folder will be validated if not specified")
|
||||
("generate_presets,g", po::value<bool>()->default_value(false), "Generate user presets for mock test")
|
||||
("log_level,l", po::value<int>()->default_value(2), "Log level. Optional, default is 2 (warning). Higher values produce more detailed logs.");
|
||||
// clang-format on
|
||||
|
||||
po::variables_map vm;
|
||||
try {
|
||||
po::store(po::parse_command_line(argc, argv, desc), vm);
|
||||
|
||||
if (vm.count("help")) {
|
||||
std::cout << desc << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
po::notify(vm);
|
||||
} catch (const po::error& e) {
|
||||
std::cerr << "Error: " << e.what() << "\n";
|
||||
std::cerr << desc << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string path = vm["path"].as<std::string>();
|
||||
std::string vendor = vm["vendor"].as<std::string>();
|
||||
int log_level = vm["log_level"].as<int>();
|
||||
bool generate_user_preset = vm["generate_presets"].as<bool>();
|
||||
|
||||
// check if path is valid, and return error if not
|
||||
if (!fs::exists(path) || !fs::is_directory(path)) {
|
||||
std::cerr << "Error: " << path << " is not a valid directory\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
// std::cout<<"path: "<<path<<std::endl;
|
||||
// std::cout<<"vendor: "<<vendor<<std::endl;
|
||||
// std::cout<<"log_level: "<<log_level<<std::endl;
|
||||
|
||||
set_data_dir(path);
|
||||
|
||||
auto user_dir = fs::path(Slic3r::data_dir()) / PRESET_USER_DIR;
|
||||
user_dir.make_preferred();
|
||||
if (!fs::exists(user_dir))
|
||||
fs::create_directory(user_dir);
|
||||
|
||||
set_logging_level(log_level);
|
||||
auto preset_bundle = new PresetBundle();
|
||||
// preset_bundle->setup_directories();
|
||||
preset_bundle->set_is_validation_mode(true);
|
||||
preset_bundle->set_vendor_to_validate(vendor);
|
||||
|
||||
preset_bundle->set_default_suppressed(true);
|
||||
AppConfig app_config;
|
||||
app_config.set("preset_folder", "default");
|
||||
|
||||
if(generate_user_preset)
|
||||
preset_bundle->remove_user_presets_directory("default");
|
||||
|
||||
try {
|
||||
auto preset_substitutions = preset_bundle->load_presets(app_config, ForwardCompatibilitySubstitutionRule::Disable);
|
||||
} catch (const std::exception& ex) {
|
||||
BOOST_LOG_TRIVIAL(error) << ex.what();
|
||||
std::cout << "Validation failed" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
// Report loaded presets
|
||||
std::cout << "Total loaded vendors: " << preset_bundle->vendors.size() << std::endl;
|
||||
|
||||
if (generate_user_preset) {
|
||||
generate_custom_presets(preset_bundle, app_config);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (preset_bundle->has_errors()) {
|
||||
std::cout << "Validation failed" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::cout << "Validation completed successfully" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
541
src/dev-utils/StackWalker.cpp
Normal file
541
src/dev-utils/StackWalker.cpp
Normal file
@@ -0,0 +1,541 @@
|
||||
#include "StackWalker.h"
|
||||
#include <strsafe.h>
|
||||
//#include <atlconv.h>
|
||||
#include <dbghelp.h>
|
||||
#pragma comment(lib, "version.lib")
|
||||
#pragma comment( lib, "dbghelp.lib" )
|
||||
|
||||
CStackWalker::CStackWalker(HANDLE hProcess, WORD wPID, LPCTSTR lpSymbolPath):
|
||||
m_hProcess(hProcess),
|
||||
m_wPID(wPID),
|
||||
m_bSymbolLoaded(FALSE),
|
||||
m_lpszSymbolPath(NULL)
|
||||
{
|
||||
if (NULL != lpSymbolPath)
|
||||
{
|
||||
size_t dwLength = 0;
|
||||
StringCchLength(lpSymbolPath, MAX_SYMBOL_PATH, &dwLength);
|
||||
m_lpszSymbolPath = new TCHAR[dwLength + 1];
|
||||
ZeroMemory(m_lpszSymbolPath, sizeof(TCHAR) * (dwLength + 1));
|
||||
StringCchCopy(m_lpszSymbolPath, dwLength, lpSymbolPath);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CStackWalker::~CStackWalker(void)
|
||||
{
|
||||
if (NULL != m_lpszSymbolPath)
|
||||
{
|
||||
delete[] m_lpszSymbolPath;
|
||||
}
|
||||
|
||||
if (m_bSymbolLoaded)
|
||||
{
|
||||
SymCleanup(m_hProcess);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL CStackWalker::LoadSymbol()
|
||||
{
|
||||
//USES_CONVERSION;
|
||||
//只加载一次
|
||||
if(m_bSymbolLoaded)
|
||||
{
|
||||
return m_bSymbolLoaded;
|
||||
}
|
||||
|
||||
if (NULL != m_lpszSymbolPath)
|
||||
{
|
||||
|
||||
m_bSymbolLoaded = SymInitialize(m_hProcess, textconv_helper::T2A_(m_lpszSymbolPath), FALSE);
|
||||
return m_bSymbolLoaded;
|
||||
}
|
||||
|
||||
//添加当前程序路径
|
||||
TCHAR szSymbolPath[MAX_SYMBOL_PATH] = _T("");
|
||||
StringCchCopy(szSymbolPath, MAX_SYMBOL_PATH, _T(".;"));
|
||||
|
||||
//添加程序所在目录
|
||||
TCHAR szTemp[MAX_PATH] = _T("");
|
||||
if (GetCurrentDirectory(MAX_PATH, szTemp) > 0)
|
||||
{
|
||||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, szTemp);
|
||||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, _T(";"));
|
||||
}
|
||||
|
||||
//添加程序主模块所在路径
|
||||
ZeroMemory(szTemp, MAX_PATH * sizeof(TCHAR));
|
||||
if (GetModuleFileName(NULL, szTemp, MAX_PATH) > 0)
|
||||
{
|
||||
size_t sLength = 0;
|
||||
StringCchLength(szTemp, MAX_PATH, &sLength);
|
||||
for (int i = sLength; i >= 0; i--)
|
||||
{
|
||||
if (szTemp[i] == _T('\\') || szTemp[i] == _T('/') || szTemp[i] == _T(':'))
|
||||
{
|
||||
szTemp[i] = _T('\0');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, szTemp);
|
||||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, _T(";"));
|
||||
|
||||
ZeroMemory(szTemp, MAX_PATH * sizeof(TCHAR));
|
||||
if (GetEnvironmentVariable(_T("_NT_SYMBOL_PATH"), szTemp, MAX_PATH) > 0)
|
||||
{
|
||||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, szTemp);
|
||||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, _T(";"));
|
||||
}
|
||||
|
||||
ZeroMemory(szTemp, MAX_PATH * sizeof(TCHAR));
|
||||
if (GetEnvironmentVariable(_T("_NT_ALTERNATE_SYMBOL_PATH"), szTemp, MAX_PATH) > 0)
|
||||
{
|
||||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, szTemp);
|
||||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, _T(";"));
|
||||
}
|
||||
|
||||
ZeroMemory(szTemp, MAX_PATH * sizeof(TCHAR));
|
||||
if (GetEnvironmentVariable(_T("SYSTEMROOT"), szTemp, MAX_PATH) > 0)
|
||||
{
|
||||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, szTemp);
|
||||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, _T(";"));
|
||||
// also add the "system32"-directory:
|
||||
StringCchCat(szTemp, MAX_PATH, _T("\\system32"));
|
||||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, szTemp);
|
||||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, _T(";"));
|
||||
}
|
||||
|
||||
ZeroMemory(szTemp, MAX_PATH * sizeof(TCHAR));
|
||||
if (GetEnvironmentVariable(_T("SYSTEMDRIVE"), szTemp, MAX_PATH) > 0)
|
||||
{
|
||||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, _T("SRV*"));
|
||||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, szTemp);
|
||||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, _T("\\websymbols"));
|
||||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, _T("*http://msdl.microsoft.com/download/symbols;"));
|
||||
}
|
||||
else
|
||||
{
|
||||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, _T("SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols;"));
|
||||
}
|
||||
|
||||
size_t sLength = 0;
|
||||
StringCchLength(szSymbolPath, MAX_SYMBOL_PATH, &sLength);
|
||||
if (sLength > 0)
|
||||
{
|
||||
m_lpszSymbolPath = new TCHAR[sLength + 1];
|
||||
ZeroMemory(m_lpszSymbolPath, sizeof(TCHAR) * (sLength + 1));
|
||||
StringCchCopy(m_lpszSymbolPath, sLength, szSymbolPath);
|
||||
}
|
||||
|
||||
if (NULL != m_lpszSymbolPath)
|
||||
{
|
||||
m_bSymbolLoaded = SymInitialize(m_hProcess, textconv_helper::T2A_(m_lpszSymbolPath), TRUE); //这里设置为TRUE,让它在初始化符号表的同时加载符号表
|
||||
}
|
||||
|
||||
DWORD symOptions = SymGetOptions();
|
||||
symOptions |= SYMOPT_LOAD_LINES;
|
||||
symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS;
|
||||
symOptions |= SYMOPT_DEBUG;
|
||||
SymSetOptions(symOptions);
|
||||
|
||||
return m_bSymbolLoaded;
|
||||
}
|
||||
|
||||
LPMODULE_INFO CStackWalker::GetLoadModules()
|
||||
{
|
||||
LPMODULE_INFO pHead = GetModulesTH32();
|
||||
if (NULL == pHead)
|
||||
{
|
||||
pHead = GetModulesPSAPI();
|
||||
}
|
||||
|
||||
return pHead;
|
||||
}
|
||||
|
||||
void CStackWalker::FreeModuleInformations(LPMODULE_INFO pmi)
|
||||
{
|
||||
LPMODULE_INFO head = pmi;
|
||||
while (NULL != head)
|
||||
{
|
||||
pmi = pmi->pNext;
|
||||
delete head;
|
||||
head = pmi;
|
||||
}
|
||||
}
|
||||
|
||||
LPMODULE_INFO CStackWalker::GetModulesTH32()
|
||||
{
|
||||
//这里为了防止加载Toolhelp.dll 影响最终结果,所以采用动态加载的方式
|
||||
LPMODULE_INFO pHead = NULL;
|
||||
LPMODULE_INFO pTail = pHead;
|
||||
|
||||
typedef HANDLE (WINAPI *pfnCreateToolhelp32Snapshot)(DWORD dwFlags, DWORD th32ProcessID);
|
||||
typedef BOOL (WINAPI *pfnModule32First)(HANDLE hSnapshot, LPMODULEENTRY32 lpme );
|
||||
typedef BOOL (WINAPI *pfnModule32Next)(HANDLE hSnapshot, LPMODULEENTRY32 lpme );
|
||||
|
||||
const TCHAR* dllname[] = {_T("kernel32.dll"), _T("tlhelp32.dll")};
|
||||
HINSTANCE hToolhelp = NULL;
|
||||
|
||||
pfnCreateToolhelp32Snapshot CreateToolhelp32Snapshot = NULL;
|
||||
pfnModule32First Module32First = NULL;
|
||||
pfnModule32Next Module32Next = NULL;
|
||||
|
||||
HANDLE hSnap;
|
||||
MODULEENTRY32 me;
|
||||
me.dwSize = sizeof(me);
|
||||
BOOL keepGoing;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < (sizeof(dllname) / sizeof(dllname[0])); i++)
|
||||
{
|
||||
hToolhelp = LoadLibrary(dllname[i]);
|
||||
if (hToolhelp == NULL)
|
||||
continue;
|
||||
CreateToolhelp32Snapshot = (pfnCreateToolhelp32Snapshot)GetProcAddress(hToolhelp, "CreateToolhelp32Snapshot");
|
||||
#ifdef UNICODE
|
||||
Module32First = (pfnModule32First)GetProcAddress(hToolhelp, "Module32FirstW");
|
||||
Module32Next = (pfnModule32Next)GetProcAddress(hToolhelp, "Module32NextW");
|
||||
#else
|
||||
Module32First = (pfnModule32First)GetProcAddress(hToolhelp, "Module32FirstA");
|
||||
Module32Next = (pfnModule32Next)GetProcAddress(hToolhelp, "Module32NextA");
|
||||
#endif
|
||||
|
||||
if ((CreateToolhelp32Snapshot != NULL) && (Module32First != NULL) && (Module32Next != NULL))
|
||||
break;
|
||||
|
||||
FreeLibrary(hToolhelp);
|
||||
hToolhelp = NULL;
|
||||
}
|
||||
|
||||
if (hToolhelp == NULL)
|
||||
return pHead;
|
||||
|
||||
hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, m_wPID);
|
||||
|
||||
if (hSnap == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
FreeLibrary(hToolhelp);
|
||||
return pHead;
|
||||
}
|
||||
|
||||
keepGoing = Module32First(hSnap, &me);
|
||||
|
||||
while (keepGoing)
|
||||
{
|
||||
LPMODULE_INFO pmi = new MODULE_INFO;
|
||||
ZeroMemory(pmi, sizeof(MODULE_INFO));
|
||||
|
||||
pmi->dwModSize = me.modBaseSize;
|
||||
pmi->ModuleAddress = (DWORD64)me.modBaseAddr;
|
||||
StringCchCopy(pmi->szModuleName, MAX_MODULE_NAME32, me.szModule);
|
||||
StringCchCopy(pmi->szModulePath, MAX_PATH, me.szExePath);
|
||||
GetModuleInformation(pmi);
|
||||
if (pHead == NULL)
|
||||
{
|
||||
pHead = pmi;
|
||||
pTail = pHead;
|
||||
}else
|
||||
{
|
||||
pTail->pNext = pmi;
|
||||
pTail = pmi;
|
||||
}
|
||||
|
||||
keepGoing = Module32Next(hSnap, &me);
|
||||
}
|
||||
|
||||
CloseHandle(hSnap);
|
||||
FreeLibrary(hToolhelp);
|
||||
return pHead;
|
||||
}
|
||||
|
||||
LPMODULE_INFO CStackWalker::GetModulesPSAPI()
|
||||
{
|
||||
LPMODULE_INFO pHead = NULL;
|
||||
LPMODULE_INFO pTail = pHead;
|
||||
typedef BOOL(WINAPI *pfnEnumProcessModules)(HANDLE hProcess, HMODULE * lphModule, DWORD cb,LPDWORD lpcbNeeded);
|
||||
typedef DWORD(WINAPI *pfnGetModuleFileNameEx)(HANDLE hProcess, HMODULE hModule, LPTSTR lpFilename, DWORD nSize);
|
||||
typedef DWORD(WINAPI *pfnGetModuleBaseName)(HANDLE hProcess, HMODULE hModule, LPTSTR lpFilename, DWORD nSize);
|
||||
typedef BOOL(WINAPI *pfnGetModuleInformation)(HANDLE hProcess, HMODULE hModule, LPMODULEINFO pmi, DWORD nSize);
|
||||
|
||||
HINSTANCE hPsapi;
|
||||
pfnEnumProcessModules EnumProcessModules = NULL;
|
||||
pfnGetModuleFileNameEx GetModuleFileNameEx = NULL;
|
||||
pfnGetModuleBaseName GetModuleBaseName = NULL;
|
||||
pfnGetModuleInformation GetModuleInformation = NULL;
|
||||
|
||||
DWORD i;
|
||||
//ModuleEntry e;
|
||||
DWORD cbNeeded;
|
||||
MODULEINFO mi;
|
||||
HMODULE* hMods = NULL;
|
||||
TCHAR szModuleName[MAX_MODULE_NAME32 + 1] = _T("");
|
||||
TCHAR szModulePath[MAX_PATH] = _T("");
|
||||
|
||||
hPsapi = LoadLibrary(_T("psapi.dll"));
|
||||
if (hPsapi == NULL)
|
||||
{
|
||||
return pHead;
|
||||
}
|
||||
|
||||
EnumProcessModules = (pfnEnumProcessModules)GetProcAddress(hPsapi, "EnumProcessModules");
|
||||
#ifdef UNICODE
|
||||
GetModuleFileNameEx = (pfnGetModuleFileNameEx)GetProcAddress(hPsapi, "GetModuleFileNameExW");
|
||||
GetModuleBaseName = (pfnGetModuleBaseName)GetProcAddress(hPsapi, "GetModuleBaseNameW");
|
||||
#else
|
||||
GetModuleFileNameEx = (pfnGetModuleFileNameEx)GetProcAddress(hPsapi, "GetModuleFileNameExA");
|
||||
GetModuleBaseName = (pfnGetModuleBaseName)GetProcAddress(hPsapi, "GetModuleBaseNameA");
|
||||
#endif
|
||||
GetModuleInformation = (pfnGetModuleInformation)GetProcAddress(hPsapi, "GetModuleInformation");
|
||||
if ((EnumProcessModules == NULL) || (GetModuleFileNameEx == NULL) || (GetModuleBaseName == NULL) || (GetModuleInformation == NULL))
|
||||
{
|
||||
FreeLibrary(hPsapi);
|
||||
return pHead;
|
||||
}
|
||||
|
||||
EnumProcessModules(m_hProcess, hMods, 0, &cbNeeded);
|
||||
hMods = new HMODULE[cbNeeded / sizeof(HMODULE)];
|
||||
ASSERT(NULL != hMods);
|
||||
ZeroMemory(hMods, cbNeeded);
|
||||
|
||||
if (!EnumProcessModules(m_hProcess, hMods, cbNeeded, &cbNeeded))
|
||||
{
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (i = 0; i < cbNeeded / sizeof(HMODULE); i++)
|
||||
{
|
||||
GetModuleInformation(m_hProcess, hMods[i], &mi, sizeof(mi));
|
||||
GetModuleFileNameEx(m_hProcess, hMods[i], szModulePath, MAX_PATH);
|
||||
GetModuleBaseName(m_hProcess, hMods[i], szModuleName, MAX_MODULE_NAME32);
|
||||
LPMODULE_INFO pmi = new MODULE_INFO;
|
||||
ZeroMemory(pmi, sizeof(MODULE_INFO));
|
||||
pmi->dwModSize = mi.SizeOfImage;
|
||||
pmi->ModuleAddress = (DWORD64)mi.lpBaseOfDll;
|
||||
StringCchCopy(pmi->szModuleName, MAX_MODULE_NAME32, szModuleName);
|
||||
StringCchCopy(pmi->szModulePath, MAX_PATH, szModulePath);
|
||||
this->GetModuleInformation(pmi);
|
||||
if (pHead == NULL)
|
||||
{
|
||||
pHead = pmi;
|
||||
pTail = pHead;
|
||||
}else
|
||||
{
|
||||
pTail->pNext = pmi;
|
||||
pTail = pmi;
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (hPsapi != NULL)
|
||||
{
|
||||
FreeLibrary(hPsapi);
|
||||
}
|
||||
if (hMods != NULL)
|
||||
{
|
||||
delete[] hMods;
|
||||
}
|
||||
|
||||
return pHead;
|
||||
}
|
||||
|
||||
void CStackWalker::OutputString(LPCTSTR lpszFormat, ...)
|
||||
{
|
||||
TCHAR szBuf[1024] = _T("");
|
||||
va_list args;
|
||||
va_start(args, lpszFormat);
|
||||
_vsntprintf_s(szBuf, 1024, lpszFormat, args);
|
||||
va_end(args);
|
||||
|
||||
OutputDebugString(szBuf);
|
||||
}
|
||||
|
||||
void CStackWalker::GetModuleInformation(LPMODULE_INFO pmi)
|
||||
{
|
||||
//USES_CONVERSION;
|
||||
IMAGEHLP_MODULE64 im = {0};
|
||||
im.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
|
||||
|
||||
VS_FIXEDFILEINFO* pvfi = NULL;
|
||||
DWORD dwHandle = 0;
|
||||
DWORD dwInfoSize = 0;
|
||||
dwInfoSize = GetFileVersionInfoSize(pmi->szModulePath, &dwHandle);
|
||||
|
||||
if (dwInfoSize > 0)
|
||||
{
|
||||
LPVOID lpData = new byte[dwInfoSize];
|
||||
ZeroMemory(lpData, dwInfoSize * sizeof(byte));
|
||||
|
||||
if (GetFileVersionInfo(pmi->szModulePath, dwHandle, dwInfoSize, lpData) > 0 )
|
||||
{
|
||||
TCHAR szBlock[] = _T("\\");
|
||||
UINT len;
|
||||
if (VerQueryValue(lpData, szBlock, (LPVOID*)&pvfi, &len))
|
||||
{
|
||||
WORD v1 = HIWORD(pvfi->dwFileVersionMS);
|
||||
WORD v2 = LOWORD(pvfi->dwFileVersionMS);
|
||||
WORD v3 = HIWORD(pvfi->dwFileVersionLS);
|
||||
WORD v4 = LOWORD(pvfi->dwFileVersionLS);
|
||||
_stprintf_s(pmi->szVersion, MAX_VERSION_LENGTH, _T("%d.%d.%d.%d"), v1, v2, v3, v4);
|
||||
}
|
||||
}
|
||||
|
||||
delete[] lpData;
|
||||
}
|
||||
|
||||
SymGetModuleInfo64(m_hProcess, pmi->ModuleAddress, &im);
|
||||
StringCchCopy(pmi->szSymbolPath, MAX_PATH, textconv_helper::A2T_(im.LoadedPdbName));
|
||||
}
|
||||
|
||||
LPSTACKINFO CStackWalker::StackWalker(HANDLE hThread, const CONTEXT* context)
|
||||
{
|
||||
//USES_CONVERSION;
|
||||
//加载符号表
|
||||
LoadSymbol();
|
||||
|
||||
LPSTACKINFO pHead = NULL;
|
||||
LPSTACKINFO pTail = pHead;
|
||||
|
||||
//获取当前线程的上下文环境
|
||||
CONTEXT c = {0};
|
||||
if (context == NULL)
|
||||
{
|
||||
#if _WIN32_WINNT <= 0x0501
|
||||
if (hThread == GetCurrentThread())
|
||||
#else
|
||||
if (GetThreadId(hThread) == GetCurrentThreadId())
|
||||
#endif
|
||||
{
|
||||
GET_CURRENT_THREAD_CONTEXT(c, CONTEXT_FULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
//如果不是当前线程,需要停止目标线程,以便取出正确的堆栈信息
|
||||
SuspendThread(hThread);
|
||||
memset(&c, 0, sizeof(CONTEXT));
|
||||
c.ContextFlags = CONTEXT_FULL;
|
||||
if (GetThreadContext(hThread, &c) == FALSE)
|
||||
{
|
||||
ResumeThread(hThread);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
c = *context;
|
||||
|
||||
STACKFRAME64 sf = {0};
|
||||
DWORD imageType;
|
||||
|
||||
//intel X86
|
||||
#ifdef _M_IX86
|
||||
imageType = IMAGE_FILE_MACHINE_I386;
|
||||
sf.AddrPC.Offset = c.Eip;
|
||||
sf.AddrPC.Mode = AddrModeFlat;
|
||||
sf.AddrFrame.Offset = c.Ebp;
|
||||
sf.AddrFrame.Mode = AddrModeFlat;
|
||||
sf.AddrStack.Offset = c.Esp;
|
||||
sf.AddrStack.Mode = AddrModeFlat;
|
||||
// AMD
|
||||
#elif _M_X64
|
||||
imageType = IMAGE_FILE_MACHINE_AMD64;
|
||||
sf.AddrPC.Offset = c.Rip;
|
||||
sf.AddrPC.Mode = AddrModeFlat;
|
||||
sf.AddrFrame.Offset = c.Rsp;
|
||||
sf.AddrFrame.Mode = AddrModeFlat;
|
||||
sf.AddrStack.Offset = c.Rsp;
|
||||
sf.AddrStack.Mode = AddrModeFlat;
|
||||
////intel Itanium(安腾)
|
||||
#elif _M_IA64
|
||||
imageType = IMAGE_FILE_MACHINE_IA64;
|
||||
sf.AddrPC.Offset = c.StIIP;
|
||||
sf.AddrPC.Mode = AddrModeFlat;
|
||||
sf.AddrFrame.Offset = c.IntSp;
|
||||
sf.AddrFrame.Mode = AddrModeFlat;
|
||||
sf.AddrBStore.Offset = c.RsBSP;
|
||||
sf.AddrBStore.Mode = AddrModeFlat;
|
||||
sf.AddrStack.Offset = c.IntSp;
|
||||
sf.AddrStack.Mode = AddrModeFlat;
|
||||
#else
|
||||
#error "Platform not supported!"
|
||||
#endif
|
||||
|
||||
|
||||
DWORD64 dwDisplayment = 0;
|
||||
PIMAGEHLP_SYMBOL64 pSym = (PIMAGEHLP_SYMBOL64)new BYTE[sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN];
|
||||
PIMAGEHLP_LINE64 pLine = new IMAGEHLP_LINE64;
|
||||
while (StackWalk64(imageType, m_hProcess, hThread, &sf, &c, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
|
||||
{
|
||||
ZeroMemory(pSym, sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);
|
||||
ZeroMemory(pLine, sizeof(IMAGEHLP_LINE64));
|
||||
|
||||
pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
|
||||
pSym->MaxNameLength = STACKWALK_MAX_NAMELEN;
|
||||
pLine->SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
|
||||
LPSTACKINFO pCallStack = new STACKINFO;
|
||||
ZeroMemory(pCallStack, sizeof(STACKINFO));
|
||||
pCallStack->szFncAddr = sf.AddrPC.Offset;
|
||||
if (sf.AddrPC.Offset != 0)
|
||||
{
|
||||
if(SymGetSymFromAddr64(m_hProcess, sf.AddrPC.Offset, &dwDisplayment, pSym))
|
||||
{
|
||||
char szName[STACKWALK_MAX_NAMELEN] = "";
|
||||
StringCchCopy(pCallStack->szFncName, STACKWALK_MAX_NAMELEN, textconv_helper::A2T_(pSym->Name));
|
||||
UnDecorateSymbolName(pSym->Name, szName, STACKWALK_MAX_NAMELEN, UNDNAME_COMPLETE);
|
||||
StringCchCopy(pCallStack->undFullName, STACKWALK_MAX_NAMELEN, textconv_helper::A2T_(szName));
|
||||
ZeroMemory(szName, STACKWALK_MAX_NAMELEN * sizeof(char));
|
||||
UnDecorateSymbolName(pSym->Name, szName, STACKWALK_MAX_NAMELEN, UNDNAME_NAME_ONLY);
|
||||
StringCchCopy(pCallStack->undName, STACKWALK_MAX_NAMELEN, textconv_helper::A2T_(szName));
|
||||
}else
|
||||
{
|
||||
//调用错误一般是487(地址无效或者没有访问的权限、在符号表中未找到指定地址的相关信息)
|
||||
//this->OutputString(_T("Call SymGetSymFromAddr64 ,Address %08x Error:%08x\n"), sf.AddrPC.Offset, GetLastError());
|
||||
|
||||
StringCchCopy(pCallStack->undFullName, STACKWALK_MAX_NAMELEN, textconv_helper::A2T_("Unknown"));
|
||||
}
|
||||
|
||||
if (SymGetLineFromAddr64(m_hProcess, sf.AddrPC.Offset, (DWORD*)&dwDisplayment, pLine))
|
||||
{
|
||||
StringCchCopy(pCallStack->szFileName, MAX_PATH, textconv_helper::A2T_(pLine->FileName));
|
||||
pCallStack->uFileNum = pLine->LineNumber;
|
||||
}else
|
||||
{
|
||||
//this->OutputString(_T("Call SymGetLineFromAddr64 ,Address %08x Error:%08x\n"), sf.AddrPC.Offset, GetLastError());
|
||||
|
||||
StringCchCopy(pCallStack->szFileName, MAX_PATH, textconv_helper::A2T_("Unknown file"));
|
||||
pCallStack->uFileNum = -1;
|
||||
}
|
||||
|
||||
//这里为了将获取函数信息失败的情况与正常的情况一起输出,防止用户在查看时出现误解
|
||||
this->OutputString(_T("%08llx:%s [%s][%ld]\n"), pCallStack->szFncAddr, pCallStack->undFullName, pCallStack->szFileName, pCallStack->uFileNum);
|
||||
if (NULL == pHead)
|
||||
{
|
||||
pHead = pCallStack;
|
||||
pTail = pHead;
|
||||
}else
|
||||
{
|
||||
pTail->pNext = pCallStack;
|
||||
pTail = pCallStack;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete[] pSym;
|
||||
delete pLine;
|
||||
|
||||
return pHead;
|
||||
}
|
||||
|
||||
void CStackWalker::FreeStackInformations(LPSTACKINFO psi)
|
||||
{
|
||||
LPSTACKINFO head = psi;
|
||||
while (NULL != head)
|
||||
{
|
||||
psi = psi->pNext;
|
||||
delete head;
|
||||
head = psi;
|
||||
}
|
||||
|
||||
}
|
||||
284
src/dev-utils/StackWalker.h
Normal file
284
src/dev-utils/StackWalker.h
Normal file
@@ -0,0 +1,284 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
#include <tchar.h>
|
||||
#include <vector>
|
||||
|
||||
namespace textconv_helper
|
||||
{
|
||||
// Forward declarations of our classes. They are defined later.
|
||||
class CA2A_;
|
||||
class CA2W_;
|
||||
class CW2A_;
|
||||
class CW2W_;
|
||||
class CA2BSTR_;
|
||||
class CW2BSTR_;
|
||||
|
||||
// typedefs for the well known text conversions
|
||||
typedef CA2W_ A2W_;
|
||||
typedef CW2A_ W2A_;
|
||||
//typedef CW2BSTR_ W2BSTR_;
|
||||
//typedef CA2BSTR_ A2BSTR_;
|
||||
typedef CW2A_ BSTR2A_;
|
||||
typedef CW2W_ BSTR2W_;
|
||||
|
||||
#ifdef _UNICODE
|
||||
typedef CA2W_ A2T_;
|
||||
typedef CW2A_ T2A_;
|
||||
typedef CW2W_ T2W_;
|
||||
typedef CW2W_ W2T_;
|
||||
//typedef CW2BSTR_ T2BSTR_;
|
||||
//typedef BSTR2W_ BSTR2T_;
|
||||
#else
|
||||
typedef CA2A_ A2T_;
|
||||
typedef CA2A_ T2A_;
|
||||
typedef CA2W_ T2W_;
|
||||
typedef CW2A_ W2T_;
|
||||
typedef CA2BSTR_ T2BSTR_;
|
||||
typedef BSTR2A_ BSTR2T_;
|
||||
#endif
|
||||
|
||||
typedef A2W_ A2OLE_;
|
||||
typedef T2W_ T2OLE_;
|
||||
typedef CW2W_ W2OLE_;
|
||||
typedef W2A_ OLE2A_;
|
||||
typedef W2T_ OLE2T_;
|
||||
typedef CW2W_ OLE2W_;
|
||||
|
||||
class CA2W_
|
||||
{
|
||||
public:
|
||||
CA2W_(LPCSTR pStr, UINT codePage = CP_ACP) : m_pStr(pStr)
|
||||
{
|
||||
if (pStr)
|
||||
{
|
||||
// Resize the vector and assign null WCHAR to each element
|
||||
int length = MultiByteToWideChar(codePage, 0, pStr, -1, NULL, 0) + 1;
|
||||
m_vWideArray.assign(length, L'\0');
|
||||
|
||||
// Fill our vector with the converted WCHAR array
|
||||
MultiByteToWideChar(codePage, 0, pStr, -1, &m_vWideArray[0], length);
|
||||
}
|
||||
}
|
||||
~CA2W_() {}
|
||||
operator LPCWSTR() { return m_pStr ? &m_vWideArray[0] : NULL; }
|
||||
//operator LPOLESTR() { return m_pStr ? (LPOLESTR)&m_vWideArray[0] : (LPOLESTR)NULL; }
|
||||
|
||||
private:
|
||||
CA2W_(const CA2W_&);
|
||||
CA2W_& operator= (const CA2W_&);
|
||||
std::vector<wchar_t> m_vWideArray;
|
||||
LPCSTR m_pStr;
|
||||
};
|
||||
|
||||
class CW2A_
|
||||
{
|
||||
public:
|
||||
CW2A_(LPCWSTR pWStr, UINT codePage = CP_ACP) : m_pWStr(pWStr)
|
||||
// Usage:
|
||||
// CW2A_ ansiString(L"Some Text");
|
||||
// CW2A_ utf8String(L"Some Text", CP_UTF8);
|
||||
//
|
||||
// or
|
||||
// SetWindowTextA( W2A(L"Some Text") ); The ANSI version of SetWindowText
|
||||
{
|
||||
// Resize the vector and assign null char to each element
|
||||
int length = WideCharToMultiByte(codePage, 0, pWStr, -1, NULL, 0, NULL, NULL) + 1;
|
||||
m_vAnsiArray.assign(length, '\0');
|
||||
|
||||
// Fill our vector with the converted char array
|
||||
WideCharToMultiByte(codePage, 0, pWStr, -1, &m_vAnsiArray[0], length, NULL, NULL);
|
||||
}
|
||||
|
||||
~CW2A_()
|
||||
{
|
||||
m_pWStr = 0;
|
||||
}
|
||||
operator LPCSTR() { return m_pWStr ? &m_vAnsiArray[0] : NULL; }
|
||||
|
||||
private:
|
||||
CW2A_(const CW2A_&);
|
||||
CW2A_& operator= (const CW2A_&);
|
||||
std::vector<char> m_vAnsiArray;
|
||||
LPCWSTR m_pWStr;
|
||||
};
|
||||
|
||||
class CW2W_
|
||||
{
|
||||
public:
|
||||
CW2W_(LPCWSTR pWStr) : m_pWStr(pWStr) {}
|
||||
operator LPCWSTR() { return const_cast<LPWSTR>(m_pWStr); }
|
||||
//operator LPOLESTR() { return const_cast<LPOLESTR>(m_pWStr); }
|
||||
|
||||
private:
|
||||
CW2W_(const CW2W_&);
|
||||
CW2W_& operator= (const CW2W_&);
|
||||
|
||||
LPCWSTR m_pWStr;
|
||||
};
|
||||
|
||||
class CA2A_
|
||||
{
|
||||
public:
|
||||
CA2A_(LPCSTR pStr) : m_pStr(pStr) {}
|
||||
operator LPCSTR() { return (LPSTR)m_pStr; }
|
||||
|
||||
private:
|
||||
CA2A_(const CA2A_&);
|
||||
CA2A_& operator= (const CA2A_&);
|
||||
|
||||
LPCSTR m_pStr;
|
||||
};
|
||||
|
||||
/*class CW2BSTR_
|
||||
{
|
||||
public:
|
||||
CW2BSTR_(LPCWSTR pWStr) { m_bstrString = ::SysAllocString(pWStr); }
|
||||
~CW2BSTR_() { ::SysFreeString(m_bstrString); }
|
||||
operator BSTR() { return m_bstrString; }
|
||||
|
||||
private:
|
||||
CW2BSTR_(const CW2BSTR_&);
|
||||
CW2BSTR_& operator= (const CW2BSTR_&);
|
||||
BSTR m_bstrString;
|
||||
};
|
||||
|
||||
class CA2BSTR_
|
||||
{
|
||||
public:
|
||||
CA2BSTR_(LPCSTR pStr) { m_bstrString = ::SysAllocString(textconv_helper::CA2W_(pStr)); }
|
||||
~CA2BSTR_() { ::SysFreeString(m_bstrString); }
|
||||
operator BSTR() { return m_bstrString; }
|
||||
|
||||
private:
|
||||
CA2BSTR_(const CA2BSTR_&);
|
||||
CA2BSTR_& operator= (const CA2BSTR_&);
|
||||
BSTR m_bstrString;
|
||||
};*/
|
||||
}
|
||||
|
||||
#define MAX_SYMBOL_PATH 1024
|
||||
#define MAX_MODULE_NAME32 255
|
||||
#define TH32CS_SNAPMODULE 0x00000008
|
||||
#define MAX_VERSION_LENGTH 512
|
||||
#define STACKWALK_MAX_NAMELEN 1024
|
||||
|
||||
#define ASSERT(judge)\
|
||||
{\
|
||||
if(!(judge))\
|
||||
{\
|
||||
DebugBreak();\
|
||||
}\
|
||||
}
|
||||
|
||||
typedef struct tagMODULEENTRY32
|
||||
{
|
||||
DWORD dwSize;
|
||||
DWORD th32ModuleID; // This module
|
||||
DWORD th32ProcessID; // owning process
|
||||
DWORD GlblcntUsage; // Global usage count on the module
|
||||
DWORD ProccntUsage; // Module usage count in th32ProcessID's context
|
||||
BYTE* modBaseAddr; // Base address of module in th32ProcessID's context
|
||||
DWORD modBaseSize; // Size in bytes of module starting at modBaseAddr
|
||||
HMODULE hModule; // The hModule of this module in th32ProcessID's context
|
||||
TCHAR szModule[MAX_MODULE_NAME32 + 1];
|
||||
TCHAR szExePath[MAX_PATH];
|
||||
} MODULEENTRY32;
|
||||
|
||||
typedef struct _MODULEINFO
|
||||
{
|
||||
LPVOID lpBaseOfDll;
|
||||
DWORD SizeOfImage;
|
||||
LPVOID EntryPoint;
|
||||
} MODULEINFO, *LPMODULEINFO;
|
||||
|
||||
typedef MODULEENTRY32* PMODULEENTRY32;
|
||||
typedef MODULEENTRY32* LPMODULEENTRY32;
|
||||
|
||||
typedef struct _tag_MODULE_INFO
|
||||
{
|
||||
DWORD64 ModuleAddress;
|
||||
DWORD dwModSize;
|
||||
TCHAR szModuleName[MAX_MODULE_NAME32 + 1];
|
||||
TCHAR szModulePath[MAX_PATH];
|
||||
TCHAR szSymbolPath[MAX_PATH];
|
||||
TCHAR szVersion[MAX_VERSION_LENGTH];
|
||||
struct _tag_MODULE_INFO* pNext;
|
||||
}MODULE_INFO, *LPMODULE_INFO;
|
||||
|
||||
typedef struct tagSTACKINFO
|
||||
{
|
||||
DWORD64 szFncAddr;
|
||||
TCHAR szFileName[MAX_PATH];
|
||||
TCHAR szFncName[MAX_PATH];
|
||||
unsigned long uFileNum;
|
||||
TCHAR undName[STACKWALK_MAX_NAMELEN];
|
||||
TCHAR undFullName[STACKWALK_MAX_NAMELEN];
|
||||
tagSTACKINFO *pNext;
|
||||
}STACKINFO, *LPSTACKINFO;
|
||||
|
||||
class CStackWalker
|
||||
{
|
||||
public:
|
||||
CStackWalker(HANDLE hProcess = GetCurrentProcess(), WORD wPID = GetCurrentProcessId(), LPCTSTR lpSymbolPath = NULL);
|
||||
~CStackWalker(void);
|
||||
BOOL LoadSymbol();
|
||||
LPMODULE_INFO GetLoadModules();
|
||||
void GetModuleInformation(LPMODULE_INFO pmi);
|
||||
|
||||
void FreeModuleInformations(LPMODULE_INFO pmi);
|
||||
virtual void OutputString(LPCTSTR lpszFormat, ...);
|
||||
|
||||
LPSTACKINFO StackWalker(HANDLE hThread = GetCurrentThread(), const CONTEXT* context = NULL);
|
||||
void FreeStackInformations(LPSTACKINFO psi);
|
||||
|
||||
protected:
|
||||
LPMODULE_INFO GetModulesTH32();
|
||||
LPMODULE_INFO GetModulesPSAPI();
|
||||
protected:
|
||||
HANDLE m_hProcess;
|
||||
WORD m_wPID;
|
||||
LPTSTR m_lpszSymbolPath;
|
||||
BOOL m_bSymbolLoaded;
|
||||
};
|
||||
|
||||
#if defined(_M_IX86)
|
||||
#ifdef CURRENT_THREAD_VIA_EXCEPTION
|
||||
#define GET_CURRENT_THREAD_CONTEXT(c, contextFlags)\
|
||||
do\
|
||||
{\
|
||||
memset(&c, 0, sizeof(CONTEXT));\
|
||||
EXCEPTION_POINTERS* pExp = NULL;\
|
||||
__try\
|
||||
{\
|
||||
throw 0;\
|
||||
}\
|
||||
__except (((pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER:EXCEPTION_EXECUTE_HANDLER))\
|
||||
{\
|
||||
}\
|
||||
if (pExp != NULL)\
|
||||
memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT));\
|
||||
c.ContextFlags = contextFlags;\
|
||||
} while (0);
|
||||
#else
|
||||
#define GET_CURRENT_THREAD_CONTEXT(c, contextFlags) \
|
||||
do\
|
||||
{\
|
||||
memset(&c, 0, sizeof(CONTEXT));\
|
||||
c.ContextFlags = contextFlags;\
|
||||
__asm call $+5\
|
||||
__asm pop eax\
|
||||
__asm mov c.Eip, eax\
|
||||
__asm mov c.Ebp, ebp\
|
||||
__asm mov c.Esp, esp\
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define GET_CURRENT_THREAD_CONTEXT(c, contextFlags) \
|
||||
do\
|
||||
{ \
|
||||
memset(&c, 0, sizeof(CONTEXT));\
|
||||
c.ContextFlags = contextFlags;\
|
||||
RtlCaptureContext(&c);\
|
||||
} while (0);
|
||||
#endif
|
||||
119
src/dev-utils/encoding-check.cpp
Normal file
119
src/dev-utils/encoding-check.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstdlib>
|
||||
|
||||
|
||||
/*
|
||||
* The utf8_check() function scans the '\0'-terminated string starting
|
||||
* at s. It returns a pointer to the first byte of the first malformed
|
||||
* or overlong UTF-8 sequence found, or NULL if the string contains
|
||||
* only correct UTF-8. It also spots UTF-8 sequences that could cause
|
||||
* trouble if converted to UTF-16, namely surrogate characters
|
||||
* (U+D800..U+DFFF) and non-Unicode positions (U+FFFE..U+FFFF). This
|
||||
* routine is very likely to find a malformed sequence if the input
|
||||
* uses any other encoding than UTF-8. It therefore can be used as a
|
||||
* very effective heuristic for distinguishing between UTF-8 and other
|
||||
* encodings.
|
||||
*
|
||||
* I wrote this code mainly as a specification of functionality; there
|
||||
* are no doubt performance optimizations possible for certain CPUs.
|
||||
*
|
||||
* Markus Kuhn <http://www.cl.cam.ac.uk/~mgk25/> -- 2005-03-30
|
||||
* License: http://www.cl.cam.ac.uk/~mgk25/short-license.html
|
||||
*/
|
||||
|
||||
unsigned char *utf8_check(unsigned char *s)
|
||||
{
|
||||
while (*s) {
|
||||
if (*s < 0x80) {
|
||||
// 0xxxxxxx
|
||||
s++;
|
||||
} else if ((s[0] & 0xe0) == 0xc0) {
|
||||
// 110xxxxx 10xxxxxx
|
||||
if ((s[1] & 0xc0) != 0x80 ||
|
||||
(s[0] & 0xfe) == 0xc0) { // overlong?
|
||||
return s;
|
||||
} else {
|
||||
s += 2;
|
||||
}
|
||||
} else if ((s[0] & 0xf0) == 0xe0) {
|
||||
// 1110xxxx 10xxxxxx 10xxxxxx
|
||||
if ((s[1] & 0xc0) != 0x80 ||
|
||||
(s[2] & 0xc0) != 0x80 ||
|
||||
(s[0] == 0xe0 && (s[1] & 0xe0) == 0x80) || // overlong?
|
||||
(s[0] == 0xed && (s[1] & 0xe0) == 0xa0) || // surrogate?
|
||||
(s[0] == 0xef && s[1] == 0xbf &&
|
||||
(s[2] & 0xfe) == 0xbe)) { // U+FFFE or U+FFFF?
|
||||
return s;
|
||||
} else {
|
||||
s += 3;
|
||||
}
|
||||
} else if ((s[0] & 0xf8) == 0xf0) {
|
||||
// 11110xxX 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
if ((s[1] & 0xc0) != 0x80 ||
|
||||
(s[2] & 0xc0) != 0x80 ||
|
||||
(s[3] & 0xc0) != 0x80 ||
|
||||
(s[0] == 0xf0 && (s[1] & 0xf0) == 0x80) || // overlong?
|
||||
(s[0] == 0xf4 && s[1] > 0x8f) || s[0] > 0xf4) { // > U+10FFFF?
|
||||
return s;
|
||||
} else {
|
||||
s += 4;
|
||||
}
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
if (argc != 3) {
|
||||
std::cerr << "Usage: " << argv[0] << " <program/library> <file>" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char* target = argv[1];
|
||||
const char* filename = argv[2];
|
||||
|
||||
const auto error_exit = [=](const char* error) {
|
||||
std::cerr << "\n\tError: " << error << ": " << filename << "\n"
|
||||
<< "\tTarget: " << target << "\n"
|
||||
<< std::endl;
|
||||
std::exit(-2);
|
||||
};
|
||||
|
||||
std::ifstream file(filename, std::ios::binary | std::ios::ate);
|
||||
const auto size = file.tellg();
|
||||
|
||||
if (size == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
file.seekg(0, std::ios::beg);
|
||||
std::vector<char> buffer(size);
|
||||
|
||||
if (file.read(buffer.data(), size)) {
|
||||
buffer.push_back('\0');
|
||||
|
||||
// Check UTF-8 validity
|
||||
if (utf8_check(reinterpret_cast<unsigned char*>(buffer.data())) != nullptr) {
|
||||
error_exit("Source file does not contain (valid) UTF-8");
|
||||
}
|
||||
|
||||
// Check against a BOM mark
|
||||
if (buffer.size() >= 3
|
||||
&& buffer[0] == '\xef'
|
||||
&& buffer[1] == '\xbb'
|
||||
&& buffer[2] == '\xbf') {
|
||||
error_exit("Source file is valid UTF-8 but contains a BOM mark");
|
||||
}
|
||||
} else {
|
||||
error_exit("Could not read source file");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
25
src/dev-utils/platform/msw/OrcaSlicer-gcodeviewer.rc.in
Normal file
25
src/dev-utils/platform/msw/OrcaSlicer-gcodeviewer.rc.in
Normal file
@@ -0,0 +1,25 @@
|
||||
1 VERSIONINFO
|
||||
FILEVERSION @SLIC3R_VERSION@
|
||||
PRODUCTVERSION @SLIC3R_VERSION@
|
||||
{
|
||||
BLOCK "StringFileInfo"
|
||||
{
|
||||
BLOCK "040904E4"
|
||||
{
|
||||
VALUE "CompanyName", "SoftFever"
|
||||
VALUE "FileDescription", "@SLIC3R_APP_NAME@ G-code Viewer"
|
||||
VALUE "FileVersion", "@SLIC3R_BUILD_ID@"
|
||||
VALUE "ProductName", "@SLIC3R_APP_NAME@ G-code Viewer"
|
||||
VALUE "ProductVersion", "@SLIC3R_BUILD_ID@"
|
||||
VALUE "InternalName", "@SLIC3R_APP_NAME@ G-code Viewer"
|
||||
VALUE "LegalCopyright", ""
|
||||
VALUE "OriginalFilename", "bambu-gcodeviewer.exe"
|
||||
}
|
||||
}
|
||||
BLOCK "VarFileInfo"
|
||||
{
|
||||
VALUE "Translation", 0x409, 1252
|
||||
}
|
||||
}
|
||||
2 ICON "@SLIC3R_RESOURCES_DIR@/images/OrcaSlicer-gcodeviewer.ico"
|
||||
1 24 "OrcaSlicer.manifest"
|
||||
38
src/dev-utils/platform/msw/OrcaSlicer.manifest.in
Normal file
38
src/dev-utils/platform/msw/OrcaSlicer.manifest.in
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" manifestVersion="1.0">
|
||||
<assemblyIdentity version="@SLIC3R_VERSION@" name="Slic3r" type="Win32" />
|
||||
<description>Perl</description>
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity type="Win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0"
|
||||
processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*" />
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- The ID below indicates application support for Windows Vista -->
|
||||
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
|
||||
<!-- The ID below indicates application support for Windows 7 -->
|
||||
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
|
||||
<!-- The ID below indicates application support for Windows 8 -->
|
||||
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
|
||||
<!-- The ID below indicates application support for Windows 8.1 -->
|
||||
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
|
||||
<!-- The ID below indicates application support for Windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
|
||||
</application>
|
||||
</compatibility>
|
||||
<asmv3:application>
|
||||
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2017/WindowsSettings">
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware> <!-- legacy -->
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">permonitorv2,permonitor</dpiAwareness>
|
||||
</asmv3:windowsSettings>
|
||||
</asmv3:application>
|
||||
</assembly>
|
||||
25
src/dev-utils/platform/msw/OrcaSlicer.rc.in
Normal file
25
src/dev-utils/platform/msw/OrcaSlicer.rc.in
Normal file
@@ -0,0 +1,25 @@
|
||||
1 VERSIONINFO
|
||||
FILEVERSION @SLIC3R_VERSION@
|
||||
PRODUCTVERSION @SLIC3R_VERSION@
|
||||
{
|
||||
BLOCK "StringFileInfo"
|
||||
{
|
||||
BLOCK "040904E4"
|
||||
{
|
||||
VALUE "CompanyName", "SoftFever"
|
||||
VALUE "FileDescription", "@SLIC3R_APP_NAME@"
|
||||
VALUE "FileVersion", "@SLIC3R_BUILD_ID@"
|
||||
VALUE "ProductName", "@SLIC3R_APP_NAME@"
|
||||
VALUE "ProductVersion", "@SLIC3R_BUILD_ID@"
|
||||
VALUE "InternalName", "@SLIC3R_APP_NAME@"
|
||||
VALUE "LegalCopyright", ""
|
||||
VALUE "OriginalFilename", "orca-slicer.exe"
|
||||
}
|
||||
}
|
||||
BLOCK "VarFileInfo"
|
||||
{
|
||||
VALUE "Translation", 0x409, 1252
|
||||
}
|
||||
}
|
||||
2 ICON "@SLIC3R_RESOURCES_DIR@/images/OrcaSlicer.ico"
|
||||
1 24 "OrcaSlicer.manifest"
|
||||
139
src/dev-utils/platform/osx/Info.plist.in
Normal file
139
src/dev-utils/platform/osx/Info.plist.in
Normal file
@@ -0,0 +1,139 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>@SLIC3R_APP_KEY@</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>@SLIC3R_APP_NAME@ Copyright(C) 2021-2023 Lunkuo All Rights Reserved</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>images/OrcaSlicer.icns</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>@SLIC3R_APP_KEY@</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>@SLIC3R_APP_NAME@ @SLIC3R_BUILD_ID@</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.softfever3d.orca-slic3r/</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>@SLIC3R_BUILD_ID@</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<key>ATSApplicationFontsPath</key>
|
||||
<string>fonts/</string>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>orcasliceropen url</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>orcasliceropen</string>
|
||||
<string>orcaslicer</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>stl</string>
|
||||
<string>STL</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>images/stl.icns</string>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>STL</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>LISsAppleDefaultForType</key>
|
||||
<true/>
|
||||
<key>LSHandlerRank</key>
|
||||
<string>Alternate</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>obj</string>
|
||||
<string>OBJ</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>images/OrcaSlicer.icns</string>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>STL</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>LISsAppleDefaultForType</key>
|
||||
<true/>
|
||||
<key>LSHandlerRank</key>
|
||||
<string>Alternate</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>amf</string>
|
||||
<string>AMF</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>images/OrcaSlicer.icns</string>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>AMF</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>LISsAppleDefaultForType</key>
|
||||
<true/>
|
||||
<key>LSHandlerRank</key>
|
||||
<string>Alternate</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>3mf</string>
|
||||
<string>3MF</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>images/OrcaSlicer.icns</string>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>3MF</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>LISsAppleDefaultForType</key>
|
||||
<true/>
|
||||
<key>LSHandlerRank</key>
|
||||
<string>Alternate</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>gcode</string>
|
||||
<string>GCODE</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>images/gcode.icns</string>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>GCODE</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>LISsAppleDefaultForType</key>
|
||||
<true/>
|
||||
<key>LSHandlerRank</key>
|
||||
<string>Alternate</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.10</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true/>
|
||||
<key>LSEnvironment</key>
|
||||
<dict>
|
||||
<key>ASAN_OPTIONS</key>
|
||||
<string>detect_container_overflow=0</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
9
src/dev-utils/platform/osx/entitlements.plist
Normal file
9
src/dev-utils/platform/osx/entitlements.plist
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<!-- for dynamic loading of libraries without signature validation. Used for 3dconnection drivers.-->
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
9
src/dev-utils/platform/unix/BambuGcodeviewer.desktop
Normal file
9
src/dev-utils/platform/unix/BambuGcodeviewer.desktop
Normal file
@@ -0,0 +1,9 @@
|
||||
[Desktop Entry]
|
||||
Name=Bambu GCode viewer
|
||||
Exec=orca-slicer --gcodeviewer %F
|
||||
Icon=OrcaSlicer-gcodeviewer
|
||||
Terminal=false
|
||||
Type=Application
|
||||
MimeType=text/x.gcode;
|
||||
Categories=Graphics;3DGraphics;
|
||||
Keywords=3D;Printing;Slicer;
|
||||
12
src/dev-utils/platform/unix/OrcaSlicer.desktop
Normal file
12
src/dev-utils/platform/unix/OrcaSlicer.desktop
Normal file
@@ -0,0 +1,12 @@
|
||||
[Desktop Entry]
|
||||
Name=OrcaSlicer
|
||||
GenericName=3D Printing Software
|
||||
Icon=OrcaSlicer
|
||||
Exec=orca-slicer %U
|
||||
Terminal=false
|
||||
Type=Application
|
||||
MimeType=model/stl;model/3mf;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;application/x-amf;x-scheme-handler/orcaslicer;
|
||||
Categories=Graphics;3DGraphics;Engineering;
|
||||
Keywords=3D;Printing;Slicer;slice;3D;printer;convert;gcode;stl;obj;amf;SLA
|
||||
StartupNotify=false
|
||||
StartupWMClass=orca-slicer
|
||||
39
src/dev-utils/platform/unix/build_appimage.sh.in
Normal file
39
src/dev-utils/platform/unix/build_appimage.sh.in
Normal file
@@ -0,0 +1,39 @@
|
||||
#!/bin/sh
|
||||
APPIMAGETOOLURL="https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-$(uname -m).AppImage"
|
||||
|
||||
|
||||
APP_IMAGE="@SLIC3R_APP_KEY@_Linux_V@SoftFever_VERSION@.AppImage"
|
||||
|
||||
wget ${APPIMAGETOOLURL} -O ../appimagetool.AppImage
|
||||
chmod +x ../appimagetool.AppImage
|
||||
|
||||
if [ -f /.dockerenv ] ; then # Only run if inside of a Docker Container
|
||||
sed '0,/AI\x02/{s|AI\x02|\x00\x00\x00|}' -i ../appimagetool.AppImage
|
||||
fi
|
||||
|
||||
sed -i -e 's#/usr#././#g' bin/@SLIC3R_APP_CMD@
|
||||
mv @SLIC3R_APP_CMD@ AppRun
|
||||
chmod +x AppRun
|
||||
|
||||
cp resources/images/@SLIC3R_APP_KEY@_192px.png @SLIC3R_APP_KEY@.png
|
||||
mkdir -p usr/share/icons/hicolor/192x192/apps
|
||||
cp resources/images/@SLIC3R_APP_KEY@_192px.png usr/share/icons/hicolor/192x192/apps/@SLIC3R_APP_KEY@.png
|
||||
cat <<EOF > @SLIC3R_APP_KEY@.desktop
|
||||
[Desktop Entry]
|
||||
Name=@SLIC3R_APP_KEY@
|
||||
Exec=AppRun %F
|
||||
Icon=@SLIC3R_APP_KEY@
|
||||
Type=Application
|
||||
Categories=Utility;
|
||||
MimeType=model/stl;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;application/x-amf;
|
||||
EOF
|
||||
|
||||
|
||||
if [ -f /.dockerenv ] ; then # Only run if inside of a Docker Container
|
||||
../appimagetool.AppImage --appimage-extract-and-run . $([ ! -z "${container}" ] && echo '--appimage-extract-and-run')
|
||||
else
|
||||
../appimagetool.AppImage . $([ ! -z "${container}" ] && echo '--appimage-extract-and-run')
|
||||
fi
|
||||
|
||||
mv @SLIC3R_APP_KEY@-$(uname -m).AppImage ${APP_IMAGE}
|
||||
chmod +x ${APP_IMAGE}
|
||||
87
src/dev-utils/platform/unix/build_linux_image.sh.in
Executable file
87
src/dev-utils/platform/unix/build_linux_image.sh.in
Executable file
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
export ROOT=$(echo $ROOT | grep . || pwd)
|
||||
export NCORES=`nproc --all`
|
||||
|
||||
while getopts ":ih" opt; do
|
||||
case ${opt} in
|
||||
i )
|
||||
export BUILD_IMAGE="1"
|
||||
;;
|
||||
h ) echo "Usage: ./build_linux_image.sh [-i]"
|
||||
echo " -i: Generate Appimage (optional)"
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo -n "[9/9] Generating Linux app..."
|
||||
#{
|
||||
# create directory and copy into it
|
||||
if [ -d "package" ]
|
||||
then
|
||||
rm -rf package/*
|
||||
rm -rf package/.* 2&>/dev/null
|
||||
else
|
||||
mkdir package
|
||||
fi
|
||||
mkdir package/bin
|
||||
|
||||
# copy Resources
|
||||
cp -Rf ../resources package/resources
|
||||
cp -f src/@SLIC3R_APP_CMD@ package/bin/@SLIC3R_APP_CMD@
|
||||
# remove unneeded po from resources
|
||||
## find package/resources/localization -name "*.po" -type f -delete ## FIXME: DD - do we need this?
|
||||
|
||||
# create bin
|
||||
cat << EOF >@SLIC3R_APP_CMD@
|
||||
#!/bin/bash
|
||||
DIR=\$(readlink -f "\$0" | xargs dirname)
|
||||
export LD_LIBRARY_PATH="\$DIR/bin:\$LD_LIBRARY_PATH"
|
||||
|
||||
# FIXME: OrcaSlicer segfault workarounds
|
||||
# 1) OrcaSlicer will segfault on systems where locale info is not as expected (i.e. Holo-ISO arch-based distro)
|
||||
export LC_ALL=C
|
||||
|
||||
if [ "\$XDG_SESSION_TYPE" = "wayland" ] && [ "\$ZINK_DISABLE_OVERRIDE" != "1" ]; then
|
||||
if command -v glxinfo >/dev/null 2>&1; then
|
||||
RENDERER=\$(glxinfo | grep "OpenGL renderer string:" | sed 's/.*: //')
|
||||
if echo "\$RENDERER" | grep -qi "NVIDIA"; then
|
||||
if command -v nvidia-smi >/dev/null 2>&1; then
|
||||
DRIVER_VERSION=\$(nvidia-smi --query-gpu=driver_version --format=csv,noheader | head -n1)
|
||||
DRIVER_MAJOR=\$(echo "\$DRIVER_VERSION" | cut -d. -f1)
|
||||
[ "\$DRIVER_MAJOR" -gt 555 ] && ZINK_FORCE_OVERRIDE=1
|
||||
fi
|
||||
if [ "\$ZINK_FORCE_OVERRIDE" = "1" ]; then
|
||||
export __GLX_VENDOR_LIBRARY_NAME=mesa
|
||||
export __EGL_VENDOR_LIBRARY_FILENAMES=/usr/share/glvnd/egl_vendor.d/50_mesa.json
|
||||
export MESA_LOADER_DRIVER_OVERRIDE=zink
|
||||
export GALLIUM_DRIVER=zink
|
||||
export WEBKIT_DISABLE_DMABUF_RENDERER=1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
exec "\$DIR/bin/@SLIC3R_APP_CMD@" "\$@"
|
||||
EOF
|
||||
|
||||
chmod ug+x @SLIC3R_APP_CMD@
|
||||
cp -f @SLIC3R_APP_CMD@ package/@SLIC3R_APP_CMD@
|
||||
pushd package > /dev/null
|
||||
tar -cvf ../@SLIC3R_APP_KEY@.tar . &>/dev/null
|
||||
popd > /dev/null
|
||||
#} &> $ROOT/Build.log # Capture all command output
|
||||
echo "done"
|
||||
|
||||
if [[ -n "$BUILD_IMAGE" ]]
|
||||
then
|
||||
echo -n "Creating Appimage for distribution..."
|
||||
#{
|
||||
pushd package > /dev/null
|
||||
chmod +x ../build_appimage.sh
|
||||
../build_appimage.sh
|
||||
popd > /dev/null
|
||||
mv package/"@SLIC3R_APP_KEY@_Linux_V@SoftFever_VERSION@.AppImage" "@SLIC3R_APP_KEY@_Linux_V@SoftFever_VERSION@.AppImage"
|
||||
#} &> $ROOT/Build.log # Capture all command output
|
||||
echo "done"
|
||||
fi
|
||||
2
src/dev-utils/platform/unix/fhs.hpp.in
Normal file
2
src/dev-utils/platform/unix/fhs.hpp.in
Normal file
@@ -0,0 +1,2 @@
|
||||
#cmakedefine SLIC3R_FHS @SLIC3R_FHS@
|
||||
#define SLIC3R_FHS_RESOURCES "@SLIC3R_FHS_RESOURCES@"
|
||||
Reference in New Issue
Block a user