Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 831
  • Last Modified:

C# callback handler and type conversions

I have an API (I have control over it) written in C that accepts a callback target. During execution, the API will call back presenting an event code and a void * for the event context. Its the basic WndProc model (where the LPARAM will be cast'ed to the appropriate struct pointer), where depending on the event the context is converted to a pointer to a structure specific to that event.

In C#, the callback works, thats simple. What doesnt work is my efforts to on event X, convert the void * context argument to a C# structure.

How do I get the generic void * argument converted to a C# struct of type X for an event type of X, and a type of Y for event type Y?

I can of course take the brute force method of setting multiple callback targets, one for each event type, where the callback context is a known structure type, but thats less than ideal. Then again, its a small set of events, so maybe ill go that way. Regardless, this is something id like to understand going forward.

Im hoping this is a function of the language (C#) that I do net understand fully, so ive listed this as 'easy'.

Thanks
0
Escobar
Asked:
Escobar
  • 3
1 Solution
 
EscobarAuthor Commented:
Code, if my question was not clear...

C API

extern "C"
{

//     Define the signature for a callback event handler
typedef unsigned int (CALLBACK  * EGLEVENTTARGETPROC)(unsigned int eventId, void * context);
}

EGLAPIEXPORT bool eglApplicationStart(EGLEVENTTARGETPROC eventTarget);

typedef struct tagEVENT_DUMMY
{
unsigned int test;
} EVENT_DUMMY, * PEVENT_DUMMY;

C# client

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct EventDummy
{
public uint test;
}

public delegate uint _EventHandler(uint eventId, [MarshalAs(UnmanagedType.SysInt)] IntPtr context);

public static uint eventHandler(uint eventId, IntPtr context)
{
  switch (eventId)
  {
    case 0: // Dummy EVent
    {
      // Now, how do I get the context in to a usable EventDummy structure?
    }
    break;
  }

  return (0);
}



0
 
EscobarAuthor Commented:
Code, if my question was not clear...

C API

extern "C"
{

//     Define the signature for a callback event handler
typedef unsigned int (CALLBACK  * EGLEVENTTARGETPROC)(unsigned int eventId, void * context);
}

EGLAPIEXPORT bool eglApplicationStart(EGLEVENTTARGETPROC eventTarget);

typedef struct tagEVENT_DUMMY
{
unsigned int test;
} EVENT_DUMMY, * PEVENT_DUMMY;

C# client

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct EventDummy
{
public uint test;
}

public delegate uint _EventHandler(uint eventId, [MarshalAs(UnmanagedType.SysInt)] IntPtr context);

public static uint eventHandler(uint eventId, IntPtr context)
{
  switch (eventId)
  {
    case 0: // Dummy EVent
    {
      // Now, how do I get the context in to a usable EventDummy structure?
    }
    break;
  }

  return (0);
}



0
 
Nebulus_Commented:
I think that the key for your problem is unsafe zone in code. (project must be compiled with unsafe option) I hope this code helps you:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public unsafe struct EvDummy1 {
  public bool test1;
  public uint test2;
}

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public unsafe struct EvDummy2 {
  public uint test1;
  public bool test2;
}

private unsafe void testIntPtr(int i, byte* aux) {
  switch(i) {
    case 0:
      MessageBox.Show((*(EvDummy1*)aux).test1.ToString());
      MessageBox.Show((*(EvDummy1*)aux).test2.ToString());
      break;
    case 1:
      MessageBox.Show((*(EvDummy2*)aux).test1.ToString());
      MessageBox.Show((*(EvDummy2*)aux).test2.ToString());
      break;
  }
}

private unsafe void button5_Click(object sender, System.EventArgs e) {
  EvDummy1 a = new EvDummy1();
  a.test1 = true;
  a.test2 = 1;
  EvDummy2 b = new EvDummy2();
  b.test1 = 0;
  b.test2 = false;

  testIntPtr(0, (byte*)&a);
  testIntPtr(1, (byte*)&b);
}
0
 
EscobarAuthor Commented:
Sometimes you just need to walk away for a few days. Your suggestion, while not technically correct, did help me to find the answer.

I understand the need for unsafe code marking, at the method and project level and that was already in place. At first, on reading your answer, I though that the problem may have been that I was not marking the structure definitions as unsafe. But the problem actually was that the structure in question, contains as a member, a managed type reference. The C api works with components that are also addressed by .NET classes. So the C API may return an object interface pointer that I can share with the .NET code. My mistake was listing the member of the struct as the .NET managed type and not as a generic intptr and performing a conversion later on in code. I was simply misreading the error as if it referred to my use of the structure itself, instead of in m use of n embedded managed type within an unmanaged or unsafe  structure.


Thanks very much
0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now