C sharp - Trabajar con CopyMemory en C#

   
Vista:

Trabajar con CopyMemory en C#

Publicado por Leo (10 intervenciones) el 07/07/2015 16:26:08
Hola amigos,

Estoy trabajando en un proyecto para pasar un programa originalmente escrito en Visual Basic 5 a C# para trabajar con el programa MMTTY de codificacion de audio, y estoy atascado en este código.

La funcion "Private Sub XMMR_OnNotifyNMMR(pNMMR As Long)" se ejecuta cuando el receptor de audio recibe una trama y manda como argumento el puntero pNMMR que apunta a la posición de memoria de la estructura NMMR donde se encuentran los datos.

Luego se hace un CopyMemory para guardar los datos en el array m_nmmr().

A la hora de pasarlo a C# me encuentro con el problema de que la estructura no está definida y no sé como usar el puntero pNMMR.

Alguien me da una orientación de como definir la estructura en C# y poder trabajar con el punero pNMMR?

Gracias de antemano,



Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As Any, ByVal Source As Any, ByVal Length As Long)
Dim m_nmmr(63) As Long
Private Sub XMMR_OnNotifyNMMR(pNMMR As Long)

Call CopyMemory(m_nmmr(0), pNMMR, 64 * 4)

MarkFreq = m_nmmr(5)

End Sub


#pragma pack(push, 1)
typedef struct {
DWORD m_markfreq;
DWORD m_spacefreq;
DWORD m_siglevel;
DWORD m_sqlevel;
DWORD m_codeswitch;
DWORD m_notch1;
DWORD m_notch2;
DWORD m_baud;
DWORD m_fig;
DWORD m_radiofreq;
DWORD m_Reserved[];
}NMMR;
#pragma pack(pop)
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder

Trabajar con CopyMemory en C#

Publicado por David (59 intervenciones) el 08/07/2015 00:25:11
Tienes que usar marshalling y p/invoke.

La declaración de la función CopyMemory() sería así (dentro de una clase):

1
2
[DllImport("Kernel32.dll", EntryPoint="RtlMoveMemory", SetLastError=false)]
static extern void MoveMemory(IntPtr dest, IntPtr src, int size);

Y la estructura así:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[StructLayout(LayoutKind.Sequential)]
public struct NMMR
{
uint m_markfreq;
uint m_spacefreq;
uint m_siglevel;
uint m_sqlevel;
uint m_codeswitch;
uint m_notch1;
uint m_notch2;
uint m_baud;
uint m_fig;
uint m_radiofreq;
uint[] m_Reserved;
}

Luego tan solo tienes que convertir de struct a intptr y viceversa. Aquí tienes ejemplos.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar

Trabajar con CopyMemory en C#

Publicado por Leo (10 intervenciones) el 08/07/2015 09:55:05
Gracias por tu ayuda,

El problema que encuentro es que este evento que me envia el programa externo me devuelve un puntero con la posicion de memoria donde se encuentran los datos:

private void XMMR_OnNotifyNMMR(object sender, AxXMMTLib._DXMMREvents_OnNotifyNMMREvent e)

El puntero sería e.pNMMR

Definí la instrucción de CallMemory() de esta forma:

[DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)]

static extern void MoveMemory(long[] dest, IntPtr src, int size);

Por lo tanto lo que quiero es copiar los datos a los que apunta e.pNMMR al buffer m_nmmr[63], con algo parecido a:

MoveMemory(m_nmmr[0],e.pNNMR,64*4)

Pero es que no me da salido, todas las opciones que pruebo me dan error de compilación.

Un saludo,
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Trabajar con CopyMemory en C#

Publicado por David (59 intervenciones) el 09/07/2015 03:03:24
Antes de hacer la copia, necesitas el intptr de m_nmmr. En el link que te puse tienes cómo hacerlo usando Marshall.StructureToPtr(). El IntPtr es el que tienes que poner, no m_nmmr directamente.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Trabajar con CopyMemory en C#

