ANSI APIs in 64-bit code

Here you can propose new features, make suggestions etc.

Moderators: white, Hacker, petermad, Stefan2

Post Reply
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

ANSI APIs in 64-bit code

Post by *MarcinW »

According to this thread, using ANSI APIs in 64-bit code (in particular when handling file names, network names, current user name) may lead to problems, in particular due to data loss during conversion from the native Unicode string to an ANSI string (this is true also for 32-bit code, running on NT platforms, but the operating system launches them on a WoW64 subsystem, so some problems may never occur for 32-bit applications, since they are handled in a special way).


Sometimes ANSI versions must be used, even in 64-bit code, to work properly (in particular when interacting with ANSI windows - possibly created by other applications):

Code: Select all

if IsWindowUnicode(Wnd) then
  SendMessageW(Wnd, ...)
else
  SendMessageA(Wnd, ...);
Sometimes it doesn't matter, if either ANSI or Unicode version is used:

Code: Select all

Handle:=GetModuleHandleA('kernel32.dll');
Handle:=GetModuleHandleW('kernel32.dll');
But sometimes using ANSI functions may lead to errors. So I dumped all ANSI imports from 64-bit TC executables (TC 9.12 RC4) - you may want to review them sometime. It may be possible, that changing them to Unicode versions will fix some weird, hard to diagnose problems, that haven't been even detected yet.



Noclose64.exe:

Code: Select all

CreateProcessA
FreeEnvironmentStringsA
GetCommandLineA
GetEnvironmentStrings (this name exists simultaneously with GetEnvironmentStringsA)
GetLocaleInfoA
GetModuleFileNameA
GetModuleHandleA
GetStartupInfoA
GetStringTypeA
GetVersionExA
LCMapStringA
LoadLibraryA
Tclzma64.dll:

Code: Select all

CreateEventA
CreateSemaphoreA
FreeEnvironmentStringsA
GetCommandLineA
GetEnvironmentStrings (this name exists simultaneously with GetEnvironmentStringsA)
GetLocaleInfoA
GetModuleFileNameA
GetModuleHandleA
GetStartupInfoA
GetStringTypeA
GetVersionExA
LCMapStringA
LoadLibraryA
Tcmadm64.exe:

Code: Select all

CreateFileA
CreateNamedPipeA
FreeEnvironmentStringsA
GetCommandLineA
GetEnvironmentStrings (this name exists simultaneously with GetEnvironmentStringsA)
GetLocaleInfoA
GetModuleFileNameA
GetModuleHandleA
GetStartupInfoA
GetStringTypeA
GetSystemDirectoryA
GetUserNameA
GetVersionExA
GetWindowsDirectoryA
LCMapStringA
LoadLibraryA
LoadLibraryExA
LookupAccountNameA
LookupPrivilegeValueA
MessageBoxA
WaitNamedPipeA
Tcmdx64.exe:

Code: Select all

CreateFileA
CreateFontIndirectA
CreateNamedPipeA
CreateWindowExA
DefWindowProcA
DispatchMessageA
FreeEnvironmentStringsA
GetCommandLineA
GetEnvironmentStrings (this name exists simultaneously with GetEnvironmentStringsA)
GetLocaleInfoA
GetMenuItemInfoA
GetModuleFileNameA
GetModuleHandleA
GetObjectA
GetStartupInfoA
GetStringTypeA
GetVersionExA
LCMapStringA
LoadLibraryA
MessageBoxA
PeekMessageA
RegEnumKeyA
RegisterClassExA
RegOpenKeyA
RegQueryValueA
SystemParametersInfoA
WaitNamedPipeA
WriteConsoleA
Tcunin64.exe:

Code: Select all

CharPrevA
CharUpperA
CreateDirectoryA
CreateEventA
CreateFileA
CreateFontA
DeleteFileA
DialogBoxParamA
DispatchMessageA
EnumResourceLanguagesA
EnumResourceNamesA
EnumResourceTypesA
FindFirstFileA
FindNextFileA
FindResourceA
FindResourceExA
FindWindowA
GetCommandLineA
GetEnvironmentVariableA
GetFileAttributesA
GetModuleFileNameA
GetModuleHandleA
GetPrivateProfileIntA
GetPrivateProfileStringA
GetStartupInfoA
GetTempFileNameA
GetTempPathA
GetVersionExA
GetWindowsDirectoryA
LoadLibraryA
MessageBoxA
MoveFileA
PeekMessageA
PostMessageA
RegDeleteKeyA
RegOpenKeyExA
RegQueryValueExA
RemoveDirectoryA
SendDlgItemMessageA
SetCurrentDirectoryA
SetDlgItemTextA
Tcunzl64.dll:

