src\mcrt.c
// _ __ _____ _________ _ __ _ __ ___
// | '_ \ / _ \ \ /\ / /_ / _ \| '__| '__/ _ \
// | | | | (_) \ V V / / / (_) | | | | | (_) |
// |_| |_|\___/ \_/\_/ /___\___/|_| |_| \___/
//
//
// https://nowzorro.blogspot.com/2016/11/total-commander-starter.html
// Version: 2017-05-22
//
#include
#if _WIN64
#pragma function(memset)
void* __cdecl memset(void *dest, int value, size_t num)
{
unsigned char *p = dest;
while (num-- > 0)
*p++ = (unsigned char)value;
return dest;
}
#pragma function(memcpy)
void* __cdecl memcpy(void *dest, const void *source, size_t num)
{
char *pd = dest;
const char *ps = source;
while (num-- > 0)
*pd++ = *ps++;
return dest;
}
#pragma function(wcslen)
size_t __cdecl wcslen(const wchar_t *str)
{
size_t len = 0;
while (*str++)
++len;
return len;
}
#pragma function(strlen)
size_t __cdecl strlen(const char *str)
{
size_t len = 0;
while (*str++)
++len;
return len;
}
#else // _WIN32
#pragma function(memset)
void* __cdecl memset(void *dest, int value, size_t num)
{
_asm
{
push ecx
push edi
mov eax, value
mov ecx, num
mov edi, dest
rep stosb
pop edi
pop ecx
}
return dest;
}
#pragma function(memcpy)
void* __cdecl memcpy(void *dest, const void *source, size_t num)
{
_asm
{
push ecx
push edi
push esi
mov ecx, num
mov edi, dest
mov esi, source
rep movsb
pop esi
pop edi
pop ecx
}
return dest;
}
#pragma function(wcslen)
size_t __cdecl wcslen(const wchar_t *s)
{
_asm
{
push edi
mov edi, s
sub ecx, ecx
not ecx
sub ax, ax
cld
repne scasw
not ecx
pop edi
lea eax, [ecx-1]
}
}
#pragma function(strlen)
size_t __cdecl strlen(const char *s)
{
_asm
{
push edi
mov edi, s
sub ecx, ecx
not ecx
sub al, al
cld
repne scasb
not ecx
pop edi
lea eax, [ecx-1]
}
}
#endif // _WIN64
src\tc_starter.c
// _ __ _____ _________ _ __ _ __ ___
// | '_ \ / _ \ \ /\ / /_ / _ \| '__| '__/ _ \
// | | | | (_) \ V V / / / (_) | | | | | (_) |
// |_| |_|\___/ \_/\_/ /___\___/|_| |_| \___/
//
//
// https://nowzorro.blogspot.com/2016/11/total-commander-starter.html
// Version: 2017-05-22
//
#include
#define INIT_WAIT_TIMEOUT 5000
#define TRY_FIND_TIMEOUT 5000
#define TRY_FIND_SLEEP 10
#define TRY_FIND_COUNT (TRY_FIND_TIMEOUT / TRY_FIND_SLEEP)
enum
{
E_OK = 0,
E_RUN,
E_HOOK,
E_BTN
};
const TCHAR *MESSAGE[] =
{
0,
TEXT("Cannot run Total Commander."),
TEXT("Initialization hook error."),
TEXT("Button window not found")
};
const TCHAR *NAG_CLASS = TEXT("TNASTYNAGSCREEN");
const TCHAR *NAG_TITLE = TEXT("Total Commander");
#if _WIN64
const TCHAR *PATHS[] =
{
TEXT("TOTALCMD64.EXE"),
TEXT("c:\\totalcmd\\TOTALCMD64.EXE"),
TEXT("c:\\Program Files\\totalcmd\\TOTALCMD64.EXE")
};
const TCHAR *TITLES[] =
{
TEXT("Window"),
TEXT("Window"),
TEXT("Window"),
TEXT("Window"),
TEXT("Button")
};
#else // !_WIN64
const TCHAR *PATHS[] =
{
TEXT("TOTALCMD.EXE"),
TEXT("c:\\totalcmd\\TOTALCMD.EXE"),
TEXT("c:\\Program Files\\totalcmd\\TOTALCMD.EXE")
};
const TCHAR *TITLES[] =
{
TEXT("TNotebook"),
TEXT("TPage"),
TEXT("TPanel"),
TEXT("TPanel"),
TEXT("TButton")
};
#endif // _WIN64
extern void* __cdecl memset(void*, int, size_t);
extern void* __cdecl memcpy(void*, const void*, size_t);
extern size_t __cdecl wcslen(const wchar_t*);
extern size_t __cdecl strlen(const char*);
#ifdef _UNICODE
#define tcslen wcslen
#else
#define tcslen strlen
#endif
// Return process handle
HANDLE runProcess(const TCHAR *path)
{
TCHAR buf[MAX_PATH];
size_t size = tcslen(path) * sizeof(TCHAR);
if (!size || size >= sizeof(buf))
return NULL;
memset(&buf, 0, sizeof(buf));
memcpy(&buf, path, size);
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
memset(&pi, 0, sizeof(pi));
if (!CreateProcess(NULL, buf, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
return NULL;
CloseHandle(pi.hThread);
return pi.hProcess;
}
TCHAR* skipClExePath(TCHAR *s)
{
if (TEXT('"') == *s)
{
++s;
for (; *s && *s != TEXT('"'); ++s);
if (TEXT('"') == *s)
++s;
}
else
for (; *s > TEXT(' '); ++s);
for (; *s && *s <= TEXT(' '); ++s);
return s;
}
HWND findNearLabel(HWND hParent)
{
const TCHAR *LBL_CLASS = TITLES[_countof(TITLES) - 2];
const TCHAR *BTN_CLASS = TITLES[_countof(TITLES) - 1];
TCHAR title[3] = TEXT("&\0");
HWND hLabel = NULL;
while (hLabel = FindWindowEx(hParent, hLabel, LBL_CLASS, NULL))
{
int len = (int)GetWindowText(hLabel, &title[1], 2);
if ((len == 1) &&
((title[1] == '1') || (title[1] == '2') || (title[1] == '3')))
{
return FindWindowEx(hParent, NULL, BTN_CLASS, title);
}
}
return NULL;
}
HWND scanSubTreeWnd(HWND hParent, size_t titleZIndex)
{
HWND hChild = NULL;
while (hChild = FindWindowEx(hParent, hChild, TITLES[titleZIndex], NULL))
{
if (titleZIndex == _countof(TITLES) - 3)
return findNearLabel(hChild);
HWND ret = scanSubTreeWnd(hChild, titleZIndex + 1);
if (ret)
return ret;
}
return NULL;
}
int work(TCHAR *commandLine)
{
HANDLE hProcess = 0;
if (!commandLine || commandLine[0] == TEXT('\0'))
{
for (size_t i = 0; i < _countof(PATHS) && !hProcess; i++)
hProcess = runProcess(PATHS[i]);
}
else
hProcess = runProcess(commandLine);
if (!hProcess)
return E_RUN;
// Wait until app has finished initialization
if (WaitForInputIdle(hProcess, INIT_WAIT_TIMEOUT) != 0)
{
CloseHandle(hProcess);
return E_HOOK;
}
CloseHandle(hProcess);
// Find windows
HWND hParent = NULL;
HWND hButton = NULL;
for (size_t i = TRY_FIND_COUNT; i--; Sleep(TRY_FIND_SLEEP))
{
if (!hParent)
hParent = FindWindow(NAG_CLASS, NAG_TITLE);
if (!hParent)
continue;
if (hButton = scanSubTreeWnd(hParent, 0))
{
SetForegroundWindow(hParent);
SendMessage(hButton, WM_LBUTTONDOWN, 0, 0);
SendMessage(hButton, WM_LBUTTONUP, 0, 0);
return E_OK;
}
}
return E_BTN;
}
void WINAPI main()
{
TCHAR *cl = GetCommandLine();
cl = skipClExePath(cl);
int ret = work(cl);
if (ret != E_OK)
MessageBox(NULL, MESSAGE[ret], TEXT("Error"), MB_OK | MB_ICONERROR);
ExitProcess(ret);
}
make.cmd
:: _ __ _____ _________ _ __ _ __ ___
:: | '_ \ / _ \ \ /\ / /_ / _ \| '__| '__/ _ \
:: | | | | (_) \ V V / / / (_) | | | | | (_) |
:: |_| |_|\___/ \_/\_/ /___\___/|_| |_| \___/
::
:: Usage: this.cmd [x64] [ansi]
::
@echo off
:: Parse params
:PARSE_PARAMS_LOOP
if (%1)==(x64) set NOWZORRO_ARCH=amd64
if (%1)==(ansi) set NOWZORRO_ANSI=A
shift
if (%1)==() goto :PARAMS_PARSED
goto :PARSE_PARAMS_LOOP
:PARAMS_PARSED
:: Init
if not (%NOWZORRO_ARCH%)==() (
set NOWZORRO_PATHSUF=\x64
set NOWZORRO_OUTSUF=64
set NOWZORRO_CL=
set NOWZORRO_LINK=/SUBSYSTEM:WINDOWS,5.02
) else (
set NOWZORRO_ARCH=x86
set NOWZORRO_PATHSUF=
set NOWZORRO_OUTSUF=
set NOWZORRO_CL=/GL
set NOWZORRO_LINK=/SUBSYSTEM:WINDOWS,5.01 /LTCG
)
:: XP Toolset
set SDK71PATH=%ProgramFiles%\Microsoft SDKs\Windows\7.1A
path %SDK71PATH%\Bin%NOWZORRO_PATHSUF%;%PATH%
set CL=%NOWZORRO_CL% /W3 /O1 /GF /GS- /MT /EHsa- ^
/D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D_USING_V110_SDK71_
if (%NOWZORRO_ANSI%)==() set CL=%CL% /D "_UNICODE" /D "UNICODE"
set LINK=%NOWZORRO_LINK% /OPT:REF /OPT:ICF /DYNAMICBASE:NO ^
/NXCOMPAT:NO /FIXED /NODEFAULTLIB /MERGE:.rdata=.text /ENTRY:main
set INCLUDE=%INCLUDE%;%SDK71PATH%\Include
set LIB=%LIB%;%SDK71PATH%\Lib%NOWZORRO_PATHSUF%
:: Prepare VC++2017 compiler
set VSPATH=%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community
call "%VSPATH%\Common7\Tools\VsDevCmd.bat" -arch=%NOWZORRO_ARCH%
if errorlevel 1 pause & goto :EOF
:: Build
if not exist bin mkdir bin
cl.exe /nologo src\mcrt.c src\tc_starter.c "kernel32.lib" "user32.lib" ^
/link /NOLOGO /OUT:bin\tc_starter%NOWZORRO_OUTSUF%%NOWZORRO_ANSI%.exe ^
& del *.obj
if errorlevel 1 pause
:EOF
exit
usage.txt
_ __ _____ _________ _ __ _ __ ___
| '_ \ / _ \ \ /\ / /_ / _ \| '__| '__/ _ \
| | | | (_) \ V V / / / (_) | | | | | (_) |
|_| |_|\___/ \_/\_/ /___\___/|_| |_| \___/
1) If TC installed in:
- Current dir
- c:\totalcmd\
- c:\Program Files\totalcmd\
then simple run starter:
tc_starter.exe [-uac]
2) Or set command line parameter in shortcut:
"STARTER_PATH\tc_starter.exe" [-uac] "TOTALCMD_PATH\TOTALCMD.exe"
"STARTER_PATH\tc_starter.exe" [-uac] "TOTALCMD_PATH\TOTALCMD.exe"^
"I=INI_PATH\wincmd.ini"
3) Or use in .bat/.cmd
start "" "STARTER_PATH\tc_starter.exe" [-uac] "TOTALCMD_PATH\TOTALCMD.exe"
start "" "STARTER_PATH\tc_starter.exe" [-uac] "TOTALCMD_PATH\TOTALCMD.exe"^
"I=INI_PATH\wincmd.ini"
cmd /k "STARTER_PATH\tc_starter.exe" [-uac] "TOTALCMD_PATH\TOTALCMD.exe"
cmd /k "STARTER_PATH\tc_starter.exe" [-uac] "TOTALCMD_PATH\TOTALCMD.exe"^
"I=INI_PATH\wincmd.ini"
Note: Use icon from TOTALCMD.exe in shortcut.
No comments:
Post a Comment