Publicado por Leo (10 intervenciones) el 09/07/2015 11:26:04
Hola, intento hacer esto en C# pero me salta una excepción de "System.AcessViolationException" cuando copio los datos desde el puntero e.pNMMR al array m_nmmr[]
El valor de e.pNMMR (int) en ese momento es 1519 que coincide con el parametro del primer valor de la estructura NMMR "m_markfreq"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[StructLayout(LayoutKind.Sequential)]
        public struct NMMR
        {
            public uint m_markfreq;
            public uint m_spacefreq;
            public uint m_siglevel;
            public uint m_sqlevel;
            public uint m_codeswitch;
            public uint m_codeview;
            public uint m_notch1;
            public uint m_baud;
            public uint m_fig;
            public uint m_radiofreq;
            [MarshalAs( UnmanagedType.ByValArray , SizeConst=53)]
            public uint[] m_Reserved;
        }
 
        public NMMR myNMMR;
 
private void XMMR_OnNotifyNMMR(object sender, AxXMMTLib._DXMMREvents_OnNotifyNMMREvent e)
        {
            Int32[] m_nmmr = new Int32[63];
            //MessageBox.Show(Convert.ToString(e.pNMMR));
            IntPtr ptr = (IntPtr)e.pNMMR;
            //CopyMemory(m_nmmr, ptr, 64);
            Marshal.Copy(ptr, m_nmmr, 0, 63);
          }
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Trabajar con CopyMemory en C#

Publicado por David (59 intervenciones) el 11/07/2015 16:48:57
Te falla porque no puedes mezclar objetos manejados con punteros. Necesitas recuperar el intptr de tu objeto de la estructura nmmr. El array m_nmmr te sobra. Usa el objeto myNMMR para ajustar el ejemplo de la documentación para conseguir el intptr que necesitas.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar

Trabajar con CopyMemory en C#

Publicado por Leo (10 intervenciones) el 13/07/2015 10:06:22
Probé a hacer esto y tampoco doy conseguido recuperar los datos a los que apunta e.pNMMR. El valor que recibo de e.NMMR es un valor int que coincide con el valor del primer elemento de la estructura (m_markfreq)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
[StructLayout(LayoutKind.Sequential)]
public struct NMMR
{
	public uint m_markfreq;
	public uint m_spacefreq;
	public uint m_siglevel;
	public uint m_sqlevel;
	public uint m_codeswitch;
	public uint m_codeview;
	public uint m_notch1;
	public uint m_baud;
	public uint m_fig;
	public uint m_radiofreq;
	[MarshalAs( UnmanagedType.ByValArray , SizeConst=53)]
	public uint[] m_Reserved;
 
	public NMMR(uint[] pNMMR)
	{
		m_markfreq = pNMMR[0];
		m_spacefreq = pNMMR[1];
		m_siglevel = pNMMR[2];
		m_sqlevel = pNMMR[3];
		m_codeswitch = pNMMR[4];
		m_codeview = pNMMR[5];
		m_notch1 = pNMMR[6];
		m_baud = pNMMR[7];
		m_fig = pNMMR[8];
		m_radiofreq = pNMMR[9];
		m_Reserved = new uint[53];
		Array.Copy(pNMMR, 10, m_Reserved, 0, 53);
	}
 
}
 
public NMMR myNMMR;
 
private void XMMR_OnNotifyNMMR(object sender, AxXMMTLib._DXMMREvents_OnNotifyNMMREvent e)
{
 
	IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(e.pNMMR));
	Marshal.StructureToPtr(myNMMR, pnt, false);
	NMMR anotherNMMR;
	anotherNMMR = (NMMR)Marshal.PtrToStructure(pnt, typeof(NMMR));
}
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Trabajar con CopyMemory en C#

Publicado por David (59 intervenciones) el 19/07/2015 12:22:04
La línea
1
IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(e.pNMMR));

