Direcciones de memoria

04/07/2008 - 19:03 por Rick | Informe spam
Que tal lista, tengo una dll hecha en C, desde C# quiero enviarle una
direccion de memoria que es lo que recibe como parametro mi dll

sin embargo no se porque siempre el compilador C# me dice que no se puede
obtener la direccion de un arreglo (el parametro que envio es un arreglo de
estructuras)

saben si se puede hacer ? o desproteger la memoria que usa c# ?

mi codigo en C es:

typedef struct {
int idVariable;
char *nombreMedidor;
char *nombreVariable;
char hora;
long valor;
short calidad;
int instancia; //uso para los esclavos (la llena el maestro)
int refBdl;
} BASE_DATOS_LOCAL;

typedef struct {
int numInstancia;
int pidInstancia;
int estadoInstancia; //0ÞTENIDO, 1=INICIADO
BASE_DATOS_LOCAL *bdl; //uso llenado por maestros, leido
por esclavos
int numVariables; //uso solo para maestros
int *referencias; //uso solo para esclavos
int numReferencias; //uso solo para esclavos
} INSTANCIA;

extern "C" __declspec(dllexport) void __stdcall main(INSTANCIA *instancia,
int NumInstancia)
{

int i,j;
for(i=0;i<NumInstancia;i++)
{
printf("%d-",instancia[i].numInstancia);
for(j=0;j<30;j++)
{
printf("%c",instancia[i].bdl[j].hora);
instancia[i].bdl[j].hora='Z';
}
}
getch();
}

en C#:

unsafe class Program

