PDA

Ver la Versión Completa : ¿como llenar de nulos una cadena?


usuario87
06-08-2012, 04:25:26
hola , mi programa usa una funcion que esta dentro de una dll, esta funcion es parecida a GetSystemDirectory, se le pasa una direccion de memoria donde regresara una cadena que consta de caracteres distintos al caracter nulo (0) , pero al regresar de la funcion esta no te devuelve el numero de caracteres escritos en la direccion de memoria, en visual basic lo que se hace en estos casos es declarar una variable string y llenarlo de puros nulos y al regresar de la funcion simplemente busco el primer nulo dentro de la cadena y ese nulo me indica el final de esa cadena devuelta:

dim Cantidad as Integer
dim Buffer as string 'delcra la var string
Buffer = String(255,Chr(0)) 'asigna 255 nulos en la variable
ObtenerNombre Buffer 'Esta es la funcion que uso
Cantidad = InStr(1,Buffer,Chr(0)) ' aqui busco el primer caracter nulo que indica el final
Buffer = Mid(Buffer,1,Cantidad - 1) 'aqui cojo todos los caracteres -1 que seria el nulo
MsgBox Buffer 'muestro la cadena


¿como se haria eso en delphi?

intente usando setlength pero esta funcion no llena de nulos una cadena xP, para mi es mas facil usar una cadena.

Chris
06-08-2012, 04:45:24
Antes que todo, encuentro un poco confuso lo que dices. Pareciera como qué tu rutina en la DLL implementa las cadenas de C o algo similar. Desearía que aclararas un poco más tu próposito para darte una mejor ayuda.

Ahora, para llenar una cadena con nulos en Delphi, utiliza el siguiente código:

var
Cadena: Array[0..255] of Char;
begin
FillChar(Cadena, SizeOf(Cadena), 0);
end;


Vale la pena mencionar que las cadenas nativas de Delphi (String) no pueden estar llenas de Nulos, a menos que utilices cadenas con longitud específica, cómo por ejemplo: "cadena: string[255]". En el último caso, la variable cadena ya estará llena de nulos una vez creada.

Pero ya que utilizarás una función en una DLL, es mejor que utilices el código del primer ejemplo. Las cadenas nativas de Delphi no son buenas para interacturar con DLLs. Esto es porque por estándar, las DLLs trabajan con cadenas de C.

Saludos.

roman
06-08-2012, 06:08:38
Vale la pena mencionar que las cadenas nativas de Delphi (String) no pueden estar llenas de Nulos

¿A qué te refieres? Un string puede contener cualquier byte, incluido un 0 (nulo). La única restricción es que una tal cadena no se llevará bien con rutinas de texto.

// Saludos

Casimiro Notevi
06-08-2012, 09:30:47
Bienvenido a clubdelphi, usuario87, ¿ya leiste nuestra guía de estilo (http://www.clubdelphi.com/foros/guiaestilo.php)?, gracias por tu colaboración :)

Recuerda poner los tags al código fuente, ejemplo:

http://neftali.clubdelphi.com/images/UtilizarTAGs.png

Gracias :)

usuario87
09-08-2012, 04:24:00
Si, la rutina emplea cadenas de tipo C y como la rutina solo devuelve la cadena sin el nulo al final , entonces lo que se hace es poner una cadena llena de nulos y al regresar la rutina solo busco el primer nulo y ya se que hasta ahi es la cadena.
por poner un ejemplo la rutina puede regresar un nombre como "abcd", entonces regresara tal cual sin el nulo al final , esto en bytes seria 97-98-99-100, entonces si pongo la cadena en nulos antes de entrar en la rutina seria: 0-0-0-0-0-0-0 y al regresar seria 97-98-99-100-0-0-0 (lo que al mostrar seria abcd\0), especifico que tengo que usar cadenas porque es mucho mas facil porque la idea es llenar de nulos esa cadena para entrar en la rutina y luego del retorno usar la funcion Pos(Chr(0),Cadena) para buscar el nulo y asi encuentro el final.

roman
09-08-2012, 16:54:46
Pues, tal como te indica Chris lo puedes hacer. El único problema sería si los datos devueltos ocupan más de 256 bytes.

// Saludos

