This mighty Cheb finally wrangled unicode paths into submission!
I've successfully ran my engine in GL ES 2 mode from a folder named D:\/人◕‿‿◕人\ while it contains ANGLE DLLs ripped from old Firefox, which are NOT unicode - i.e. they crash and burn if loaded from a path not representable in the system 8-bit encoding (CP1251 in my case).
This is how:
Code:
function GetAnsiSafePath(s: TFileNameString): TFileNameString;
{$ifndef windows}
begin
Result:= s;
end;
{$else}
// ASSUMING that the file name is safe anyway
var
u, b: UnicodeString;
reqlen: dword;
fn, pt: TFileNameString;
a: Array of UnicodeString;
i: integer;
begin
if Length(s) = 0 then Exit(s);
fn:= ExtractFileName(s);
// first, optimize the path correcting slashes and collapsing all '\..\'
pt:= OptiPath(ExtractFilePath(s));
u:= FileNameToUnicode(pt);
if IsPathAnsiSafe(u) then Exit(s);
a:= Explode('\', u);
u:= a[0] + '\'; // assuming its the drive letter, not checking
for i:= 1 to High(a) - 1 do begin
u+= a[i] + '\';
if IsPathAnsiSafe(u) then continue;
reqlen:= GetShortPathNameW(@u[1], nil, 0); //msdn sayd NOT INCLUDING
// the terminating #0 but then where does that extra space
// come from?
if reqlen = 0 then begin
GetLastError; // clear the error message
Exit(s);
end;
SetLength(b, reqlen); // automatically creates extra space for the terminating zero
SetLength(b, GetShortPathNameW(@u[1], @b[1], reqlen + 1));
if Length(b) = 0 then Exit(s);
u:= b;
end;
Result:= UnicodeToFileName(u) + fn;
end;
{$endif}
, where OptiPath is my custom path parser that collapses relative paths containing '\..\', UnicodeToFileName and so on are from my chtonic patch for fpc where TFileNameString = Utf8String even in Windows (I don't use lazarus libraries, implemented everything on my own) and IsPathAnsiSafe is this:
Code:
function IsPathAnsiSafe(u: UnicodeString): boolean;
{$ifndef windows}
begin Result:= Yes end;
{$else windows}
var
a: UnicodeString;
b: AnsiString;
i: integer;
res: longbool;
ac: AnsiChar;
begin
if Length(u) < 1 then Exit(Yes);
res:= false;
i:= WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK or WC_DISCARDNS,
@u[1], length(u), nil, 0, nil, nil);
if i < 1 then Exit(Yes); // graceful degradation
SetLength(b, i);
ac:= #7;
WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK or WC_DISCARDNS,
@u[1], length(u), @b[1], i, @ac, @res);
Result:= Yes;
for i:= 1 to Length(b) do
if ord(b[i]) < 32 then begin
Result:= No;
break;
end;
end;
{$endif windows}
Aaaand, it worked!
Loading d:\84BC~1\3rdparty\ANGLE\win32\libGLESv2.dll...Ok, d:\84BC~1\3rdparty\ANGLE\win32\libGLESv2.dll
Loading d:\84BC~1\3rdparty\ANGLE\win32\libEGL.dll...Ok, d:\84BC~1\3rdparty\ANGLE\win32\libEGL.dll
Loading the procedure addresses from the GL ES DLL ...
glActiveTexture() at 5F1742C0h in d:\84BC~1\3rdparty\ANGLE\win32\libGLESv2.dll
glAttachShader() at 5F1742C5h in d:\84BC~1\3rdparty\ANGLE\win32\libGLESv2.dll
glBindAttribLocation() at 5F1742CAh in d:\84BC~1\3rdparty\ANGLE\win32\libGLESv2.dll
glBindBuffer() at 5F1742CFh in d:\84BC~1\3rdparty\ANGLE\win32\libGLESv2.dll
P.S. I had unhealthy obsession with redefining true and false as "Yes" and "No". I still follow this in my engine as it became standard.
P.P.S. This was a big problem in WinXP as it used user's name for that user's home directory. Use one non-unicode character and suddenly lots of software crash on you. Including anything compiled in fpc.
I'm not sure if later windozes resolved that.
Bookmarks