?
Solved

C# callback handler and type conversions

Posted on 2003-03-04
4
Medium Priority
?
829 Views
Last Modified: 2010-05-18
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
Comment
Question by:Escobar
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
4 Comments
 

Author Comment

by:Escobar
ID: 8068789
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
 

Author Comment

by:Escobar
ID: 8068836
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
 
LVL 4

Accepted Solution

by:
Nebulus_ earned 100 total points
ID: 8081262
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
 

Author Comment

by:Escobar
ID: 8083492
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

On Demand Webinar - Networking for the Cloud Era

This webinar discusses:
-Common barriers companies experience when moving to the cloud
-How SD-WAN changes the way we look at networks
-Best practices customers should employ moving forward with cloud migration
-What happens behind the scenes of SteelConnect’s one-click button

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Summary: Persistence is the capability of an application to store the state of objects and recover it when necessary. This article compares the two common types of serialization in aspects of data access, readability, and runtime cost. A ready-to…
Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
In this video, Percona Solution Engineer Dimitri Vanoverbeke discusses why you want to use at least three nodes in a database cluster. To discuss how Percona Consulting can help with your design and architecture needs for your database and infras…
How to fix incompatible JVM issue while installing Eclipse While installing Eclipse in windows, got one error like above and unable to proceed with the installation. This video describes how to successfully install Eclipse. How to solve incompa…
Suggested Courses
Course of the Month10 days, 8 hours left to enroll

764 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question