Estoy trabajando en C# con una API de Borland C que usa muchos punteros de bytes para cadenas. Me he enfrentado a la necesidad de pasar algunas cadenas de C# como (de corta duración) byte *.¿Las constantes están ancladas en C#?
Sería mi suposición natural que un objeto const no se asignaría en el montón, pero se almacenaría directamente en la memoria del programa, pero no he podido verificar esto en ninguna documentación.
Aquí hay un ejemplo de lo que he hecho para generar un puntero a una cadena constante. Esto funciona como estaba previsto en las pruebas, no estoy seguro si es realmente seguro, o solo funciona por suerte.
private const string pinnedStringGetWeight = "getWeight";
unsafe public static byte* ExampleReturnWeightPtr(int serial)
{
fixed (byte* pGetWeight = ASCIIEncoding.ASCII.GetBytes(pinnedStringGetWeight))
return pGetWeight;
}
¿Esto está realmente const, o existe la posibilidad de que se pueda mover?
@Kragen:
Aquí está la importación:
[DllImport("sidekick.dll", CallingConvention = CallingConvention.Winapi)]
public static extern int getValueByFunctionFromObject(int serial, int function, byte* debugCallString);
Ésta es la función real. Sí, en realidad se requiere un puntero de función estática:
private const int FUNC_GetWeight = 0x004243D0;
private const string pinnedStringGetWeight = "getWeight";
unsafe public static int getWeight(int serial)
{
fixed (byte* pGetWeight = ASCIIEncoding.ASCII.GetBytes(pinnedStringGetWeight))
return Core.getValueByFunctionFromObject(serial, FUNC_GetWeight, pGetWeight);
}
siguiente es otro método que utilicé cuando burlarse de mi API, utilizando una estructura estática, que también esperaba que fuera clavado. Esperaba encontrar una forma de simplificar esto.
public byte* getObjVarString(int serial, byte* varName)
{
string varname = StringPointerUtils.GetAsciiString(varName);
string value = MockObjVarAttachments.GetString(serial, varname);
if (value == null)
return null;
return bytePtrFactory.MakePointerToTempString(value);
}
static UnsafeBytePointerFactoryStruct bytePtrFactory = new UnsafeBytePointerFactoryStruct();
private unsafe struct UnsafeBytePointerFactoryStruct
{
fixed byte _InvalidScriptClass[255];
fixed byte _ItemNotFound[255];
fixed byte _MiscBuffer[255];
public byte* InvalidScriptClass
{
get
{
fixed (byte* p = _InvalidScriptClass)
{
CopyNullString(p, "Failed to get script class");
return p;
}
}
}
public byte* ItemNotFound
{
get
{
fixed (byte* p = _ItemNotFound)
{
CopyNullString(p, "Item not found");
return p;
}
}
}
public byte* MakePointerToTempString(string text)
{
fixed (byte* p = _ItemNotFound)
{
CopyNullString(p, text);
return p;
}
}
private static void CopyNullString(byte* ptrDest, string text)
{
byte[] textBytes = ASCIIEncoding.ASCII.GetBytes(text);
fixed (byte* p = textBytes)
{
int i = 0;
while (*(p + i) != 0 && i < 254 && i < textBytes.Length)
{
*(ptrDest + i) = *(p + i);
i++;
}
*(ptrDest + i) = 0;
}
}
}
Este no es el forma de ordenar las cadenas de caracteres para el código nativo - ¿puedes publicar un ejemplo de la llamada (presumiblemente P/Invocar) a tu API de C? – Justin
Sospecho que las cadenas constantes se "fijan" de manera efectiva, ya que no creo que estén almacenadas en el montón recogido de basura. Una evidencia para esto es que las cadenas constantes se cargan usando el código de operación IL de "Ldstr", con la cadena constante proporcionada como parte del cuerpo del método. –
Debo aclarar mi declaración anterior. "La instrucción fija evita que el recolector de basura reubique una variable movible. La declaración fija solo se permite en un contexto inseguro. La solución fija también se puede usar para crear almacenamientos intermedios de tamaño fijo". - http://msdn.microsoft.com/en-us/library/f58wzh21(v=VS.100).aspx - RunUO es tan 2010 :-) –