escafandra
09-08-2012, 19:53:21
Una función que trata cadenas al estilo C debe poner un nulo al final del Buffer que se le pasa, si no lo hace, entonces podemos decir que no es estilo C o que es una chapuza. Por lo tanto me inclino a pensar que si te devuelve un nulo final de cadena.

En el caso de que no devuelve el nulo, puedes usar un Buffer tipo array of char o un String con longitud asignada previamente o un ShortString si no va a ser mas larga de 255.

Para la llamada a esa función deberás usar un puntero que apunte al primer elemento de tu cadena o array:
En el caso de un array: @Buffer[0];
En el caso de un ShortString o String: @Cadena[1] (para luego poder asignar la longitud).

Si tienes que usar el resultado de la llamada como un String tienes estos casos:
En el caso de usar array of char puedes convertirlo a un String.
En el caso de usar un ShortString debes asignar al caracter[0] la longitud de la cadena sin el nulo final
En el caso de un String debes usar SetLength para asignar el tamaño sin el nulo final.



Saludos.

roman
09-08-2012, 20:06:45
No creo que pueda usar un string sin conocer de antemano la longitud de la cadena devuelta. Dicho de otra forma, necesitaría usar SetLength antes de la llamada, de lo contrario no habría memoria asignada para recibir el resultado.

// Saludos

escafandra
09-08-2012, 22:02:36
No creo que pueda usar un string sin conocer de antemano la longitud de la cadena devuelta. Dicho de otra forma, necesitaría usar SetLength antes de la llamada, de lo contrario no habría memoria asignada para recibir el resultado.

Teniendo encuenta que va a usar una función de una dll parecida a GetSystemDirectory:
...mi programa usa una funcion que esta dentro de una dll, esta funcion es parecida a GetSystemDirectory...

El tamaño debe ser MAX_PATH. El problema del tamaño también lo tenemos en un buffer, y como ya dije antes debe asignarlo antes de usarlo:
...puedes usar un Buffer tipo array of char o un String con longitud asignada previamente o un ShortString si no va a ser mas larga de 255...

Luego debes reasignar el tamaño del String al verdadero número de caracteres. En definitiva usas el String como un mero Buffer. Un ejemplo:
var
S: String;
begin
SetLength(S, 100); // Asigno un tamaño
lstrcpy(@S[1], 'Hola'); // API estilo C para copiar una cadena terminada en nulo 'Hola'#0
S:= String(PAnsiChar(@S[1])); // Reasigno el tamaño del String
end;

Saludos.

roman
09-08-2012, 22:10:51
Es cierto que tienes que reasignar el tamaño también al regreso de la función. Pero sí usas un string, también tienes que ponerlo antes, así sea MAX_PATH. Si mandas el string, o @S[1] así nada más, obtendrás una violación de acceso.

// Saludos

escafandra
09-08-2012, 22:43:57
Es cierto que tienes que reasignar el tamaño también al regreso de la función. Pero sí usas un string, también tienes que ponerlo antes, así sea MAX_PATH. Si mandas el string, o @S[1] así nada más, obtendrás una violación de acceso.

Estamos de acuerdo. :)

Saludos.

usuario87
10-08-2012, 05:28:32
jeje no pense que mi preguntilla iba a causar tantas respuestas, bueno miren primero el buffer debe estar si o si en nulos porque como ya dije la funcion de la dll solo me devuelve la cadena sin el nulo (una mala imitacion de las cadenas en C xP), segundo el buffer como maximo debe ser de 255 porque me va a devolver nombres y al principio en ese codigo de visual basic especifique "Buffer = String(255,Chr(0)) 'asigna 255 nulos en la variable" , queria hacerlo con cadenas porque me parecia mucho mas facil hacer algo como esto:

Var
Buffer: string;
Posicion: Byte;
begin
Buffer:=LlenarNulos(255); // equivalente a Buffer = String(255,Chr(0))
ObtenerNombres(PChar(Buffer));
Posicion:=Pos(Chr(0),Buffer);
Buffer:=Copy(Buffer,1,Posicion-1);
Form1.Caption:='Tamaño de la cadena: '+IntToStr(Posicion-1);
ShowMessage(Buffer);



usare shortstring y array of char, tambien se me habia ocurrido usar una api para asignar memoria y pasarle esa direccion a la funcion de la dll y luego busco el nulo mediante un puntero a esa direccion.
gracias

usuario87
10-08-2012, 05:30:27
gracias .