2

I´m trying to get the MultiPeerConnectivity-Framework to work in Delphi. Everything works fine until the Point where i need to call the invitationHandler in the MCNearbyServiceAdvertiserDelegate.

procedure TMCNearbyServiceAdvertiserDelegate.advertiser(advertiser: MCNearbyServiceAdvertiser;
 didReceiveInvitationFromPeer: MCPeerID; withContext: NSData;
 invitationHandler: TMCNearbyServiceAdvertiserDelegateBlockMethod1);

The Peers are finding each other and are exchanging Discoveryinfo. The 'Client' uses the MCNearbyServiceBrowser to connect to the MCNearbyServiceAdvertiser in the 'Server'.

When calling the invitationHandler-BlockMethod an AccessViolation is thrown :(

Now i´ve tried using the method imp_implementationWithBlock to get the code for the Handler:

procedure TMCNearbyServiceAdvertiserDelegate.advertiser(advertiser: MCNearbyServiceAdvertiser;
  didReceiveInvitationFromPeer: MCPeerID; withContext: NSData;
  invitationHandler: TMCNearbyServiceAdvertiserDelegateBlockMethod1);
var
  MainForm: TMainForm;

  aImp: procedure(accept: Boolean; session: MCSession); cdecl;
begin
  MainForm := application.MainForm as TMainForm;

  if MainForm.fSession = nil then
  begin
    MainForm.fSession := TMCSession.Alloc;
    MainForm.fSession.initWithPeer(MainForm.fPeerId);
    MainForm.fSessionDelegate := TMCSessionDelegate.Create;
    MainForm.fSession.setDelegate(MainForm.fSessionDelegate.GetObjectID);
  end; 
   
  @aImp := imp_implementationWithBlock(invitationHandler);
  aImp(True, MainForm.fSession);
  imp_removeBlock(@aImp);
end;

But with that Approch i get an error because the invitationHandler is no Pointer i guess.

Definition of the TMCNearbyServiceAdvertiserDelegateBlockMethod1 in the iOSApi.MultiPeerConnectivity.pas from Kastri:

  TMCNearbyServiceAdvertiserDelegateBlockMethod1 = procedure(accept: Boolean; session: MCSession) of object;

i hope thats not to much information a once. Any help toward calling that invitationHandler the right way would be very appreciated!

Max
  • 41
  • 7
  • Try making the type for invitationHandler as a Pointer instead of TMCNearbyServiceAdvertiserDelegateBlockMethod1, in MCNearbyServiceAdvertiserDelegate. If that works, I'll update the import. – Dave Nottage Jul 29 '22 at 13:08
  • Well, that didn't work, but I expect the block method references should be pointers because that is consistent with all the others throughout the iOS frameworks. I've created a gist of my own work, [here](https://gist.github.com/DelphiWorlds/912a3020502ec4f283ae36cd36bc6113). – Dave Nottage Jul 30 '22 at 23:39
  • I've changed the code in the gist to now use the Assistant by default, which obviously works around the crash since the Advertiser is not used. This might help at least until the crash is resolved. The Assistant uses a simple dialog to Accept or Cancel when being invited – Dave Nottage Jul 31 '22 at 01:05

1 Answers1

3

Finally solved it!

I found a similar case in the System.Net.HttpClient.Mac unit in Delphi, in the TMacConnectionDataDelegate.URLSessionTaskDidReceiveChallengeCompletionHandler method. Block handlers need to include a second parameter declared as a Pointer. I cannot remember why this is, I just know it works :-) The session parameter also needs to be a Pointer, and use the NSObjectToID method to turn your reference into a pointer for that parameter.

As per my comments in the question, you need to change the block method type to a Pointer (instead of TMCNearbyServiceAdvertiserDelegateBlockMethod1) in the delegate interface and the implementation, and declare the block handler method as discussed above, so this should work for you:

procedure TMCNearbyServiceAdvertiserDelegate.advertiser(advertiser: MCNearbyServiceAdvertiser;
  didReceiveInvitationFromPeer: MCPeerID; withContext: NSData;
  invitationHandler: Pointer);
var
  MainForm: TMainForm;

  aImp: procedure(accept: Boolean; ignored: Pointer; session: Pointer); cdecl;
begin
  MainForm := application.MainForm as TMainForm;

  if MainForm.fSession = nil then
  begin
    MainForm.fSession := TMCSession.Alloc;
    MainForm.fSession.initWithPeer(MainForm.fPeerId);
    MainForm.fSessionDelegate := TMCSessionDelegate.Create;
    MainForm.fSession.setDelegate(MainForm.fSessionDelegate.GetObjectID);
  end; 
   
  @aImp := imp_implementationWithBlock(invitationHandler);
  aImp(True, nil, NSObjectToID(MainForm.fSession));
  imp_removeBlock(@aImp);
end;
Dave Nottage
  • 3,411
  • 1
  • 20
  • 57