Code: Select all

CreateFileA
FindFirstFileA
FreeEnvironmentStringsA
GetCommandLineA
GetEnvironmentStrings (this name exists simultaneously with GetEnvironmentStringsA)
GetLocaleInfoA
GetModuleFileNameA
GetModuleHandleA
GetStartupInfoA
GetStringTypeA
GetVersionExA
LCMapStringA
LoadLibraryA
WriteConsoleA
Totalcmd64.exe:

Code: Select all

AppendMenuA
CallWindowProcA
CharLowerA
CharLowerBuffA
CharNextA
CharNextExA
CharPrevA
CharPrevExA
CharToOemA
CharToOemBuffA
CharUpperA
CharUpperBuffA
ChooseColorA
ChooseFontA
CompareStringA
CopyFileA
CreateDCA
CreateDialogParamA
CreateDirectoryA
CreateEventA
CreateFileA
CreateFileMappingA
CreateFontA
CreateFontIndirectA
CreateMutexA
CreateProcessA
CreateSemaphoreA
CreateServiceA
CreateWindowExA
DefWindowProcA
DeleteFileA
DeviceCapabilitiesA
DispatchMessageA
DocumentPropertiesA
DragQueryFileA
DrawStateA
DrawTextA
EnumCalendarInfoA
EnumFontFamiliesA
EnumFontFamiliesExA
EnumFontsA
EnumPrintersA
EnumPropsA
EnumResourceLanguagesA
EnumResourceNamesA
EnumResourceTypesA
ExpandEnvironmentStringsA
ExtractIconA
ExtTextOutA
FindExecutableA
FindFirstFileA
FindNextFileA
FindResourceA
FindResourceExA
FindWindowA
FormatMessageA
FreeEnvironmentStringsA
GetCharABCWidthsA
GetClassInfoA
GetClassLongA
GetClassNameA
GetClipboardFormatNameA
GetCommandLineA
GetComputerNameA
GetCurrentDirectoryA
GetDateFormatA
GetDiskFreeSpaceA
GetDlgItemTextA
GetDriveTypeA
GetEnvironmentStringsA
GetEnvironmentVariableA
GetFileAttributesA
GetFileVersionInfoA
GetFileVersionInfoSizeA
GetLocaleInfoA
GetMenuItemInfoA
GetMenuStringA
GetMessageA
GetModuleFileNameA
GetModuleHandleA
GetObjectA
GetOpenFileNameA
GetPrinterA
GetPrivateProfileIntA
GetPrivateProfileSectionA
GetPrivateProfileStringA
GetProfileIntA
GetProfileStringA
GetPropA
GetSaveFileNameA
GetShortPathNameA
GetStartupInfoA
GetSystemDirectoryA
GetTabbedTextExtentA
GetTempFileNameA
GetTempPathA
GetTextExtentExPointA
GetTextExtentPoint32A
GetTextExtentPointA
GetTextMetricsA
GetUserNameA
GetVersionExA
GetVolumeInformationA
GetWindowLongA
GetWindowLongPtrA
GetWindowsDirectoryA
GetWindowTextA
GetWindowTextLengthA
GlobalAddAtomA
InsertMenuA
InsertMenuItemA
IsBadStringPtrA
IsCharAlphaA
IsCharAlphaNumericA
IsDialogMessageA
LCMapStringA
LoadBitmapA
LoadCursorA
LoadIconA
LoadImageA
LoadKeyboardLayoutA
LoadLibraryA
LoadLibraryExA
LoadStringA
LookupAccountSidA
LookupPrivilegeValueA
MapVirtualKeyA
MessageBoxA
ModifyMenuA
MoveFileA
OemToCharA
OemToCharBuffA
OpenDesktopA
OpenMutexA
OpenPrinterA
OpenSCManagerA
OpenServiceA
OutputDebugStringA
PageSetupDlgA
PeekMessageA
PlaySoundA
PostMessageA
PrintDlgA
QueryServiceConfigA
RegCreateKeyA
RegCreateKeyExA
RegDeleteKeyA
RegDeleteValueA
RegEnumKeyA
RegEnumValueA
RegisterClassA
RegisterClipboardFormatA
RegisterWindowMessageA
RegOpenKeyA
RegOpenKeyExA
RegQueryValueA
RegQueryValueExA
RegSetValueA
RegSetValueExA
RemoveDirectoryA
RemovePropA
SendDlgItemMessageA
SendMessageA
SendMessageTimeoutA
SetClassLongA
SetClassLongPtrA
SetCurrentDirectoryA
SetDlgItemTextA
SetEnvironmentVariableA
SetFileAttributesA
SetMenuItemInfoA
SetPropA
SetVolumeLabelA
SetWindowLongA
SetWindowLongPtrA
SetWindowsHookExA
SetWindowTextA
Shell_NotifyIconA
ShellExecuteA
ShellExecuteExA
SHFileOperationA
SHGetFileInfoA
StartDocA
StartDocPrinterA
StartServiceA
SystemParametersInfoA
TabbedTextOutA
TextOutA
UnregisterClassA
VerQueryValueA
WinHelpA
WNetAddConnection3A
WNetCancelConnectionA
WNetEnumResourceA
WNetGetConnectionA
WNetGetUserA
WNetOpenEnumA
WritePrivateProfileSectionA
WritePrivateProfileStringA
wvsprintfA
Wcmzip64.dll:

