I need some help related to xpidl tool available in
mozilla source tree used for making plugin.
When I run "xpidl -m typelib" on the following idl. I
am getting an error
"Error: can't handle that type of ident in param list"
for the last line.
/***********************************/
/* test.idl**/
/**********************************/
#include "nsISupports.idl"
struct Can1 {
short num;
string name;
};
//typedef Can1 Can2;
[scriptable, uuid(xxx-xxx-xxx-xxx-xxxx)]
interface nsIObjPlugin : nsISupports {
readonly attribute string version;
readonly attribute string hello;
Can1 E_GetCan1();
void E_GetTest(in unsigned long
count,[array,size_is(count)] out Can1 Can1Arr);
};
********************************************
Please suggest how to make idl interface for a c++
function that returns an array of objects.
Regards,
Hari
__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com
xpidl doesn't support 'struct' (though the corba idl parser that the
xpidl compiler is built upon does parse them). You need to use
interfaces inheriting from nsISupports to describe objects.
Also, the 'count' param in your E_GetTest method should be 'out' not
'in'. There are schemes you can do with inout params. But, the normal
case is to have the caller give addresses where the array and count
will end up, and the callee will allocate the array, populate it with
ref counted objects, and fill in the array address and count address
for the caller. The caller then has to release all the objects and
deallocate the array when done.
There are examples of this sort of stuff in the mozilla codebase.
Using lxr.mozilla.org and searching for 'size_is' will probably find a
bunch of interfaces that manipulate arrays.
There are various xpidl docs on mozilla.org that ought to say more
about what is and isn't supported. I'm sure none of them suggested
'struct' :)
John.
------------------------------------------------------
Hi,
Thanks. You are right. I think I was referring a wrong
document which gave the struct idea.
Now I have made one more idl file defining a new
interface of type "can1" and implemented all required
members including the ones from nsIClassInfo and
SecurityCh..component. This works when I try to return
an object. But when I try to return an array of
objects to javascript, the browser crashes.
I am using the template from simple plugin for doing
this interface (modules/ plugin/ tools/ sdk/ samples/
simple/).
The following debug given by gdb makes me think that I
have to do some change to nsQueryInterface function.
********************************
Program ./obj-i686-pc-linux-gnu/dist/bin/firefox-bin
(pid = 28672) received signal 11.
Stack:
UNKNOWN [./obj-i686-pc-linux-gnu/dist/bin/firefox-bin
+0x0001B5A3]
UNKNOWN [/lib/tls/libpthread.so.0 +0x0000B888]
nsCOMPtr_base::assign_from_qi(nsQueryInterface, nsID
const&)+0x00000028
[./obj-i686-pc-linux-gnu/dist/bin/libxpcom_core.so
+0x0002842E]
***********************************
***********************************
the func defined for testing this looks like
NS_IMETHODIMP nsScriptablePeer:: E_GetTest(PRUint32
*count, Can1 ***Can1Arr)
*************************************
************************************
Some debug prints using gdb
(gdb) print Can1Arr
$19 = (class Can1 ***) 0xbfe9a780
(gdb) print *Can1Arr
$20 = (class Can1 **) 0xbfe9a570
(gdb) print **Can1Arr
$21 = (class Can1 *) 0xb686a844
(gdb) print ***Can1Arr
$22 = {<nsISupports> = {_vptr.nsISupports =
0x6d9aef8},
(gdb) print mCan1
$16 = (class Can1 **&) @0xbfe9a780: 0xbfe9a570
(gdb) print *mCan1
$17 = (class Can1 *) 0xb686a844
*************************************
*************************************
I think the mail has become too long. sorry for that.
Please suggest some way out. My browser keeps
crashing....:(
:)
Thanks and Regards,
Hari
x-------x-------------x--------x-----------x
************************************************
************************************************
NS_IMETHODIMP nCan1::QueryInterface(const nsIID& aIID,
void** aInstancePtr)
{
if(!aInstancePtr)
return NS_ERROR_NULL_POINTER;
if(aIID.Equals(kICan1IID)) {
*aInstancePtr = NS_STATIC_CAST(Can1*, this);
AddRef();
return NS_OK;
}
if(aIID.Equals(kIClassInfoIID)) {
*aInstancePtr = NS_STATIC_CAST(nsIClassInfo*,
this);
AddRef();
return NS_OK;
}
if(aIID.Equals(kISupportsIID)) {
*aInstancePtr =
NS_STATIC_CAST(nsISupports*,(NS_STATIC_CAST(Can1*,
this)));
AddRef();
return NS_OK;
}
return NS_NOINTERFACE;
}
**************************************
**************************************
That would suggest there is perhaps something wrong with the code that
returns the array of objects, no? You might post that code if you can't
find the problem yourself.
John.
Hi,
My test code lines are pasted here.
Following is the function that returns array
*************************************************************
NS_IMETHODIMP nsScriptablePeer:: E_GetTest(PRUint32 *count, Can1
***Can1Arr)
{
Can1** &mCan1=*Can1Arr;
*count=2;
Can1 *ACan1;
ACan1= new nCan1[2];
*mCan1=ACan1;
/*
// Can1 * three;
// three=new nCan1[2];
// *Can1Arr=&three;
// *count=2;
*/
return NS_OK;
}
***************************************************************
Class
****************************************************************
/*nsClassInfoMixing has class info has security check implemented*/
class nCan1 : public nsClassInfoMixing, public Can1
{
public:
//NS_DECL_ISUPPORTS
NS_DECL_CAN1
nCan1();/*empty - does nothing*/
~nCan1();/*empty - does nothing*/
public:
// methods from nsISupports
NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
NS_IMETHOD_(nsrefcnt) AddRef();
NS_IMETHOD_(nsrefcnt) Release();
protected:
nsrefcnt mRefCnt;
public:
// native methods callable from JavaScript
// void SetInstance(nsPluginInstance* plugin);
protected:
//nsPluginInstance* mPlugin;
};
*********************************************************************
Regards,
Hari
I see a few problem...
> nCan1();/*empty - does nothing*/
Is your constructor implementation really empty? At minimum you'd want
to be initializing mRefCnt. BTW, the mozilla internal code is using
nsAutoRefCnt to avoid manual initilization these days. But, I'm not sure
about the status for using that in plugins and extensions.
> Can1** &mCan1=*Can1Arr;
> *count=2;
> Can1 *ACan1;
> ACan1= new nCan1[2];
> *mCan1=ACan1;
This is all wrong.
The use of a C++ reference does not help the clarity :)
What you need to be returning is an array of *pointers* to objects - not
an array of objects. The caller has no way of knowing the size of the
implementation objects. So, it would not be able to walk an array of
object instances. What the caller *does* know is the size of a pointer.
So, arrays of pointers are used.
And, the array of pointers needs to be allocated with the xpcom shared
allocator. It is perfectly legal for different extensions to statically
link to their own C runtime library modules or a different dynamic
runtime than the one used by the core xpcom module. These different
runtimes can have completely different heaps. Since you are allocating
an array (of pointers) that will later be free'd by some other code, it
is necessary for both ends to use the same heap. This is ensured by
having a global 'shared' allocator. The interface to that is nsIMemory.
And the singleton implementation of that interface is in the core XPCOM
code.
you should look at:
http://developer.mozilla.org/en/docs/XPCOM_API_Reference
NS_GetMemoryManager is the global method to get the allocator:
http://developer.mozilla.org/en/docs/NS_GetMemoryManager
There are notes there suggesting alternative methods for doing this. I
have no idea what is the recommended current practice.
The objects whose pointers you put into that array need to have had
AddRef called on them before you pass the array to the caller. The
caller must call Release when it is done with each object and then use
the shared allocator to free the array of pointers. In your case where
you are calling your object implemented in C++ from Javascript it is the
XPConnect module that is doing the calls to the Release and free as
appropriate.
As I suggested before, I think you ought to use lxr.mozilla.org to look
for an interface that returns an array of object pointers and then go
look at an implementation of that interface to help you understand this.
To see such interfaces:
http://lxr.mozilla.org/seamonkey/search?string=size_is
I picked one that uses a method called 'getQueries' to look at:
http://lxr.mozilla.org/seamonkey/source/toolkit/components/places/public/nsINavHistoryService.idl#377
http://lxr.mozilla.org/seamonkey/search?string=getQueries
http://lxr.mozilla.org/seamonkey/source/toolkit/components/places/src/nsNavHistoryResult.cpp#1758
This is not an ideal example since it is not creating *new* objects.
But, rather, it is exposing existing objects. And, it is using the
mozilla-internal static nsMemory object rather than getting the shared
allocator in the same way that an extension would do. Still, it shows
the basic pattern of creating and populating an array of pointers to
objects. You could look for other examples.
Hopefully, this will get you on the road toward doing this correctly.
But, really, I think you should be asking yourself if handing around an
array of pointers to these objects is really your best option. If you
don't really need a stateful snapshot of *all* your data items then you
might just do something like:
int getItemCount()
short getItemNum(in int itemIndex)
string getItemName(in int itemIndex)
If you *do* need to make a snapshot, then you still might be better off
implementing nsISimpleEnumerator to get the items one at a time as
needed rather than forcing the creation and passing around of a flat
array of indeterminate size.
Hope this helps,
John.
Odds are you really want to be using the npruntime extensions to NPAPI
rather than XPCOM. As I understand it, the ScriptablePeer stuff is more
or less deprecated at this point. See
<http://www.mozilla.org/projects/plugins/npruntime.html>
Perhaps you have your reasons for pursuing the XPCOM approach; but in
case you are just unaware of the npruntime stuff, I thought I'd mention
it.
--
Braden McDaniel e-mail: <bra...@endoframe.com>
<http://endoframe.com> Jabber: <bra...@jabber.org>
> Is your constructor implementation really empty? At minimum you'd want
> to be initializing mRefCnt. BTW, the mozilla internal code is using
> nsAutoRefCnt to avoid manual initilization these days. But, I'm not sure
> about the status for using that in plugins and extensions.
-----------------------
Thanks Now I added this
-----------------------
> This is all wrong.
>
> The use of a C++ reference does not help the clarity :)
>
> What you need to be returning is an array of *pointers* to objects - not
> an array of objects. The caller has no way of knowing the size of the
> implementation objects. So, it would not be able to walk an array of
> object instances. What the caller *does* know is the size of a pointer.
> So, arrays of pointers are used.
-----------------------
Does the following make sense. (....poor coding----:(
Can1* one, * two, *arra[2];
Can1Arr[0]=(Can1**)NPN_MemAlloc(sizeof(nCan1**)+1);
one =(Can1*)NPN_MemAlloc(sizeof(nCan1*)+1);
*Can1Arr[0]=one;
----------------------------
>
> And, the array of pointers needs to be allocated with the xpcom shared
> allocator. It is perfectly legal for different extensions to statically
> link to their own C runtime library modules or a different dynamic
> runtime than the one used by the core xpcom module. These different
> runtimes can have completely different heaps. Since you are allocating
> an array (of pointers) that will later be free'd by some other code, it
> is necessary for both ends to use the same heap. This is ensured by
> having a global 'shared' allocator. The interface to that is nsIMemory.
> And the singleton implementation of that interface is in the core XPCOM
> code.
>
> you should look at:
> http://developer.mozilla.org/en/docs/XPCOM_API_Reference
>
> NS_GetMemoryManager is the global method to get the allocator:
> http://developer.mozilla.org/en/docs/NS_GetMemoryManager
>
---------------------------------------------
I shall do the above mentioned using memory manager also and try. I
tried this for returning a string and that works. Great .. so many new
things in browser world.
-----------------------------------------------
> To see such interfaces:
> http://lxr.mozilla.org/seamonkey/search?string=size_is
>
> I picked one that uses a method called 'getQueries' to look at:
> http://lxr.mozilla.org/seamonkey/source/toolkit/components/places/public/nsINavHistoryService.idl#377
>
> http://lxr.mozilla.org/seamonkey/search?string=getQueries
>
> http://lxr.mozilla.org/seamonkey/source/toolkit/components/places/src/nsNavHistoryResult.cpp#1758
-------------------------------------------------
I have edited my idl file as per the above example.
--------------------------------------------------
>
> This is not an ideal example since it is not creating *new* objects.
> But, rather, it is exposing existing objects. And, it is using the
> mozilla-internal static nsMemory object rather than getting the shared
> allocator in the same way that an extension would do. Still, it shows
> the basic pattern of creating and populating an array of pointers to
> objects. You could look for other examples.
>
> Hopefully, this will get you on the road toward doing this correctly.
>
> But, really, I think you should be asking yourself if handing around an
> array of pointers to these objects is really your best option. If you
> don't really need a stateful snapshot of *all* your data items then you
> might just do something like:
>
> int getItemCount()
> short getItemNum(in int itemIndex)
> string getItemName(in int itemIndex)
>
> If you *do* need to make a snapshot, then you still might be better off
> implementing nsISimpleEnumerator to get the items one at a time as
> needed rather than forcing the creation and passing around of a flat
> array of indeterminate size.
>
---------------------------------------------
I am still trying all the options given above -----going on ---- work
under progress
Thanks,
Hari
---------------------------------------------
> Hope this helps,
>
> John.