Прежде всего, если вы взаимодействуете с собственными COM-клиентами, я бы предложил использовать COM-события вместо обратных вызовов
Кроме того, я бы предложил не использовать [ClassInterface(ClassInterfaceType.AutoDual)]
, поскольку он генерируетмного беспорядка в сгенерированных файлах tlh / tli.Вместо этого определите интерфейс и реализуйте его в своем классе.
public delegate double FunctionCallback(int arg);
[ComVisible(true)]
[Guid("5F11C485-0AA8-461D-BB56-32D620D17311")]
public interface ITestServer
{
double Connect([MarshalAs(UnmanagedType.FunctionPtr)] FunctionCallback callback, int arg);
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class TestServer : ITestServer
{
public double Connect(FunctionCallback callback, int arg)
{
Console.Out.WriteLine("In server, calling callback...");
return callback(arg);
}
}
Вам не нужно отправлять обратный вызов по ссылке (ref CallBackFunction
), поскольку вы не будете изменять его, чтобы он указывал на другойреализации, и поскольку Callback
совпадает с &Callback
, вы все равно не можете разыменовать его - вот почему он падает.
В вашем родном клиенте обратный вызов будет смоделирован как long
:
double Connect (long callback, long arg );
При отправке указателя функции просто приведите его к long
:
double triple(int arg) {
return arg * 3.0;
}
double halve(int arg) {
return arg / 2.0;
}
int main() {
CoInitialize(NULL);
server::ITestServerPtr svr(__uuidof(server::TestServer));
printf("tripled: %g\n", svr->Connect((long)triple, 5));
printf("halved: %g\n", svr->Connect((long)halve, 5));
return 0;
}