Browse Source

pas2js: utility functions for com interfaces

git-svn-id: trunk@38697 -
Mattias Gaertner 7 years ago
parent
commit
52b1649b8f
1 changed files with 119 additions and 16 deletions
  1. 119 16
      utils/pas2js/dist/rtl.js

+ 119 - 16
utils/pas2js/dist/rtl.js

@@ -381,9 +381,9 @@ var rtl = {
         throw t.$create("create");
       }
     }
-    if (typename == "EInvalidCast") throw "invalid type cast";
-    if (typename == "EAbstractError") throw "Abstract method called";
-    if (typename == "ERangeError") throw "range error";
+    if (typename === "EInvalidCast") throw "invalid type cast";
+    if (typename === "EAbstractError") throw "Abstract method called";
+    if (typename === "ERangeError") throw "range error";
     throw typename;
   },
 
@@ -401,6 +401,7 @@ var rtl = {
     //console.log('createInterface name="'+name+'" guid="'+guid+'" names='+fnnames);
     var i = ancestor?Object.create(ancestor):{};
     module[name] = i;
+    i.$module = module;
     i.$name = name;
     i.$fullname = module.$name+'.'+name;
     i.$guid = guid;
@@ -431,37 +432,52 @@ var rtl = {
         var fnname = map[intfname];
         if (!fnname) fnname = intfname;
         let fn = aclass[fnname];
-        console.log('addIntf: intftype='+t.$name+' index='+i+' intfname="'+intfname+'" fnname="'+fnname+'" proc='+typeof(fn));
+        //console.log('addIntf: intftype='+t.$name+' index='+i+' intfname="'+intfname+'" fnname="'+fnname+'" proc='+typeof(fn));
         if (typeof(fn)==="function"){
           item[intfname] = function(){ return fn.apply(this.$o,arguments); };
         } else {
-          item[intfname] = rtl.raiseE('EAbstractError');
+          item[intfname] = function(){ rtl.raiseE('EAbstractError'); };
         }
       }
       t = Object.getPrototypeOf(t);
     }while(t!=null);
   },
 