Code: Select all

CreateFileA
CreateMutexA
DispatchMessageA
FreeEnvironmentStringsA
GetCommandLineA
GetEnvironmentStrings (this name exists simultaneously with GetEnvironmentStringsA)
GetLocaleInfoA
GetModuleFileNameA
GetModuleHandleA
GetStartupInfoA
GetStringTypeA
GetVersionExA
IsDialogMessageA
LCMapStringA
LoadLibraryA
PeekMessageA
SendMessageA
WriteConsoleA
User avatar
MVV
Power Member
Power Member
Posts: 8702
Joined: 2008-08-03, 12:51 UTC
Location: Russian Federation

Post by *MVV »

I suppose these files just share same sources with 32-bit versions and call best available functions. Anyway, runtime that is embedded by compilator may use ANSI functions itself so there is no way to completely get rid of them.

As I know, 64-bit ANSI functions work absolutely like 32-bit ones, and 32-bit ones internally just call 64-bit functions. So it is safe to use most ANSI functions, especially when you work with ANSI strings. The most important difference appears when you use Unicode functions with special prefix \\?\ - this prefix disables path preprocessing that is used for old school paths w/o this prefix.

However it really seems that some errors may occur when you use ANSI functions in areas where Unicode strings may be returned.
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

As you said, compiler is not a problem, because it should choose APIs dynamically, and call a best version for the specific purpose.

You are also right, that 64-bit ANSI functions should work like 32-bit ANSI functions. However, 32-bit ANSI functions use an indirection layer, WoW64 - this makes some differences, like redirecting c:\Windows\System32 to c:\Windows\SysWOW64.

I can only suppose, that system DLLs in SysWOW64 have some special, additional code, to solve some problems when using ANSI APIs. Such an additional code might be omitted in 64-bit system DLLs, since 64-bit code is expected to use Unicode APIs in all possible cases. After all, there must be some reason, why WNetEnumResourceA crashes 64-bit TC, but not 32-bit TC.

From the other side, this crash may also depend on different runtime libraries (i.e. different internal string handling) used by the 32-bit and the 64-bit compiler.

However, changing ANSI APIs to Unicode in 64-bit code (when the specific case doesn't need an ANSI version) is always a step in the right direction.

Regards
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 48077
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

TC 32-bit and 64-bit share a lot of code. Therefore there are a lot of constructs like this:
if (NT based system)
use Wide Char function
else
use ANSI function

These cost almost no processor time or program size, so it's not worth to eliminate them all.

In the linked thread, the ANSI functions were used because \\tsclient should only return two types of shares:
1. Drives in the form C, D, etc.
2. Admin shares in the form C$, D$ etc.

None of these use characters from foreign codepages - and TC would ignore them anyway. I don't haven any explanation why the user gets a crash here. Unicode to Ansi conversion doesn't crash unless there is a buffer overflow, but that would be a bug in Windows itself...
Author of Total Commander
https://www.ghisler.com
User avatar
MVV
Power Member
Power Member
Posts: 8702
Joined: 2008-08-03, 12:51 UTC
Location: Russian Federation

Post by *MVV »

ghisler(Author) wrote:but that would be a bug in Windows itself...
It may easilly be the case 'cause he uses Windows 10...
Post Reply