{

struct BASE_DATOS_LOCAL {

public int idVariable;

public char* nombreMedidor;

public char* nombreVariable;

public char hora;

public long valor;

public short calidad;

public int instancia; //uso para los esclavos (la llena el maestro)

public int refBdl;

}

struct INSTANCIA {

public int numInstancia;

public int pidInstancia;

public int estadoInstancia; //0ÞTENIDO, 1=INICIADO

public BASE_DATOS_LOCAL [] bdl; //uso llenado por maestros, leido por
esclavos

public int numVariables; //uso solo para maestros

public int* referencias; //uso solo para esclavos

public int numReferencias; //uso solo para esclavos

}

[DllImport("hilodll.dll")] public static extern void main(IntPtr no, int
numInstanacia);



static void Main(string[] args)

{

unsafe

{

INSTANCIA [] instancia = new INSTANCIA [10];

for (int i = 0; i < 10; i++)

{

BASE_DATOS_LOCAL[] memoria = new BASE_DATOS_LOCAL[30];

instancia[i].bdl = memoria;

instancia[i].numInstancia = i;

for (int j = 0; j < 30; j++)

{

instancia[i].bdl[j].hora = 'a';

}

}



for (int i = 0; i < 10; i++)

{

Console.WriteLine("Num Instanacia "+ instancia[i].numInstancia);

for (int j = 0; j < 30; j++)

{

Console.Write(instancia[i].bdl[j].hora);

}

}



Console.WriteLine("Num Instanacia " +
Marshal.UnsafeAddrOfPinnedArrayElement(instancia, 0));

Console.WriteLine("Num Instanacia " +
(Marshal.UnsafeAddrOfPinnedArrayElement(instancia, 0)).ToString("x"));

IntPtr pT = Marshal.UnsafeAddrOfPinnedArrayElement(instancia, 0);

main(pT,10); // asi manda la direccion hexadecimal del apuntador pero pues
al recibirla mi dll no hace nada porque no sabe a dnd apunta

//main(instancia, 10); <<< ASI ES COMO DEBERIA DE FUNCIONAR PARA MANDAR LA
DIRECCION DEL ARREGLO PERO PUES NO SE DEJA =(

for (int i = 0; i < 10; i++)

{

Console.WriteLine("Num Instanacia " + instancia[i].numInstancia);

for (int j = 0; j < 30; j++)

{

Console.Write(instancia[i].bdl[j].hora);

}

}

}



}



Como pueden ver lo unico que hago es de momento desplegar unos leves valores
pero pues no me funciona

Preguntas similare

Leer las respuestas

#1 RFOG
05/07/2008 - 13:14 | Informe spam
Hola.

No he visto en detalle el código porque me resulta bastante pesado de leer
en un correo (no es culpa tuya, sino del estándar), pero básicamente:

-Si necesitas recibir un puntero a memoria asignada por la parte nativa,
tienes que usar un IntPtr y luego mediante el método adecuado de la clase
Marshal copiarlo a su equivalente .NET.

-Si necesitas pasar un puntero a memoria asignada por el .NET para la parte
nativa, el método más fácil es hacerlo mediante un StringBuilder con
preasignación de la memoria adecuada mediante el constructor adecuado.

-Si necesitas pasar un puntero a una estructura C#, ésta ha de tener el
atributo [StructLayout(LayoutKind.Sequential)] y la pasas tal cual (creo que
es así, luego el Interop se encargará de pinear el tema).

-Si necesitas pasar un array de algo, no tengo ni idea en C#, pero en
C++/CLI los arrays normales son contiguos, así que mediante un pinneo y un
puntero interior se puede hacer, imagino que en C# debe haber un equivalente
pero lo desconozco.

-Si necesitas pasar punteros dentro de una estructura, entonces el tema es
un mundo en sí mismo. ¿Quién asigna la memoria de ese puntero, la parte
nativa o la manejada? Si es la nativa, el IntPtr y luego la conversión como
en el primer punto. Si es la manejada no tengo ni idea, ya que en casos
complicados lo que hago es hacerme una DLL en C++/CLI y ahí sí que puedo
trastear con pinneos y demás zarandajas que no sé cómo se hacen en C# y ni
siquiera si se pueden hacer.

-Como regla general, una vez devuelto algo mediante Interop, no podrás
manejarlo directamente en C#, es decir, si es algo compartido
simultáneamente con la parte nativa y manejada creo que en C# no se puede,
aunque sí en C++/CLI con los punteros interiores y los pinneos.

En teoría, y sólo en teoría porque no lo he probado nunca (si la cosa es
complicada la hago en C++/CLI, que para eso está), con C# no seguro
simplemente tienes que pasar los punteros sin hacer nada más ya que sería
equivalente a auto-pinnearse y auto-puntero-interiorizarse, válganme las
continuas rebuznancias al idioma castellano.


"Rick" wrote in message
news:%
Que tal lista, tengo una dll hecha en C, desde C# quiero enviarle una
direccion de memoria que es lo que recibe como parametro mi dll

sin embargo no se porque siempre el compilador C# me dice que no se puede
obtener la direccion de un arreglo (el parametro que envio es un arreglo
de estructuras)

saben si se puede hacer ? o desproteger la memoria que usa c# ?

mi codigo en C es:

typedef struct {
int idVariable;
char *nombreMedidor;
char *nombreVariable;
char hora;
long valor;
short calidad;
int instancia; //uso para los esclavos (la llena el maestro)
int refBdl;
} BASE_DATOS_LOCAL;

typedef struct {
int numInstancia;
int pidInstancia;
int estadoInstancia; //0ÞTENIDO, 1=INICIADO
BASE_DATOS_LOCAL *bdl; //uso llenado por maestros, leido
por esclavos
int numVariables; //uso solo para maestros
int *referencias; //uso solo para esclavos
int numReferencias; //uso solo para esclavos
} INSTANCIA;

extern "C" __declspec(dllexport) void __stdcall main(INSTANCIA *instancia,
int NumInstancia)
{

int i,j;
for(i=0;i<NumInstancia;i++)
{
printf("%d-",instancia[i].numInstancia);
for(j=0;j<30;j++)
{
printf("%c",instancia[i].bdl[j].hora);
instancia[i].bdl[j].hora='Z';
}
}
getch();
}

en C#:

unsafe class Program

{

struct BASE_DATOS_LOCAL {

public int idVariable;

public char* nombreMedidor;

public char* nombreVariable;

public char hora;

public long valor;

public short calidad;

public int instancia; //uso para los esclavos (la llena el maestro)

public int refBdl;

}

struct INSTANCIA {

public int numInstancia;

public int pidInstancia;

public int estadoInstancia; //0ÞTENIDO, 1=INICIADO

public BASE_DATOS_LOCAL [] bdl; //uso llenado por maestros, leido por
esclavos

public int numVariables; //uso solo para maestros

public int* referencias; //uso solo para esclavos

public int numReferencias; //uso solo para esclavos

}

[DllImport("hilodll.dll")] public static extern void main(IntPtr no, int
numInstanacia);



static void Main(string[] args)

{

unsafe

{

INSTANCIA [] instancia = new INSTANCIA [10];

for (int i = 0; i < 10; i++)

{

BASE_DATOS_LOCAL[] memoria = new BASE_DATOS_LOCAL[30];

instancia[i].bdl = memoria;

instancia[i].numInstancia = i;

for (int j = 0; j < 30; j++)

{

instancia[i].bdl[j].hora = 'a';

}

}



for (int i = 0; i < 10; i++)

{

Console.WriteLine("Num Instanacia "+ instancia[i].numInstancia);

for (int j = 0; j < 30; j++)

{

Console.Write(instancia[i].bdl[j].hora);

}

}



Console.WriteLine("Num Instanacia " +
Marshal.UnsafeAddrOfPinnedArrayElement(instancia, 0));

Console.WriteLine("Num Instanacia " +
(Marshal.UnsafeAddrOfPinnedArrayElement(instancia, 0)).ToString("x"));

IntPtr pT = Marshal.UnsafeAddrOfPinnedArrayElement(instancia, 0);

main(pT,10); // asi manda la direccion hexadecimal del apuntador pero pues
al recibirla mi dll no hace nada porque no sabe a dnd apunta

//main(instancia, 10); <<< ASI ES COMO DEBERIA DE FUNCIONAR PARA MANDAR
LA DIRECCION DEL ARREGLO PERO PUES NO SE DEJA =(

for (int i = 0; i < 10; i++)

{

Console.WriteLine("Num Instanacia " + instancia[i].numInstancia);

for (int j = 0; j < 30; j++)

{

Console.Write(instancia[i].bdl[j].hora);

}

}

}



}



Como pueden ver lo unico que hago es de momento desplegar unos leves
valores pero pues no me funciona


Respuesta Responder a este mensaje
#2 Rick
07/07/2008 - 18:09 | Informe spam
Muchas gracias por tu respuesta RFOG, he leido algo al respecto pero tu me
aclaras mas la situacion


Saludos!!!



"RFOG" escribió en el mensaje
news:
Hola.

No he visto en detalle el código porque me resulta bastante pesado de leer
en un correo (no es culpa tuya, sino del estándar), pero básicamente:

-Si necesitas recibir un puntero a memoria asignada por la parte nativa,
tienes que usar un IntPtr y luego mediante el método adecuado de la clase
Marshal copiarlo a su equivalente .NET.

-Si necesitas pasar un puntero a memoria asignada por el .NET para la
parte nativa, el método más fácil es hacerlo mediante un StringBuilder con
preasignación de la memoria adecuada mediante el constructor adecuado.

-Si necesitas pasar un puntero a una estructura C#, ésta ha de tener el
atributo [StructLayout(LayoutKind.Sequential)] y la pasas tal cual (creo
que es así, luego el Interop se encargará de pinear el tema).

-Si necesitas pasar un array de algo, no tengo ni idea en C#, pero en
C++/CLI los arrays normales son contiguos, así que mediante un pinneo y un
puntero interior se puede hacer, imagino que en C# debe haber un
equivalente pero lo desconozco.

-Si necesitas pasar punteros dentro de una estructura, entonces el tema es
un mundo en sí mismo. ¿Quién asigna la memoria de ese puntero, la parte
nativa o la manejada? Si es la nativa, el IntPtr y luego la conversión
como en el primer punto. Si es la manejada no tengo ni idea, ya que en
casos complicados lo que hago es hacerme una DLL en C++/CLI y ahí sí que
puedo trastear con pinneos y demás zarandajas que no sé cómo se hacen en
C# y ni siquiera si se pueden hacer.

-Como regla general, una vez devuelto algo mediante Interop, no podrás
manejarlo directamente en C#, es decir, si es algo compartido
simultáneamente con la parte nativa y manejada creo que en C# no se puede,
aunque sí en C++/CLI con los punteros interiores y los pinneos.

En teoría, y sólo en teoría porque no lo he probado nunca (si la cosa es
complicada la hago en C++/CLI, que para eso está), con C# no seguro
simplemente tienes que pasar los punteros sin hacer nada más ya que sería
equivalente a auto-pinnearse y auto-puntero-interiorizarse, válganme las
continuas rebuznancias al idioma castellano.


"Rick" wrote in message
news:%
Que tal lista, tengo una dll hecha en C, desde C# quiero enviarle una
direccion de memoria que es lo que recibe como parametro mi dll

sin embargo no se porque siempre el compilador C# me dice que no se puede
obtener la direccion de un arreglo (el parametro que envio es un arreglo
de estructuras)

saben si se puede hacer ? o desproteger la memoria que usa c# ?

mi codigo en C es:

typedef struct {
int idVariable;
char *nombreMedidor;
char *nombreVariable;
char hora;
long valor;
short calidad;
int instancia; //uso para los esclavos (la llena el maestro)
int refBdl;
} BASE_DATOS_LOCAL;

typedef struct {
int numInstancia;
int pidInstancia;
int estadoInstancia; //0ÞTENIDO, 1=INICIADO
BASE_DATOS_LOCAL *bdl; //uso llenado por maestros, leido
por esclavos
int numVariables; //uso solo para maestros
int *referencias; //uso solo para esclavos
int numReferencias; //uso solo para esclavos
} INSTANCIA;

extern "C" __declspec(dllexport) void __stdcall main(INSTANCIA
*instancia, int NumInstancia)
{

int i,j;
for(i=0;i<NumInstancia;i++)
{
printf("%d-",instancia[i].numInstancia);
for(j=0;j<30;j++)
{
printf("%c",instancia[i].bdl[j].hora);
instancia[i].bdl[j].hora='Z';
}
}
getch();
}

en C#:

unsafe class Program

{

struct BASE_DATOS_LOCAL {

public int idVariable;

public char* nombreMedidor;

public char* nombreVariable;

public char hora;

public long valor;

public short calidad;

public int instancia; //uso para los esclavos (la llena el maestro)

public int refBdl;

}

struct INSTANCIA {

public int numInstancia;

public int pidInstancia;

public int estadoInstancia; //0ÞTENIDO, 1=INICIADO

public BASE_DATOS_LOCAL [] bdl; //uso llenado por maestros, leido por
esclavos

public int numVariables; //uso solo para maestros

public int* referencias; //uso solo para esclavos

public int numReferencias; //uso solo para esclavos

}

[DllImport("hilodll.dll")] public static extern void main(IntPtr no, int
numInstanacia);



static void Main(string[] args)

{

unsafe

{

INSTANCIA [] instancia = new INSTANCIA [10];

for (int i = 0; i < 10; i++)

{

BASE_DATOS_LOCAL[] memoria = new BASE_DATOS_LOCAL[30];

instancia[i].bdl = memoria;

instancia[i].numInstancia = i;

for (int j = 0; j < 30; j++)

{

instancia[i].bdl[j].hora = 'a';

}

}



for (int i = 0; i < 10; i++)

{

Console.WriteLine("Num Instanacia "+ instancia[i].numInstancia);

for (int j = 0; j < 30; j++)

{

Console.Write(instancia[i].bdl[j].hora);

}

}



Console.WriteLine("Num Instanacia " +
Marshal.UnsafeAddrOfPinnedArrayElement(instancia, 0));

Console.WriteLine("Num Instanacia " +
(Marshal.UnsafeAddrOfPinnedArrayElement(instancia, 0)).ToString("x"));

IntPtr pT = Marshal.UnsafeAddrOfPinnedArrayElement(instancia, 0);

main(pT,10); // asi manda la direccion hexadecimal del apuntador pero
pues al recibirla mi dll no hace nada porque no sabe a dnd apunta

//main(instancia, 10); <<< ASI ES COMO DEBERIA DE FUNCIONAR PARA MANDAR
LA DIRECCION DEL ARREGLO PERO PUES NO SE DEJA =(

for (int i = 0; i < 10; i++)

{

Console.WriteLine("Num Instanacia " + instancia[i].numInstancia);

for (int j = 0; j < 30; j++)

{

Console.Write(instancia[i].bdl[j].hora);

}

}

}



}



Como pueden ver lo unico que hago es de momento desplegar unos leves
valores pero pues no me funciona





Respuesta Responder a este mensaje
#3 RFOG
07/07/2008 - 18:35 | Informe spam
Si tienes alguna duda puntual ponla aquí e intentaremos resolverla...

On Mon, 07 Jul 2008 18:09:56 +0200, Rick wrote:

Muchas gracias por tu respuesta RFOG, he leido algo al respecto pero tu
me
aclaras mas la situacion


Saludos!!!



"RFOG" escribió en el mensaje
news:
Hola.

No he visto en detalle el código porque me resulta bastante pesado de
leer
en un correo (no es culpa tuya, sino del estándar), pero básicamente:

-Si necesitas recibir un puntero a memoria asignada por la parte nativa,
tienes que usar un IntPtr y luego mediante el método adecuado de la
clase
Marshal copiarlo a su equivalente .NET.

-Si necesitas pasar un puntero a memoria asignada por el .NET para la
parte nativa, el método más fácil es hacerlo mediante un StringBuilder
con
preasignación de la memoria adecuada mediante el constructor adecuado.

-Si necesitas pasar un puntero a una estructura C#, ésta ha de tener el
atributo [StructLayout(LayoutKind.Sequential)] y la pasas tal cual (creo
que es así, luego el Interop se encargará de pinear el tema).

-Si necesitas pasar un array de algo, no tengo ni idea en C#, pero en
C++/CLI los arrays normales son contiguos, así que mediante un pinneo y
un
puntero interior se puede hacer, imagino que en C# debe haber un
equivalente pero lo desconozco.

-Si necesitas pasar punteros dentro de una estructura, entonces el tema
es
un mundo en sí mismo. ¿Quién asigna la memoria de ese puntero, la parte
nativa o la manejada? Si es la nativa, el IntPtr y luego la conversión
como en el primer punto. Si es la manejada no tengo ni idea, ya que en
casos complicados lo que hago es hacerme una DLL en C++/CLI y ahí sí que
puedo trastear con pinneos y demás zarandajas que no sé cómo se hacen en
C# y ni siquiera si se pueden hacer.

-Como regla general, una vez devuelto algo mediante Interop, no podrás
manejarlo directamente en C#, es decir, si es algo compartido
simultáneamente con la parte nativa y manejada creo que en C# no se
puede,
aunque sí en C++/CLI con los punteros interiores y los pinneos.

En teoría, y sólo en teoría porque no lo he probado nunca (si la cosa es
complicada la hago en C++/CLI, que para eso está), con C# no seguro
simplemente tienes que pasar los punteros sin hacer nada más ya que
sería
equivalente a auto-pinnearse y auto-puntero-interiorizarse, válganme las
continuas rebuznancias al idioma castellano.


"Rick" wrote in message
news:%
Que tal lista, tengo una dll hecha en C, desde C# quiero enviarle una
direccion de memoria que es lo que recibe como parametro mi dll

sin embargo no se porque siempre el compilador C# me dice que no se
puede
obtener la direccion de un arreglo (el parametro que envio es un
arreglo
de estructuras)

saben si se puede hacer ? o desproteger la memoria que usa c# ?

mi codigo en C es:

typedef struct {
int idVariable;
char *nombreMedidor;
char *nombreVariable;
char hora;
long valor;
short calidad;
int instancia; //uso para los esclavos (la llena el maestro)
int refBdl;
} BASE_DATOS_LOCAL;

typedef struct {
int numInstancia;
int pidInstancia;
int estadoInstancia; //0ÞTENIDO, 1=INICIADO
BASE_DATOS_LOCAL *bdl; //uso llenado por maestros,
leido
por esclavos
int numVariables; //uso solo para maestros
int *referencias; //uso solo para esclavos
int numReferencias; //uso solo para esclavos
} INSTANCIA;

extern "C" __declspec(dllexport) void __stdcall main(INSTANCIA
*instancia, int NumInstancia)
{

int i,j;
for(i=0;i<NumInstancia;i++)
{
printf("%d-",instancia[i].numInstancia);
for(j=0;j<30;j++)
{
printf("%c",instancia[i].bdl[j].hora);
instancia[i].bdl[j].hora='Z';
}
}
getch();
}

en C#:

unsafe class Program

{

struct BASE_DATOS_LOCAL {

public int idVariable;

public char* nombreMedidor;

public char* nombreVariable;

public char hora;

public long valor;

public short calidad;

public int instancia; //uso para los esclavos (la llena el maestro)

public int refBdl;

}

struct INSTANCIA {

public int numInstancia;

public int pidInstancia;

public int estadoInstancia; //0ÞTENIDO, 1=INICIADO

public BASE_DATOS_LOCAL [] bdl; //uso llenado por maestros, leido por
esclavos

public int numVariables; //uso solo para maestros

public int* referencias; //uso solo para esclavos

public int numReferencias; //uso solo para esclavos

}

[DllImport("hilodll.dll")] public static extern void main(IntPtr no,
int
numInstanacia);



static void Main(string[] args)

{

unsafe

{

INSTANCIA [] instancia = new INSTANCIA [10];

for (int i = 0; i < 10; i++)

{

BASE_DATOS_LOCAL[] memoria = new BASE_DATOS_LOCAL[30];

instancia[i].bdl = memoria;

instancia[i].numInstancia = i;

for (int j = 0; j < 30; j++)

{

instancia[i].bdl[j].hora = 'a';

}

}



for (int i = 0; i < 10; i++)

{

Console.WriteLine("Num Instanacia "+ instancia[i].numInstancia);

for (int j = 0; j < 30; j++)

{

Console.Write(instancia[i].bdl[j].hora);

}

}



Console.WriteLine("Num Instanacia " +
Marshal.UnsafeAddrOfPinnedArrayElement(instancia, 0));

Console.WriteLine("Num Instanacia " +
(Marshal.UnsafeAddrOfPinnedArrayElement(instancia, 0)).ToString("x"));

IntPtr pT = Marshal.UnsafeAddrOfPinnedArrayElement(instancia, 0);

main(pT,10); // asi manda la direccion hexadecimal del apuntador pero
pues al recibirla mi dll no hace nada porque no sabe a dnd apunta

//main(instancia, 10); <<< ASI ES COMO DEBERIA DE FUNCIONAR PARA
MANDAR
LA DIRECCION DEL ARREGLO PERO PUES NO SE DEJA =(

for (int i = 0; i < 10; i++)

{

Console.WriteLine("Num Instanacia " + instancia[i].numInstancia);

for (int j = 0; j < 30; j++)

{

Console.Write(instancia[i].bdl[j].hora);

}

}

}



}



Como pueden ver lo unico que hago es de momento desplegar unos leves
valores pero pues no me funciona














Microsoft Visual C++ MVP
==Mi blog sobre programación: http://geeks.ms/blogs/rfog
Momentos Leves: http://momentosleves.blogspot.com/
Cosas mías: http://rfog.blogsome.com/
Libros, ciencia ficción y programación
No dejes crecer la hierba en el camino de la amistad.
email Siga el debate Respuesta Responder a este mensaje
Ads by Google
Help Hacer una preguntaRespuesta Tengo una respuesta
Search Busqueda sugerida