2010-04-14 7 views
5

que estaba buscando una forma de insertar una elipse en un # ruta C, y se encontró una respuesta aquí en stackoverflow: C# Path Ellipsis without Win32 API callAñadir puntos suspensivos para un camino en un programa de Windows Forms sin Win32 llamada a la API (revisited)

Utilizando el RTM versiones de VS2010 y .Net 4.0, no pude hacer funcionar el método sugerido. Busqué en 'Net' y encontré un código de ejemplo que usa el mismo método, pero falló de la misma manera.

Puede ver la cadena que estoy tratando de acortar en mi código a continuación.

Después de llamar al método measureText, tanto la cadena de entrada (originalName) y la cadena de salida (ellipsisedName) tener este aspecto:

d: \ ABCD \ EFGH \ IJKL \ mnop \ QRST \ ... \ test .txt \ 0F \ GHIJ \ KLMN \ OPQR \ STIV \ WXYZ \ test.txt

dos problemas:

1) se narfed la cadena resultante (la ruta se trunca como se esperaba, pero va seguida de lo que parece como un nulo de terminación estilo C y un fragmento de la ruta original).

2) Mi cadena original se ha cambiado para que sea idéntica a la cadena de salida.

¿Estoy haciendo algo mal?

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); 
     } 
    } 
} 
+0

No veo cómo su llamada a MeasureText() podría modificar OriginalPath. Si eso realmente está sucediendo, el método MeasureText() está haciendo algo realmente funky. –

Respuesta

4

Holy moly, has encontrado un whopper de un error. La P/Invoke utilizada dentro de la clase TextRenderer que llama a DrawTextEx() está borked. Esa función API está escribiendo nuevamente en la cadena, lo cual está permitido hacer ya que el argumento cchText es un LPTSTR, no un LPCTSTR. Eso destruye el contenido de cadena .NET para ambas variables porque la cadena está interna.

El error no es específico de .NET 4.0, también lo veo mal en ReferenceSource para .NET 3.5 SP1 y puedo reproducirlo en VS2008. El problema está en la función interna de WindowsGraphics.MeasureText. Puede reportar el error en connect.microsoft.com.

Una posible solución consiste en alterar la cadena para que se copia y no puede afectar al original:

string ellipsisedPath = OriginalPath + '\0'; 

Pero la mejor solución en este caso es simplemente no pasar la opción ModifyString, no sirve para nada propósito. Lo cual es más seguro también, todavía hay una posibilidad de destruir el montón recogido de basura con la primera solución. La solución para Microsoft es similarmente simple, debería enmascarar la opción ModifyString. Está documentado que no tiene ningún efecto.

+0

Wow, eso es genial. –

+1

Puede usar 'string.Copy' para tener claro sobre la copia de la cadena interna a un nuevo buffer. –

+0

Gracias por la explicación. Tu solución de problemas original (y la de Ron) resuelven el problema sobreescrito-cadena original, pero ninguno hace que MeasureText funcione como yo quería, ya que la cadena de salida todavía no está elíptica correctamente. Si no especifico ModifyString, la cadena de salida no se elipsifica (como se esperaba), lo que frustra mi propósito (que era obtener una cadena de ruta elíptica). Lo que estoy tratando de hacer es probablemente un mal uso de ModifyString de todos modos. Estaba usando esta técnica como se sugirió como la forma de hacer esto aquí: http://tinyurl.com/y6rmdfr – casterle

2

Mi cadena original se cambia a ser idéntica a la cadena de salida.

Usted ha pedido que esto suceda mediante la especificación de TextFormatFlags.ModifyString, que los documentos dicen

Modifica la cadena especificada para que coincida con el texto que se muestra. Este valor no tiene ningún efecto a menos que se especifique EndEllipsis o PathEllipsis.

Esto es (en mi opinión) una forma inusual de operar una llamada de .NET Framework, pero claramente dice que hará esto. Tanto la cadena 'original' y la cadena 'output' llegar a ser modificadas, porque string es un tipo de referencia (aunque por lo general con la semántica de valor inmutables) - cuando usted dice

string ellipsisedPath = OriginalPath; 

en realidad se acaba de hacer ellipsisedPath se refieren a la misma instancia de cadena como OriginalPath hace. Cuando esta instancia es modificada por la llamada API, ambas referencias a ella verán la modificación.

En cuanto a

la ruta se trunca como se esperaba, pero es seguido por lo que parece ser un estilo de C terminación nula y un trozo de la ruta original

mi conjetura sería que la abstracción que proporciona este envoltorio administrado en torno a la llamada a la API Win32 es un poco permeable, ya que las abstracciones son propensas a serlo; no lo protege del hecho de que la llamada subyacente funciona con cadenas tipo C. Puede ser que tengas que lidiar contigo mismo.

+0

"cuando dices string ellipsisedPath = OriginalPath; en realidad estás haciendo elipshipPath se refiere a la misma instancia de cadena que tiene OriginalPath. [...]" This is ** wrong **. Asignar cadena1 a cadena2 hace una copia de valor de cadena1. Cualquier cambio en string1 tendrá ** efecto ** en string2. Y aunque string es una clase, es inmutable y se comporta como un tipo de valor. Las cadenas nunca * se cambian *, siempre se * copian * a una nueva cadena con la modificación. –

+0

I * DO * especifique PathEllipsis. – casterle

+0

@Hans: Puede describir lo que sucedió debido al error, pero también proporciona información descaradamente falsa sobre la asignación de una cadena a otra en cualquier situación normal, y no señala que esto solo ocurrió debido a un error importante en TextRenderer. Por favor, al menos reconozca que, como alguien con su representante no debe contribuir a ese malentendido. –

Cuestiones relacionadas