Recent

Author Topic: [SOLVED] Incompatible type, Got address of procedure, expected procedure...  (Read 3953 times)

Cyrax

  • Hero Member
  • *****
  • Posts: 774
Code: Pascal  [Select]
  1. {
  2.  * Copyright (c) 1998-2015 Apple Inc. All rights reserved.
  3.  *
  4.  * @APPLE_LICENSE_HEADER_START@
  5.  *
  6.  * This file contains Original Code and/or Modifications of Original Code
  7.  * as defined in and that are subject to the Apple Public Source License
  8.  * Version 2.0 (the 'License'). You may not use this file except in
  9.  * compliance with the License. Please obtain a copy of the License at
  10.  * http://www.opensource.apple.com/apsl/ and read it before using this
  11.  * file.
  12.  *
  13.  * The Original Code and all software distributed under the License are
  14.  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  15.  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  16.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  17.  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  18.  * Please see the License for the specific language governing rights and
  19.  * limitations under the License.
  20.  *
  21.  * @APPLE_LICENSE_HEADER_END@
  22.  *
  23. }
  24. { Initial Pascal Translation for Free Pascal: Hans Luijten, <webmaster@tweaking4all.com>, May 2018 }
  25.  
  26. //{$ifc not defined MACOSALLINCLUDE or not MACOSALLINCLUDE}
  27. {$mode macpas}
  28. {$packenum 1}
  29. {$macro on}
  30. {$inline on}
  31. {$calling mwpascal}
  32.  
  33. unit DADissenter;
  34. ...
  35.  

Code: Pascal  [Select]
  1. {
  2.  * Copyright (c) 1998-2015 Apple Inc. All Rights Reserved.
  3.  *
  4.  * @APPLE_LICENSE_HEADER_START@
  5.  *
  6.  * This file contains Original Code and/or Modifications of Original Code
  7.  * as defined in and that are subject to the Apple Public Source License
  8.  * Version 2.0 (the 'License'). You may not use this file except in
  9.  * compliance with the License. Please obtain a copy of the License at
  10.  * http://www.opensource.apple.com/apsl/ and read it before using this
  11.  * file.
  12.  *
  13.  * The Original Code and all software distributed under the License are
  14.  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  15.  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  16.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  17.  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  18.  * Please see the License for the specific language governing rights and
  19.  * limitations under the License.
  20.  *
  21.  * @APPLE_LICENSE_HEADER_END@
  22.  }
  23. {  Initial Pascal Translation for Free Pascal:  Hans Luijten, <webmaster@tweaking4all.com>, May 2018 }
  24. {
  25.    Version 100
  26. }
  27. //{$ifc not defined MACOSALLINCLUDE or not MACOSALLINCLUDE}
  28.  
  29.   {$mode macpas}
  30.   {$packenum 1}
  31.   {$macro on}
  32.   {$inline on}
  33.   {$calling mwpascal}
  34.  
  35.   unit DiskArbitration;
  36.   ...
  37.  

Can you try to change {$mode macpas} to {$mode objfpc} and remove/change {$calling mwpascal} to  {$calling cdecl}? I think that those aren't needed for Mac OS X (the unix version, not earlier Macintosh (PowerPC) versions).

Hansaplast

  • Hero Member
  • *****
  • Posts: 570
  • Tweaking4All.com
    • Tweaking4All
@Cyrax;


Well, I gave your suggestion a try, but then the entire christmas-tree with error messages pops up, triggered by;

Code: Pascal  [Select]
  1. {$ifc defined CPUPOWERPC and defined CPUI386}
  2.           {$error Conflicting initial definitions for CPUPOWERPC and CPUI386}
  3. {$endc}


I'll admit I have copied everything between "interface" and "uses" from other units, and I'm not 100% sure what it all does (besides checking widget sets, CPU specifics and some mac stuff). Do I really need really these definitions?


So with that question in mind I just bluntly stripped away most of those macros.
Added "cdecl;" to each function and removed the underscore after "external".
Next I added Cyrax's suggestions (use {$mode objfpc} and  {$calling cdecl}).


And I'm back where I started haha ... so with {$mode objfpc} (in my application units - not in DiskArbitration and DADissenter) it works -with the occasional Access Violation, and with {$mode objfpc} I get the same errors as before ...


The headers now look like this (I've attached the files for those who'd want to see everything):
DiskArbitration;


