If you want to build a reliable solution, you should use the following:
- Calls from C# to C++ functions. Keep types of parameters as simple as possible. Any C# thread can make these calls.
- Start your own C++ threads that read/modify only the C++ data and call only the C++ methods and functions.
- Use Windows kernel objects for synchronization and other similar stuffs. It is fine when one side signals the event and the other side waits for it.
Other types of interaction are possible but I would discourage from using them. These additional types are not simple and not that clearly defined, contain caveats, etc. The 3 methods above allow building complex applications.
To call a C++ finction, add to your assembly:
[DllImport("User32.dll")]
static extern Boolean MessageBeep(UInt32 beepType);
This tells that User32 has and entry point MessageBeep that your want to call. After that you can use it as any other function:
MessageBeep(0);
In a similar way you can call GetProcAddress or any other entry point in your own DLL.