title: Is it possible to call the Nikon SDK from Swift?
body: <p>I am trying to interface with a Z series camera using the Nikon SDK, which I assume provides a C interface (Maid3.h, Maid3d1.h). I have included the MAID headers in the bridging header.</p>
  <p>Bridging-Header.h</p>
  <pre><code>#include    &quot;Foundation/Foundation.h&quot;
  #include    &quot;Maid3.h&quot;
  #include    &quot;Maid3d1.h&quot;
  </code></pre>
  <p>But am having some trouble figuring out how to call some of the MAID APIs.  For example:</p>
  <p>Loading the library - their sample code (*.cpp) is as follows:</p>
  <pre><code>//------------------------------------------------------------------------------------------------
  //
  SLONG CallMAIDEntryPoint( 
          LPNkMAIDObject  pObject,                // module, source, item, or data object
          ULONG               ulCommand,          // Command, one of eNkMAIDCommand
          ULONG               ulParam,                // parameter for the command
          ULONG               ulDataType,         // Data type, one of eNkMAIDDataType
          NKPARAM         data,                   // Pointer or long integer
          LPNKFUNC            pfnComplete,        // Completion function, may be NULL
          NKREF               refComplete )       // Value passed to pfnComplete
  {
      return (*(LPMAIDEntryPointProc)g_pMAIDEntryPoint)( 
                          pObject, ulCommand, ulParam, ulDataType, data, pfnComplete, refComplete );
  }
  //------------------------------------------------------------------------------------------------
  //
  BOOL Search_Module( void* Path )
  {
  
      CFStringRef modulePath = NULL;
      
      CFStringRef moduleName = CFSTR( &quot;Type0024 Module.bundle&quot; );
      CFBundleRef bundle = CFBundleGetMainBundle();
      if(bundle != NULL)
      {
          CFURLRef executableURL = CFBundleCopyExecutableURL( bundle );
          if(executableURL != NULL)
          {
              CFURLRef parentFolderURL = CFURLCreateCopyDeletingLastPathComponent( kCFAllocatorDefault, executableURL );
              if(parentFolderURL != NULL)
              {
                  CFURLRef moduleURL = CFURLCreateCopyAppendingPathComponent( kCFAllocatorDefault, parentFolderURL, moduleName, FALSE );
                  if(moduleURL != NULL)
                  {
                      if(CFURLResourceIsReachable( moduleURL, NULL ))
                      {
                          modulePath = CFURLCopyFileSystemPath( moduleURL, kCFURLPOSIXPathStyle );
                      }
                      CFRelease( moduleURL );
                  }
                  CFRelease( parentFolderURL );
              }
              CFRelease( executableURL );
          }
      }
      
      Boolean result = FALSE;
      if(modulePath != NULL)
      {
          result = CFStringGetCString( modulePath, (char *)Path, PATH_MAX, kCFStringEncodingUTF8 );
          CFRelease( modulePath );
      }
      return result;
  
  }
  //------------------------------------------------------------------------------------------------
  //
  BOOL Load_Module( void* Path )
  {
  
      CFStringRef modulePath = CFStringCreateWithCString( kCFAllocatorDefault, (const char *)Path, kCFStringEncodingUTF8 );
      if(modulePath != NULL)
      {
          CFURLRef moduleURL = CFURLCreateWithFileSystemPath( kCFAllocatorDefault, modulePath, kCFURLPOSIXPathStyle, TRUE );
          if(moduleURL != NULL)
          {
              if(gBundle != NULL)
              {
                  CFRelease( gBundle );
                  gBundle = NULL;
              }
              gBundle = CFBundleCreate( kCFAllocatorDefault, moduleURL );
              CFRelease( moduleURL );
          }
          CFRelease( modulePath );
      }
      
      if(gBundle == NULL)
      {
          return FALSE;
      }
      
      // Load and link dynamic CFBundle object
      if(!CFBundleLoadExecutable(gBundle))
      {
          CFRelease( gBundle );
          gBundle = NULL;
          return FALSE;
      }
      
      // Get entry point from BundleRef
      // Set the pointer for Maid entry point LPMAIDEntryPointProc type variabl
      g_pMAIDEntryPoint = (LPMAIDEntryPointProc)CFBundleGetFunctionPointerForName( gBundle, CFSTR(&quot;MAIDEntryPoint&quot;) );
      return (g_pMAIDEntryPoint != NULL);
  
  }
  //------------------------------------------------------------------------------------------------
  //
  BOOL Command_Open( NkMAIDObject* pParentObj, NkMAIDObject* pChildObj, ULONG ulChildID )
  {
      SLONG lResult = CallMAIDEntryPoint( pParentObj, kNkMAIDCommand_Open, ulChildID, 
                                      kNkMAIDDataType_ObjectPtr, (NKPARAM)pChildObj, NULL, NULL );
      return lResult == kNkMAIDResult_NoError;
  }
  //------------------------------------------------------------------------------------------------
  //
  BOOL Command_Close( LPNkMAIDObject pObject )
  {
      SLONG nResult = CallMAIDEntryPoint( pObject, kNkMAIDCommand_Close, 0, 0, 0, NULL, NULL );
  
      return nResult == kNkMAIDResult_NoError;
  }
  </code></pre>
  <p>My conversion of that to Swift is as follows:</p>
  <pre><code>var gBundle: CFBundle? = nil
  var g_pMAIDEntryPoint: LPMAIDEntryPointProc?
  var g_bFileRemoved: UCHAR     = 0
  var g_ulCameraType: ULONG     = 0    // CameraType
  
  func Search_Module()-&gt;String?
  {
      var modulePath: CFString? = nil
      
      let moduleName = &quot;Type0024 Module.bundle&quot; as CFString
      let bundle = CFBundleGetMainBundle();
      if(bundle != nil)
      {
          let executableURL = CFBundleCopyExecutableURL( bundle );
          if(executableURL != nil)
          {
              let parentFolderURL = CFURLCreateCopyDeletingLastPathComponent( kCFAllocatorDefault, executableURL );
              if(parentFolderURL != nil)
              {
                  let moduleURL = CFURLCreateCopyAppendingPathComponent( kCFAllocatorDefault, parentFolderURL, moduleName, false );
                  if(moduleURL != nil)
                  {
                      if(CFURLResourceIsReachable( moduleURL, nil ))
                      {
                          modulePath = CFURLCopyFileSystemPath( moduleURL, CFURLPathStyle.cfurlposixPathStyle );
                      }
                      //CFRelease( moduleURL );
                  }
                  //CFRelease( parentFolderURL );
              }
              //CFRelease( executableURL );
          }
      }
      
      
      if(modulePath != nil)
      {
          //result = CFStringGetCString( modulePath, path, Int(PATH_MAX), CFStringBuiltInEncodings.UTF8.rawValue );
          //CFRelease( modulePath );
          return modulePath as String?
      }
      return nil
    
  }
  
  func Load_Module( path: String )-&gt;Bool
  {
     
      let modulePath = CFStringCreateWithCString( kCFAllocatorDefault, path, CFStringBuiltInEncodings.UTF8.rawValue);
      
      if(modulePath != nil)
      {
          let moduleURL = CFURLCreateWithFileSystemPath( kCFAllocatorDefault, modulePath, CFURLPathStyle.cfurlposixPathStyle, true );
          
          if(moduleURL != nil)
          {
              if(gBundle != nil)
              {
                  //CFRelease( gBundle );
                  gBundle = nil;
              }
              gBundle = CFBundleCreate( kCFAllocatorDefault, moduleURL );
              //CFRelease( moduleURL );
          }
          //CFRelease( modulePath );
      }
      
      if(gBundle == nil)
      {
          return false
      }
      
      // Load and link dynamic CFBundle object
      if(!CFBundleLoadExecutable(gBundle))
      {
          //CFRelease( gBundle );
          gBundle = nil;
          return false
      }
      
      // Get entry point from BundleRef
      // Set the pointer for Maid entry point LPMAIDEntryPointProc type variabl
      g_pMAIDEntryPoint = CFBundleGetFunctionPointerForName( gBundle, &quot;MAIDEntryPoint&quot; as CFString) as? LPMAIDEntryPointProc
      return (g_pMAIDEntryPoint != nil)
  }
  func CallMAIDEntryPoint(
      _ pObject: LPNkMAIDObject,                // module, source, item, or data object
      _ ulCommand: ULONG                ,            // Command, one of eNkMAIDCommand
      _ ulParam: ULONG                ,                // parameter for the command
      _ ulDataType: ULONG                ,            // Data type, one of eNkMAIDDataType
      _ data: NKPARAM            ,                    // Pointer or long integer
      _ pfnComplete: LPNKFUNC?            ,            // Completion function, may be NULL
      _ refComplete: NKREF?                 )-&gt;Int32?        // Value passed to pfnComplete
  {
      return g_pMAIDEntryPoint?(
                          pObject, ulCommand, ulParam, ulDataType, data, pfnComplete, refComplete );
  }
  func Command_Open( pParentObj: LPNkMAIDObject, pChildObj: NKPARAM, ulChildID: ULONG)-&gt;Bool
  {
      let lResult = CallMAIDEntryPoint( pParentObj, kNkMAIDCommand_Open.rawValue, ulChildID,
                                        kNkMAIDDataType_ObjectPtr.rawValue, pChildObj, nil, nil );
      return lResult == kNkMAIDResult_NoError.rawValue;
  }
  //------------------------------------------------------------------------------------------------
  //
  func Command_Close( pObject: LPNkMAIDObject)-&gt;Bool
  {
      let nResult = CallMAIDEntryPoint( pObject, kNkMAIDCommand_Close.rawValue, 0, 0, 0, nil, nil );
  
      return nResult == kNkMAIDResult_NoError.rawValue;
  }
  </code></pre>
  <p>However the call to ge the function entry point generates a warning indicating that it will always fail.</p>
  <pre><code>g_pMAIDEntryPoint = CFBundleGetFunctionPointerForName( gBundle, &quot;MAIDEntryPoint&quot; as CFString) as? LPMAIDEntryPointProc
  
  Cast from 'UnsafeMutableRawPointer?' to unrelated type 'LPMAIDEntryPointProc' (aka '@convention(c) (Optional&lt;UnsafeMutablePointer&lt;tagNkMAIDObject&gt;&gt;, UInt32, UInt32, UInt32, UInt64, Optional&lt;UnsafeMutableRawPointer&gt;, Optional&lt;UnsafeMutableRawPointer&gt;) -&gt; Int32') always fails
  </code></pre>
  <p>The definition is as follows:</p>
  <pre><code>// Client/Module Interface and Callback Functions
  typedef W32EXPORT NKERROR CALLPASCAL WINAPI MAIDEntryPointProc (
      LPNkMAIDObject  pObject,                // module, source, item, or data object
      ULONG               ulCommand,          // Command, one of eNkMAIDCommand
      ULONG               ulParam,                // parameter for the command
      ULONG               ulDataType,         // Data type, one of eNkMAIDDataType
      NKPARAM         data,                   // Pointer or long integer
      LPNKFUNC            pfnComplete,        // Completion function, may be NULL
      NKREF               refComplete );      // Value passed to pfnComplete
  typedef MAIDEntryPointProc FAR* LPMAIDEntryPointProc;
  </code></pre>
  <p>So I have a few questions:</p>
  <ol>
  <li>Is it feasible to call the Nikon SDK libraries from Swift</li>
  <li>If so is the above approach the best way to call the functions in the library</li>
  <li>How do I call the c functions (and I assume they are c functions) from Swift?</li>
  <li>It also seems the library needs to be loaded and retained in some way - is there a way to create a Swift object to wrap the library and if so where can I find examples of how to do so?</li>
  </ol>