Code: Pascal  [Select]
  1.   {$mode objfpc}
  2.   {$packenum 1}
  3.   {$inline on}
  4.   {$calling cdecl}
  5.  
  6.   unit DiskArbitration;
  7.   interface
  8.  
  9.  
  10.   uses MacTypes,DASession,CFBase,CFDictionary, DADisk, CFArray, DADissenter;                      


and DADissenter:



Code: Pascal  [Select]
  1. {$mode objfpc}
  2. {$packenum 1}
  3. {$inline on}
  4. {$calling cdecl}
  5.  
  6.  
  7. unit DADissenter;
  8. interface
  9.  
  10.  
  11. uses MacTypes,DASession,CFBase,CFDictionary,CFString,mach_error;    


and the returning error message ...



Code: [Select]
cocoa_applepibaker_daclass.pas(211,85) Error: Incompatible type for arg no. 4: Got "<address of procedure(DADiskRef;CFArrayRef;Pointer);CDecl>", expected "<procedure variable type of procedure(DADiskRef;CFArrayRef;Pointer);CDecl>"
DiskArbitration.pas(279,11) Hint: Found declaration: DARegisterDiskDescriptionChangedCallback(DASessionRef;CFDictionaryRef;CFArrayRef;DADiskDescriptionChangedCallback;Pointer); CDecl;

Next; test a newer FPC version.


p.s. am I the only one experiencing issues with the editor for posting in the forum here? Each time I use backspace until it jumps to the previous line, the following line becomes microscopical sized font. All kinds of [ s i z e ] tags appear ... nice for hiding message, but maybe I'm doing something wrong here? 


Jonas Maebe

  • Hero Member
  • *****
  • Posts: 687

Can you try to change {$mode macpas} to {$mode objfpc} and remove/change {$calling mwpascal} to  {$calling cdecl}? I think that those aren't needed for Mac OS X (the unix version, not earlier Macintosh (PowerPC) versions).

That is incorrect. {$mode macpas} is a syntax mode like any other and unrelated to the target platform. {$calling mwpascal} is the calling convention used by Metrowerks Pascal, which is the same as "cdecl" except that all "const" record parameters are passed by reference.

The script that created those units relies on both that dialect and the mwpascal calling convention for correctness.

And the solution to the original compilation problem is probably to change the "cdecl" into "mwpascal" for the callback declarations. The script probably failed to translate the procvars, and the person who did it manually probably manually added "cdecl" to them (while there should be nothing, since the {$calling mwpascal} means they will automatically get the correct calling convention). I don't know why the compiler says it expects a cdecl procvar rather than an mwpascal procvar though.
« Last Edit: February 14, 2019, 10:52:43 pm by Jonas Maebe »

Hansaplast

  • Hero Member
  • *****
  • Posts: 570
  • Tweaking4All.com
    • Tweaking4All
Thanks for chiming in Jonas!


So cdecl for the callbacks should be mwpascal. OK.
Does this apply for the functions themselves as well (eg. replace all cdecl's with mwpascal)?


For example:



Code: Pascal  [Select]
  1. procedure DARegisterDiskAppearedCallback( session: DASessionRef;
  2.                                           match: CFDictionaryRef;
  3.                                           callback: DADiskAppearedCallback;
  4.                                           context: UnivPtr ); mwpascal; external name 'DARegisterDiskAppearedCallback';
   

Hansaplast

  • Hero Member
  • *****
  • Posts: 570
  • Tweaking4All.com
    • Tweaking4All
Since it feels like I'm running in circles ... I tried using mwpascal and ended up with ...



Code: [Select]
cocoa_applepibaker_daclass.pas(211,85) Error: Incompatible type for arg no. 4: Got "<address of procedure(DADiskRef;CFArrayRef;Pointer);MWPascal>", expected "<procedure variable type of procedure(DADiskRef;CFArrayRef;Pointer);MWPascal>"
DiskArbitration.pas(277,11) Hint: Found declaration: DARegisterDiskDescriptionChangedCallback(DASessionRef;CFDictionaryRef;CFArrayRef;DADiskDescriptionChangedCallback;Pointer); MWPascal;


Using cdecl for the function resulted in the same error by the way, just the last mentioning of mwpascal in the error would say cdecl;



Code: [Select]
cocoa_applepibaker_daclass.pas(211,85) Error: Incompatible type for arg no. 4: Got "<address of procedure(DADiskRef;CFArrayRef;Pointer);MWPascal>", expected "<procedure variable type of procedure(DADiskRef;CFArrayRef;Pointer);MWPascal>"
DiskArbitration.pas(277,11) Hint: Found declaration: DARegisterDiskDescriptionChangedCallback(DASessionRef;CFDictionaryRef;CFArrayRef;DADiskDescriptionChangedCallback;Pointer); cdecl;

Cyrax

  • Hero Member
  • *****
  • Posts: 774

Can you try to change {$mode macpas} to {$mode objfpc} and remove/change {$calling mwpascal} to  {$calling cdecl}? I think that those aren't needed for Mac OS X (the unix version, not earlier Macintosh (PowerPC) versions).

That is incorrect. {$mode macpas} is a syntax mode like any other and unrelated to the target platform. {$calling mwpascal} is the calling convention used by Metrowerks Pascal, which is the same as "cdecl" except that all "const" record parameters are passed by reference.

The script that created those units relies on both that dialect and the mwpascal calling convention for correctness.

And the solution to the original compilation problem is probably to change the "cdecl" into "mwpascal" for the callback declarations. The script probably failed to translate the procvars, and the person who did it manually probably manually added "cdecl" to them (while there should be nothing, since the {$calling mwpascal} means they will automatically get the correct calling convention). I don't know why the compiler says it expects a cdecl procvar rather than an mwpascal procvar though.

Thanks, Jonas, for clarification!  :)

