Exportar (0) Imprimir
Expandir todo

Cálculo de referencias predeterminado para cadenas

Actualización: noviembre 2007

Las clases System.String y System.Text.StringBuilder tienen un comportamiento de cálculo de referencias similar.

Las referencias de cadenas se calculan como un tipo BSTR de estilo COM o como una matriz de caracteres que termina en una referencia null (Nothing en Visual Basic). Las referencias de los caracteres con la cadena pueden calcularse como Unicode o ANSI, o en función de la plataforma: Unicode en Microsoft Windows NT, Windows 2000 y Windows XP; ANSI en Windows 98 y Windows Millennium (Windows Me).

En este tema se ofrece la siguiente información sobre el cálculo de referencias de tipos de cadena:

En la tabla siguiente se muestran las opciones de cálculo de referencias para el tipo de dato de cadena cuando se calculan las referencias como un argumento de método para código no administrado. El atributo MarshalAsAttribute proporciona varios valores de la enumeración UnmanagedType para calcular las referencias de cadenas a interfaces COM.

Tipo de enumeración

Descripción de formato no administrado

UnmanagedType.BStr (predeterminado)

Un BSTR de estilo COM con una longitud fija y caracteres Unicode.

UnmanagedType.LPStr

Puntero a una matriz de caracteres ANSI terminada en null.

UnmanagedType.LPWStr

Puntero a una matriz de caracteres Unicode terminada en null.

Esta tabla se aplica a las cadenas. Sin embargo, para StringBuilder, las únicas opciones permitidas son UnmanagedType.LPStr y UnmanagedType.LPWStr.

En el ejemplo siguiente se muestran las cadenas declaradas en la interfaz IStringWorker.

public interface IStringWorker {
void PassString1(String s);
void PassString2([MarshalAs(UnmanagedType.BStr)]String s);
void PassString3([MarshalAs(UnmanagedType.LPStr)]String s);
void PassString4([MarshalAs(UnmanagedType.LPWStr)]String s);
void PassStringRef1(ref String s);
void PassStringRef2([MarshalAs(UnmanagedType.BStr)]ref String s);
void PassStringRef3([MarshalAs(UnmanagedType.LPStr)]ref String s);
void PassStringRef4([MarshalAs(UnmanagedType.LPWStr)]ref String s);
);

En el ejemplo siguiente se muestra la interfaz correspondiente descrita en una biblioteca de tipos.

[…]
interface IStringWorker : IDispatch {
HRESULT PassString1([in] BSTR s);
HRESULT PassString2([in] BSTR s);
HRESULT PassString3([in] LPStr s);
HRESULT PassString4([in] LPWStr s);
HRESULT PassStringRef1([in, out] BSTR *s);
HRESULT PassStringRef2([in, out] BSTR *s);
HRESULT PassStringRef3([in, out] LPStr *s);
HRESULT PassStringRef4([in, out] LPWStr *s);
);

La invocación de plataforma copia argumentos de cadena y convierte el formato de .NET Framework (Unicode) al formato no administrado de la plataforma. Las cadenas son inmutables y no se copian de la memoria no administrada a la memoria administrada al volver de la llamada.

En la tabla siguiente se muestran las opciones de cálculo de referencias para cadenas cuando las referencias se calculan como un argumento de método de una llamada de invocación de plataforma. El atributo MarshalAsAttribute proporciona varios valores de la enumeración UnmanagedType para calcular las referencias de cadenas.

Tipo de enumeración

Descripción de formato no administrado

UnmanagedType.AnsiBStr

Un BSTR de estilo COM con una longitud fija y caracteres ANSI.

UnmanagedType.BStr

Un BSTR de estilo COM con una longitud fija y caracteres Unicode.

UnmanagedType.LPStr

Puntero a una matriz de caracteres ANSI terminada en null.

UnmanagedType.LPTStr (predeterminado)

Puntero a una matriz de caracteres dependientes de la plataforma terminada en null.

UnmanagedType.LPWStr

Puntero a una matriz de caracteres Unicode terminada en null.

UnmanagedType.TBStr

Un BSTR de estilo COM con una longitud fija y caracteres que dependen de la plataforma.

VBByRefStr

Un valor que permite a Visual Basic .NET cambiar una cadena del código no administrado y reflejar los resultados en código administrado. Este valor sólo es compatible con la invocación de plataforma.

Esta tabla se aplica a las cadenas. Sin embargo, para StringBuilder, las únicas opciones permitidas son LPStr, LPTStr y LPWStr.

En la definición de tipo siguiente se muestra el uso correcto de MarshalAsAttribute en llamadas de invocación de plataforma.

class StringLibAPI {
[DllImport("StringLib.Dll")]
public static extern void PassLPStr([MarshalAs(UnmanagedType.LPStr)]
String s);
[DllImport("StringLib.Dll")]
public static extern void 
PassLPWStr([MarshalAs(UnmanagedType.LPWStr)]String s);
[DllImport("StringLib.Dll")]
public static extern void 
PassLPTStr([MarshalAs(UnmanagedType.LPTStr)]String s);
[DllImport("StringLib.Dll")]
public static extern void PassBStr([MarshalAs(UnmanagedType.BStr)]
String s);
[DllImport("StringLib.Dll")]
public static extern void 
PassAnsiBStr([MarshalAs(UnmanagedType.AnsiBStr)]String s);
[DllImport("StringLib.Dll")]
public static extern void PassTBStr([MarshalAs(UnmanagedType.TBStr)]
String s);
}

