classdef (ConstructOnLoad = true) DLLReference < handle
% Class intended to be used as a base class for establishing references   
% to a specific DLL.
%
% First time an object of this class is created the DLL is loaded.
%
% When the last object of this class is destroyed, the DLL is
% unloaded.
  properties (SetAccess = 'private', GetAccess = 'private', Transient=true)
    is_attached = 0;
  end
  methods
    function obj = DLLReference
      % Attach to dll
      DLLReference.instance_operation(true);
      obj.is_attached = 1;
    end
    
    % Called automatically by matlab when object being cleared
    function delete(obj)
      % Detach from dll
      DLLReference.instance_operation(false);
    end
    
  end
  
  methods(Static=true, Access='private')
    function instance_operation(direction)
    % direction true to add a reference, false to remove
      persistent references;
      if isempty(references)
        references = 0;
      end
      if direction 
        if references == 0
          disp 'Loading DLL'
          % Customise path and name, perhaps change to header file approach
          loadlibrary( ...
              'C:\path_to_your_dll\FortranObject.dll', ...
              @prototypes, 'alias', DLLReference.alias_name );
        end
        references = references + 1;
      else        
        if references > 0
          references = references - 1;
          if references == 0
            disp 'Unloading DLL'
            unloadlibrary(DLLReference.alias_name);
          end
        end
      end        
    end
  end 

  methods(Static=true, Access='protected', Sealed=true)
    function name = alias_name
      name = 'UniqueDLLAlias';
    end
  end  
end


function [methodinfo,structs,enuminfo,ThunkLibName]=prototypes
  ival = { cell(1,3)};   % Preallocate
  structs = [];
  enuminfo = [];
  fcnNum = 1;
  fcns=struct('name',ival,'calltype',ival,'LHS',ival,'RHS',ival,'alias',ival);
  ThunkLibName=[];
  
  fcns.name{fcnNum}='Construct'; 
  fcns.calltype{fcnNum}='cdecl';
  fcns.LHS{fcnNum}='voidPtr';
  fcns.RHS{fcnNum}={'double'};
  fcnNum = fcnNum + 1;
  
  fcns.name{fcnNum}='Destruct'; 
  fcns.calltype{fcnNum}='cdecl';
  fcns.LHS{fcnNum}=[];
  % Pass in object allocated using Construct
  fcns.RHS{fcnNum}={'voidPtr'};
  fcnNum = fcnNum + 1;
  
  fcns.name{fcnNum}='DoSomethingUseful'; 
  fcns.calltype{fcnNum}='cdecl';
  fcns.LHS{fcnNum}='double';
  % Pass in object allocated using Construct
  fcns.RHS{fcnNum}={'voidPtr', 'double'};
  fcnNum = fcnNum + 1;

  % Other exported functions in DLL would follow

  methodinfo=fcns;
end