Jonas Maebe

  • Hero Member
  • *****
  • Posts: 687
Since it feels like I'm running in circles ...

The problem is that you have not posted your test program (at least I didn't see it), so everyone has to guess how to make it compilable. My guess is that you are adding MacOSAll to its the uses clause. That unit simply contains all universal interfaces units (such as MacTypes, CFBase etc) as include files. This means that it defines the same types as those individual units.

Your DADissenter and DiskArbitration units contain the individual units, and hence use the types from those individual units. If your main program uses MacOSAll, it will use types with the same name from the MacOSAll unit instead. In Pascal, two structurally equivalent types are not necessarily compatible, even if they have the same name. In this case, the solution will be to also use the individual units from the universal interfaces in your test program instead of MacOSAll.

Jonas Maebe

  • Hero Member
  • *****
  • Posts: 687
An alternative could also be to replace the uses clause in your DA units with just "uses MacOSAll" (and the other DA unit if applicable).

Hansaplast

  • Hero Member
  • *****
  • Posts: 570
  • Tweaking4All.com
    • Tweaking4All
Hi Jonas,


I'm taking note of your input and am trying to build a small test application for this - hope to get back today with an example.  :)

Hansaplast

  • Hero Member
  • *****
  • Posts: 570
  • Tweaking4All.com
    • Tweaking4All

Thanks Guys!
I think I have "fixed" it - would have not been able to do this with all the input and suggested you guys provided!
This has been an educational experience.  :D


I have attached an example project, which uses the callbacks for DiskAppeared, DiskDisappeared and DiskDescriptionChanged.
So when a disk becomes available, or is removed, or is changed (mount/unmount/volumename/etc), MacOS will use the callbacks to notify the test application.
For those interested;
  • the "context" variable can be used to pass a message. For example when you programmatically eject a disk, you could pass the message "ejected by me" and on DiskDisappear that message can be found in the context (default context='').
  • DAVolumePath: When the path of a disk changes (eg. mount,  unmount, change volumename)
  • DAVolumeName: When you rename a disk
(screenshot attached as well)


So to get it to work, I've set;
Code: Pascal  [Select]
  1. {$mode macpas}
  2. {$calling mwpascal}


Added the DiskArbitration framework in the DiskArbitration unit - which I originally had in the application unit itself (is this the right place?):
Code: Pascal  [Select]
  1. {$linkframework DiskArbitration}


Remove any cdecl/mwpascal from the function definitions, like so;
Code: Pascal  [Select]
  1. procedure DARegisterDiskDescriptionChangedCallback( session: DASessionRef;
  2.                                                     match: CFDictionaryRef;
  3.                                                     watch: CFArrayRef;
  4.                                                     callback: DADiskDescriptionChangedCallback;
  5.                                                     context: UnivPtr ); external name '_DARegisterDiskDescriptionChangedCallback';


Defined the callback functions with mwpascal, like so;
Code: Pascal  [Select]
  1. DADiskDisappearedCallback = procedure( disk: DADiskRef; context: univptr); mwpascal;