Las cadenas son miembros válidos de las estructuras; sin embargo, los búferes StringBuilder no son válidos en las estructuras. En la tabla siguiente se muestran las opciones de cálculo de referencias para el tipo de dato de cadena cuando se calculan las referencias del tipo como un campo. El atributo MarshalAsAttribute proporciona varios valores de la enumeración UnmanagedType para calcular las referencias de cadenas a un campo.

Tipo de enumeración

Descripción de formato no administrado

UnmanagedType.BStr

Un BSTR de estilo COM con una longitud fija y caracteres Unicode.

UnmanagedType.LPStr

Puntero a una matriz de caracteres ANSI terminada en null.

UnmanagedType.LPTStr

Puntero a una matriz de caracteres dependientes de la plataforma terminada en null.

UnmanagedType.LPWStr

Puntero a una matriz de caracteres Unicode terminada en null.

UnmanagedType.ByValTStr

Matriz de caracteres de longitud fija; el tipo de la matriz se determina mediante el conjunto de caracteres de la estructura contenedora.

El tipo ByValTStr se utiliza para matrices insertadas de caracteres de longitud fija que aparecen dentro de una estructura. Otros tipos se aplican a referencias de cadena que se encuentran en estructuras que contienen punteros a cadenas.

El argumento CharSet del atributo StructLayoutAttribute que se aplica a la estructura contenedora determina el formato de los caracteres de cadena en las estructuras. Las siguientes estructuras de ejemplo contienen referencias de cadena y cadenas en línea, así como caracteres ANSI, Unicode y dependientes de la plataforma.

Representación de biblioteca de tipos

struct StringInfoA {
   char *    f1;
   char      f2[256];
};
struct StringInfoW {
   WCHAR *   f1;
   WCHAR     f2[256];
   BSTR      f3;
};
struct StringInfoT {
   TCHAR *   f1;
   TCHAR     f2[256];
};

En el ejemplo de código siguiente se muestra cómo utilizar el atributo MarshalAsAttribute para definir la misma estructura en diferentes formatos.

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
struct StringInfoA {
   [MarshalAs(UnmanagedType.LPStr)] public String f1;
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] public String f2;
}
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
struct StringInfoW {
   [MarshalAs(UnmanagedType.LPWStr)] public String f1;
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] public String f2;
   [MarshalAs(UnmanagedType.BStr)] public String f3;
}
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
struct StringInfoT {
   [MarshalAs(UnmanagedType.LPTStr)] public String f1;
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] public String f2;
}

En algunas circunstancias, para manipular un búfer de caracteres de longitud fija se debe pasar a código no administrado. No basta sólo con pasar una cadena en este caso, ya que el destinatario de la llamada no puede modificar el contenido del búfer pasado. Aunque se pase la cadena por referencia, no hay modo de inicializar el búfer con un tamaño determinado.

La solución consiste en pasar un búfer StringBuilder como argumento en lugar de una cadena. El destinatario de la llamada puede anular la referencia de un generador StringBuilder y modificarlo, siempre que no supere la capacidad del generador StringBuilder. También puede inicializarse con una longitud fija. Por ejemplo, si inicializa un búfer StringBuilder para una capacidad de N, el contador de referencias proporcionará un búfer de caracteres con el tamaño N+1. El incremento en uno se debe a que la cadena no administrada tiene un terminador null, a diferencia de StringBuilder, que no lo tiene.

Por ejemplo, la función GetWindowText de la API Win32 de Microsoft (definida en Windows.h) es un búfer de caracteres de longitud fija que debe pasarse a código no administrado para que pueda manipularse. LpString apunta a un búfer asignado a un llamador de tamaño nMaxCount. Se espera que el llamador asigne el búfer y establezca el argumento nMaxCount al tamaño del búfer asignado. En el código siguiente se muestra la declaración de la función GetWindowText tal y como se define en Windows.h.

int GetWindowText(
HWND hWnd,        // Handle to window or control.
LPTStr lpString,  // Text buffer.
int nMaxCount     // Maximum number of characters to copy.
);

El destinatario de la llamada puede anular la referencia de un generador StringBuilder y modificarlo, siempre que no supere la capacidad del generador StringBuilder. En el ejemplo de código siguiente se muestra cómo puede inicializarse StringBuilder con una longitud fija.

public class Win32API {
[DllImport("User32.Dll")]
public static extern void GetWindowText(int h, StringBuilder s, 
int nMaxCount);
}
public class Window {
   internal int h;        // Internal handle to Window.
   public String GetText() {
      StringBuilder sb = new StringBuilder(256);
      Win32API.GetWindowText(h, sb, sb.Capacity + 1);
   return sb.ToString();
   }
}

Adiciones de comunidad

AGREGAR
Mostrar:
© 2015 Microsoft