@@ -71,6 +71,18 @@ class CDirectoryLine : public CChildWindow
7171 // string for storing a copy of the path with an ellipsis
7272 TCHAR _pathtemp[MAX_PATH + 3 ];
7373
74+ // Wide-char versions of path fields for GDI rendering.
75+ // Paths are stored internally as UTF-8 (char), but GDI ANSI functions
76+ // use the system ANSI code page and cannot render UTF-8 correctly.
77+ // These wide versions are kept in sync with _path/_rootLen and are used
78+ // exclusively for measuring and drawing text via the W GDI variants.
79+ wchar_t _pathW[MAX_PATH + 4 ];
80+ int _pathWLen;
81+ int _rootLenW;
82+ wchar_t _pathtempW[MAX_PATH + 3 ];
83+ wchar_t const * _pathstrW;
84+ int _pathlenW;
85+
7486 // Cached values - colors: active/inactive
7587 COLORREF _backColor;
7688 COLORREF _rootColor;
@@ -132,6 +144,13 @@ class CDirectoryLine : public CChildWindow
132144 this ->_nodeCount = nodeid;
133145 this ->_nodes [this ->_nodeCount ].xright = LAST_NODEX;
134146
147+ // Build wide-char version of path for GDI rendering (paths are UTF-8 internally)
148+ this ->_pathWLen = MultiByteToWideChar (CP_UTF8, 0 , this ->_path ->GetString (), (int )this ->_path ->GetLength (), this ->_pathW , ARRAYSIZE (this ->_pathW ) - 1 );
149+ if (this ->_pathWLen < 0 )
150+ this ->_pathWLen = 0 ;
151+ this ->_pathW [this ->_pathWLen ] = L' \0 ' ;
152+ this ->_rootLenW = MultiByteToWideChar (CP_UTF8, 0 , this ->_path ->GetString (), this ->_rootLen , NULL , 0 );
153+
135154 this ->_sizeCached = FALSE ;
136155 this ->Repaint ();
137156 }
@@ -193,11 +212,13 @@ class CDirectoryLine : public CChildWindow
193212 SIZE sz;
194213 int sizewidth = 0 ;
195214 int pathwidth = 0 ;
215+ // dx holds per-wide-char pixel positions; wide length <= UTF-8 byte length
196216 int dx[MAX_PATH + 3 ];
197- GetTextExtentExPoint (hdc, this ->_path -> GetString (), ( int ) this ->_path -> GetLength () , 0 , NULL , dx, &sz);
217+ GetTextExtentExPointW (hdc, this ->_pathW , this ->_pathWLen , 0 , NULL , dx, &sz);
198218 pathwidth = sz.cx ;
199219 if (this ->_disksize >= 0 )
200220 {
221+ // Size strings are ASCII-only formatted numbers; ANSI call is correct here
201222 GetTextExtentPoint32 (hdc, this ->_sizestrlong ->GetString (), (int )this ->_sizestrlong ->GetLength (), &sz);
202223 sizewidth = sz.cx + 2 ;
203224
@@ -228,50 +249,60 @@ class CDirectoryLine : public CChildWindow
228249 }*/
229250 }
230251
252+ // Map each node's UTF-8 byte offset to its wide-char position for dx indexing.
253+ // Backslashes are always single-byte ASCII in UTF-8 so the positions differ only
254+ // when non-ASCII characters appear before the backslash.
255+ const char * utf8path = this ->_path ->GetString ();
256+ int nodeWPos[MAX_PATH / 2 + 1 ];
257+ for (int i = 0 ; i < this ->_nodeCount ; i++)
258+ {
259+ nodeWPos[i] = MultiByteToWideChar (CP_UTF8, 0 , utf8path, this ->_nodes [i].strpos , NULL , 0 );
260+ }
261+
231262 if (pathwidth <= width)
232263 {
233- this ->_pathstr = this ->_path -> GetString () ;
234- this ->_pathlen = ( int ) this ->_path -> GetLength () ;
264+ this ->_pathstrW = this ->_pathW ;
265+ this ->_pathlenW = this ->_pathWLen ;
235266
236- this ->_rootX = dx[this ->_rootLen - 1 ] + rct.left ;
267+ this ->_rootX = dx[this ->_rootLenW - 1 ] + rct.left ;
237268
238269 for (int i = 0 ; i < this ->_nodeCount ; i++)
239270 {
240- int ppos = this -> _nodes [i]. strpos ;
241- this ->_nodes [i].xright = dx[ppos - 1 ] + rct.left ;
271+ int wpos = nodeWPos [i];
272+ this ->_nodes [i].xright = dx[wpos - 1 ] + rct.left ;
242273 }
243274 }
244275 else
245276 {
246- TCHAR * ostr = this ->_pathtemp ;
277+ wchar_t * ostr = this ->_pathtempW ;
247278 int ostrlen = 0 ;
248279 if (width > this ->_dotsWidth )
249280 {
250- TCHAR const * str = this ->_path -> GetString () ;
251- int strlen = ( int ) this ->_path -> GetLength () ;
281+ wchar_t const * str = this ->_pathW ;
282+ int strlen = this ->_pathWLen ;
252283
253284 int remwidth = width - this ->_dotsWidth ;
254285
255286 int p = 0 ;
256- while (p < strlen && dx[p] <= remwidth && str[p] != TEXT ( ' \\ ' ) )
287+ while (p < strlen && dx[p] <= remwidth && str[p] != L ' \\ ' )
257288 {
258289 ostr[p] = str[p];
259290 p++;
260291 ostrlen++;
261292 }
262- BOOL found = (str[p] == TEXT ( ' \\ ' ) );
293+ BOOL found = (str[p] == L ' \\ ' );
263294
264- while (p < strlen && dx[p] <= remwidth && str[p] == TEXT ( ' \\ ' ) )
295+ while (p < strlen && dx[p] <= remwidth && str[p] == L ' \\ ' )
265296 {
266297 ostr[p] = str[p];
267298 p++;
268299 ostrlen++;
269300 }
270- BOOL whole = (str[p] != TEXT ( ' \\ ' ) );
301+ BOOL whole = (str[p] != L ' \\ ' );
271302
272- ostr[ostrlen++] = TEXT ( ' .' ) ;
273- ostr[ostrlen++] = TEXT ( ' .' ) ;
274- ostr[ostrlen++] = TEXT ( ' .' ) ;
303+ ostr[ostrlen++] = L ' .' ;
304+ ostr[ostrlen++] = L ' .' ;
305+ ostr[ostrlen++] = L ' .' ;
275306
276307 if (found && whole)
277308 {
@@ -287,20 +318,20 @@ class CDirectoryLine : public CChildWindow
287318 {
288319 ostr[ostrlen++] = str[i];
289320 }
290- if (this ->_rootLen > rp)
321+ if (this ->_rootLenW > rp)
291322 {
292- this ->_rootX = dx[this ->_rootLen - 1 ] + rct.left - dx[rp] + this ->_dotsWidth + dx[p - 1 ];
323+ this ->_rootX = dx[this ->_rootLenW - 1 ] + rct.left - dx[rp] + this ->_dotsWidth + dx[p - 1 ];
293324 }
294325 else
295326 {
296327 this ->_rootX = dx[p - 1 ] + rct.left ;
297328 }
298329 for (i = 0 ; i < this ->_nodeCount ; i++)
299330 {
300- int ppos = this -> _nodes [i]. strpos ;
301- if (ppos > rp)
331+ int wpos = nodeWPos [i];
332+ if (wpos > rp)
302333 {
303- this ->_nodes [i].xright = dx[ppos - 1 ] + rct.left - dx[rp] + this ->_dotsWidth + dx[p - 1 ];
334+ this ->_nodes [i].xright = dx[wpos - 1 ] + rct.left - dx[rp] + this ->_dotsWidth + dx[p - 1 ];
304335 }
305336 else
306337 {
@@ -322,12 +353,12 @@ class CDirectoryLine : public CChildWindow
322353 // TODO: node clean - nothing!
323354 this ->_nodes [0 ].xright = LAST_NODEX;
324355 }
325- ostr[ostrlen] = TEXT ( ' \0 ' ) ;
326- this ->_pathstr = ostr;
327- this ->_pathlen = ostrlen;
356+ ostr[ostrlen] = L ' \0 ' ;
357+ this ->_pathstrW = ostr;
358+ this ->_pathlenW = ostrlen;
328359 }
329360
330- if (( size_t ) this ->_rootLen == this ->_path -> GetLength () )
361+ if (this ->_rootLenW == this ->_pathWLen )
331362 {
332363 this ->_rootX = -1 ;
333364 }
@@ -479,7 +510,7 @@ class CDirectoryLine : public CChildWindow
479510 {
480511 // root string
481512 trct.right = this ->_rootX ;
482- ExtTextOut (hdc, rct.left + 1 , rct.top + texttop, ETO_OPAQUE | ETO_CLIPPED, &trct, this ->_pathstr , this ->_pathlen , NULL );
513+ ExtTextOutW (hdc, rct.left + 1 , rct.top + texttop, ETO_OPAQUE | ETO_CLIPPED, &trct, this ->_pathstrW , this ->_pathlenW , NULL );
483514 trct.right = rct.right ;
484515 }
485516 trct.left = this ->_rootX ;
@@ -496,27 +527,27 @@ class CDirectoryLine : public CChildWindow
496527 int oR = trct.right ;
497528 int nr = this ->_nodes [this ->_mouseNode ].xright ;
498529 trct.right = nr;
499- ExtTextOut (hdc, rct.left + 1 , rct.top + texttop, ETO_OPAQUE | ETO_CLIPPED, &trct, this ->_pathstr , this ->_pathlen , NULL );
530+ ExtTextOutW (hdc, rct.left + 1 , rct.top + texttop, ETO_OPAQUE | ETO_CLIPPED, &trct, this ->_pathstrW , this ->_pathlenW , NULL );
500531 trct.left = nr;
501532 trct.right = oR;
502533 }
503534 else
504535 {
505536 // whole string highlighted
506- ExtTextOut (hdc, rct.left + 1 , rct.top + texttop, ETO_OPAQUE | ETO_CLIPPED, &trct, this ->_pathstr , this ->_pathlen , NULL );
537+ ExtTextOutW (hdc, rct.left + 1 , rct.top + texttop, ETO_OPAQUE | ETO_CLIPPED, &trct, this ->_pathstrW , this ->_pathlenW , NULL );
507538 }
508539 }
509540 if (!isLastNodeHighlighted)
510541 {
511542 // normal - remaining part
512543 SetTextColor (hdc, this ->_textColor );
513- ExtTextOut (hdc, rct.left + 1 , rct.top + texttop, ETO_OPAQUE | ETO_CLIPPED, &trct, this ->_pathstr , this ->_pathlen , NULL );
544+ ExtTextOutW (hdc, rct.left + 1 , rct.top + texttop, ETO_OPAQUE | ETO_CLIPPED, &trct, this ->_pathstrW , this ->_pathlenW , NULL );
514545 }
515546 }
516547 else
517548 {
518549 // root string only
519- ExtTextOut (hdc, rct.left + 1 , rct.top + texttop, ETO_OPAQUE | ETO_CLIPPED, &rct, this ->_pathstr , this ->_pathlen , NULL );
550+ ExtTextOutW (hdc, rct.left + 1 , rct.top + texttop, ETO_OPAQUE | ETO_CLIPPED, &rct, this ->_pathstrW , this ->_pathlenW , NULL );
520551 }
521552
522553 SelectFont (hdc, hfold);
@@ -618,6 +649,12 @@ class CDirectoryLine : public CChildWindow
618649 this ->_dotsWidth = 0 ;
619650 this ->_id = 0 ;
620651
652+ this ->_pathW [0 ] = L' \0 ' ;
653+ this ->_pathWLen = 0 ;
654+ this ->_rootLenW = 0 ;
655+ this ->_pathstrW = this ->_pathW ;
656+ this ->_pathlenW = 0 ;
657+
621658 this ->_connector = NULL ;
622659
623660 this ->OnSystemChange ();
0 commit comments