-  getIntfG: function (obj, guid){
+  getIntfG: function (obj, guid, query){
     if (!obj) return null;
-    console.log('getIntfG: obj='+obj.$classname+' guid='+guid);
+    //console.log('getIntfG: obj='+obj.$classname+' guid='+guid+' query='+query);
     // search
     var maps = obj.$class.$intfmaps;
     if (!maps) return null;
     var item = maps[guid];
     if (!item) return null;
     // check delegation
-    if (typeof item == 'function') return item.call(obj);
+    //console.log('getIntfG: obj='+obj.$classname+' guid='+guid+' query='+query+' item='+typeof(item));
+    if (typeof item === 'function') return item.call(obj);
     // check cache
+    var intf = null;
     if (obj.$interfaces){
       intf = obj.$interfaces[guid];
-      console.log('getIntfG: obj='+obj.$classname+' guid='+guid+' cache='+typeof(intf));
-      if (intf) return intf;
+      // intf can be undefined!
+      //console.log('getIntfG: obj='+obj.$classname+' guid='+guid+' cache='+typeof(intf));
+    }
+    if (!intf){
+      intf = Object.create(item);
+      intf.$o = obj;
+      if (!obj.$interfaces) obj.$interfaces = {};
+      obj.$interfaces[guid] = intf;
+    }
+    if (query===1){
+      var o = null;
+      if (intf.QueryInterface(guid,
+          {get:function(){ return o; }, set:function(v){ o=v; }}) === 0){
+        return o;
+      } else {
+        return null;
+      }
+    } else if(query===2){
+      intf._AddRef();
     }
-    var intf = Object.create(item);
-    intf.$o = obj;
-    if (!obj.$interfaces) obj.$interfaces = {};
-    obj.$interfaces[guid] = intf;
     return intf;
   },
 
@@ -469,6 +485,27 @@ var rtl = {
     return rtl.getIntfG(obj,intftype.$guid);
   },
 
+  queryIntfG: function(obj,guid){
+    return rtl.getIntfG(obj,guid,1);
+  },
+
+  queryIntfT: function(obj,intftype){
+    return rtl.queryIntfG(obj,intftype.$guid);
+  },
+
+  queryIntfIsT: function(obj,intftype){
+    var i = rtl.queryIntfG(obj,intftype.$guid);
+    if (!i) return false;
+    if (i._Release) i._Release();
+    return true;
+  },
+
+  asIntfT: function (obj,intftype){
+    var i = getIntfG(obj,intftype.$guid);
+    if (i!==null) return i;
+    rtl.raiseEInvalidCast();
+  },
+
   intfIsClass: function(intf,classtype){
     return (intf!=null) && (rtl.is(intf.$o,classtype));
   },
@@ -479,10 +516,76 @@ var rtl = {
   },
 
   intfToClass: function(intf,classtype){
-    if ((intf!=null) && rtl.is(intf.$o,classtype)) return intf.$o;
+    if ((intf!==null) && rtl.is(intf.$o,classtype)) return intf.$o;
     return null;
   },
 
+  // interface reference counting
+  intfRefs: { // base object for temporary interface variables
+    ref: function(id,intf){
+      // called for temporary interface references needing delayed release
+      var old = this[id];
+      //console.log('rtl.intfRefs.ref: id='+id+' old="'+(old?old.$name:'null')+'" intf="'+(intf?intf.$name:'null'));
+      if (old){
+        // called again, e.g. in a loop
+        delete this[id];
+        old._Release(); // may fail
+      }
+      this[id]=intf;
+      return intf;
+    },
+    free: function(){
+      //console.log('rtl.intfRefs.free...');
+      for (id in this){
+        if (this.hasOwnProperty(id)) this[id]._Release;
+      }
+    },
+  },
+
+  createIntfRefs: function(){
+    //console.log('rtl.createIntfRefs');
+    return Object.create(rtl.intfRefs);
+  },
+
+  setIntfP: function(path,name,value,skipAddRef){
+    var old = path[name];
+    //console.log('rtl.setIntfP path='+path+' name='+name+' old="'+(old?old.$name:'null')+'" value="'+(value?value.$name:'null')+'"');
+    if (old === value) return;
+    if (old !== null){
+      path[name]=null;
+      old._Release();
+    }
+    if (value !== null){
+      if (!skipAddRef) value._AddRef();
+      path[name]=value;
+    }
+  },
+
+  setIntfL: function(old,value,skipAddRef){
+    //console.log('rtl.setIntfL old="'+(old?old.$name:'null')+'" value="'+(value?value.$name:'null')+'"');
+    if (old !== value){
+      if (value!==null){
+        if (!skipAddRef) value._AddRef();
+      }
+      if (old!==null){
+        old._Release();  // Release after AddRef, to avoid double Release if Release creates an exception
+      }
+    }
+    return value;
+  },
+
+  _AddRef: function(intf){
+    //if (intf) console.log('rtl._AddRef intf="'+(intf?intf.$name:'null')+'"');
+    if (intf) intf._AddRef();
+    return intf;
+  },
+
+  _Release: function(intf){
+    //if (intf) console.log('rtl._Release intf="'+(intf?intf.$name:'null')+'"');
+    if (intf) intf._Release();
+    return intf;
+  },
+
   checkMethodCall: function(obj,type){
     if (rtl.isObject(obj) && rtl.is(obj,type)) return;
     rtl.raiseE("EInvalidCast");
@@ -536,7 +639,7 @@ var rtl = {
     // This function does not range check.
     if (rtl.isFunction(type)){
       for (; srcpos<end; srcpos++) dst[dstpos++] = new type(src[srcpos]); // clone record
-    } else if(isString(type) && (type === 'refSet')) {
+    } else if((typeof(type)==="string") && (type === 'refSet')) {
       for (; srcpos<end; srcpos++) dst[dstpos++] = refSet(src[srcpos]); // ref set
     }  else {
       for (; srcpos<end; srcpos++) dst[dstpos++] = src[srcpos]; // reference