Add Ellipsis to a Path in a WinForms Program without Win32 API call (revisited)

北战南征 提交于 2019-12-18 13:34:42

问题


I was searching for a way to insert an ellipsis in a C# path, and found an answer here on stackoverflow: C# Path Ellipsis without Win32 API call

Using the RTM versions of VS2010 and .Net 4.0, I was unable to get the suggested method to work. I searched the 'Net and found example code that uses the same method, but it failed in the same way.

You can see the string I'm trying to shorten in my code below.

After calling the MeasureText method, both the input string (OriginalName) and the output string (ellipsisedName) look like this:

d:\abcd\efgh\ijkl\mnop\qrst\...\test.txt\0F\GHIJ\KLMN\OPQR\STIV\WXYZ\test.txt

Two problems:

1) The resulting string is narfed (the path is truncated as expected, but is followed by what looks like a C-style terminating null and a chunk of the original path).

2) My original string is changed to be identical to the output string.

Am I doing something wrong?

namespace WindowsFormsApplication2 {
   public partial class Form1 : Form {
      public Form1()
      {
         InitializeComponent();

         string OriginalPath = @"d:\abcd\efgh\ijkl\mnop\qrst\uvwx\yzAB\CDEF\GHIJ\KLMN\OPQR\STIV\WXYZ\test.txt";
         string ellipsisedPath = OriginalPath;

         Size proposedSize = new Size(label1.Width, label1.Height);

         TextRenderer.MeasureText(ellipsisedPath, label1.Font, proposedSize, TextFormatFlags.ModifyString | TextFormatFlags.PathEllipsis);
      }
   }
}

回答1:


Holy moly, you've found a whopper of a bug. The P/Invoke used inside the TextRenderer class that calls DrawTextEx() is borked. That API function is writing back into the string, which it is allowed to do since the cchText argument is a LPTSTR, not a LPCTSTR. That destroys the .NET string content for both variables because the string is interned.

The bug isn't specific to .NET 4.0, I see it wrong in the ReferenceSource for .NET 3.5 SP1 as well and can repro it on VS2008. The trouble is in the internal WindowsGraphics.MeasureText function. You can report the bug at connect.microsoft.com.

A possible workaround is to alter the string so it gets copied and can't affect the original:

  string ellipsisedPath = OriginalPath + '\0';

But the better workaround in this case is to simply not pass the ModifyString option, it serves no purpose. Which is safer too, there is still a possibility of destroying the garbage collected heap with the first workaround. The fix for Microsoft is similarly simple, it should just mask out the ModifyString option. It is documented to have no effect.




回答2:


My original string is changed to be identical to the output string.

You've asked for this to happen by specifying TextFormatFlags.ModifyString, which the docs say

Modifies the specified string to match the displayed text. This value has no effect unless EndEllipsis or PathEllipsis is also specified.

This is (to my mind) an unusual way for a .NET Framework call to operate, but it does clearly say it will do this. Both the 'original' string and the 'output' string end up being modified, because string is a reference type (though usually with immutable value semantics) - when you say

string ellipsisedPath = OriginalPath;

you are actually just making ellipsisedPath refer to the same string instance as OriginalPath does. When this instance gets modified by the API call, both the references to it will see the modification.

As for

the path is truncated as expected, but is followed by what looks like a C-style terminating null and a chunk of the original path

my guess would be that the abstraction this managed wrapper provides around the Win32 API call is being somewhat leaky, as abstractions are prone to being - it's not shielding you from the fact that the underlying call works with C-style strings. It might be that you'll have to deal with yourself.



来源:https://stackoverflow.com/questions/2640410/add-ellipsis-to-a-path-in-a-winforms-program-without-win32-api-call-revisited

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!