Está mal. Debería ser
[codeIntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(myNMMR));][/code]
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar

Trabajar con CopyMemory en C#

Publicado por Leo (10 intervenciones) el 20/07/2015 09:18:52
Ya probara así y no funciona, porque el evento XMMR_OnNotifyNMMR me devuelve el valor del primer miembro de la estructura a través de e.pNMMR pero no consigo recuperar el resto de valores.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Trabajar con CopyMemory en C#

Publicado por David (59 intervenciones) el 21/07/2015 01:53:39
El marshaling es un poco rollo hasta que se da con la tecla :)
Antes que nada vamos a intentar ver si podemos pasar el intptr a struct, así:
1
myNMMR = (NMMR)Marshal.PtrToStructure(e.pNMMR, typeof(NMMR));
Si esto te devuelve la información correcta, podrías buscar una alternativa para copiarla. O ya vemos cómo utilizar el CopyMemory()
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar

Trabajar con CopyMemory en C#

Publicado por Leo (10 intervenciones) el 21/07/2015 09:36:57
Me da error de compilación, me dice qeu no se puede convertir de int a System.IntPtr.

El argumento e.pNMMR es de valor int, pero debería apuntar a una estructura, no?

Me da la impresion de que no voy a poder usar estos controles en C# y que me voy a tener que buscar otra alternativa...
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Trabajar con CopyMemory en C#

Publicado por David (59 intervenciones) el 21/07/2015 23:58:58
Vale, creía que ya era IntPtr.
Prueba así entonces:
1
myNMMR = (NMMR)Marshal.PtrToStructure(new IntPtr(e.pNMMR), typeof(NMMR));
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar

Trabajar con CopyMemory en C#

Publicado por Leo (10 intervenciones) el 22/07/2015 09:16:14
Hago esto:

1
2
3
4
IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(myNMMR));
myNMMR = (NMMR)Marshal.PtrToStructure(new IntPtr(e.pNMMR), typeof(NMMR));
NMMR anotherNMMR;
anotherNMMR = (NMMR)Marshal.PtrToStructure(pnt, typeof(NMMR));


y en la linea 2 me salta el siguiente error:

'FatalExecutionEngineError'

Información adicional: El runtime detectó un error irrecuperable. La dirección del error fue 0x701ecf41, en el subproceso 0x1610. El código de error es 0xc0000005. Es posible que este error sea un error de CLR o de partes no seguras y no verificables de código de usuario. Entre los orígenes más habituales de este error se encuentran los errores de cálculo de referencias para la interoperabilidad COM o PInvoke, que pueden dañar la pila.

El valor de "new IntPtr(e.pNMMR)" es 2524, que no es el valor de un puntero de memoria, sino de el valor int del primer elemento de la estructura.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Trabajar con CopyMemory en C#

Publicado por David (59 intervenciones) el 23/07/2015 17:19:05
A ver así:
1
2
3
4
unsafe
{
    myNMMR = (NMMR)Marshal.PtrToStructure(new IntPtr(&e.pNMMR), typeof(NMMR));
}
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar

Trabajar con CopyMemory en C#

Publicado por Leo (10 intervenciones) el 24/07/2015 10:33:28
Hola David, por fin conseguí acceder a los datos de la estructura haciendo esto. Tu ayuda me fue de gran utilidad, muchas gracias. Ahora a ver si consigo ponerlo a funcionar. Un saludo


1
2
3
4
5
6
7
unsafe void XMMR_OnNotifyNMMR(object sender, AxXMMTLib._DXMMREvents_OnNotifyNMMREvent e)
        {
            fixed (int* pnt = &e.pNMMR)
            myNMMR = (NMMR)Marshal.PtrToStructure(new IntPtr(pnt), typeof(NMMR));
            textBoxMarkFreq.Text = Convert.ToString(myNMMR.m_markfreq);
            textBoxSpaceFreq.Text = Convert.ToString(myNMMR.m_spacefreq);
         }
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar