Return an Object into a Cell from C++ Addin

Java, C++, C#, Delphi... - Using the UNO bridges
Post Reply
saleem145
Posts: 130
Joined: Mon Jul 02, 2012 4:47 pm

Return an Object into a Cell from C++ Addin

Post by saleem145 »

Hello,

Lets says I have a class Rectangle whose constructor takes in length and width.

In OpenOffice Cell A1 I want to be able to type in

=Rectangle(10,20)

This should invoke the constructor and return a pointer to an object of type Rectangle.

In Cell A2 I want to able to type in

Area(A1)

This should call the area method of rectangle....

Is this possible??

Saleem
OpenOffice 3.4.0
Mac OS X 10.5.8
User avatar
Charlie Young
Volunteer
Posts: 1559
Joined: Fri May 14, 2010 1:07 am

Re: Return an Object into a Cell from C++ Addin??

Post by Charlie Young »

saleem145 wrote:Is this possible??

Saleem
I doubt it. What address space is A1 supposed to be pointing into? If the pointer is into some memory allocated by the function in A1, that memory will be freed when the function exits. It would seem you could return some long integer which pointed to one of your rectangles while the function was executing, but what might be at that address later is anybody's guess, I would think.
Apache OpenOffice 4.1.1
Windows XP
User avatar
Charlie Young
Volunteer
Posts: 1559
Joined: Fri May 14, 2010 1:07 am

Re: Return an Object into a Cell from C++ Addin??

Post by Charlie Young »

Charlie Young wrote:
saleem145 wrote:Is this possible??

Saleem
I doubt it. What address space is A1 supposed to be pointing into? If the pointer is into some memory allocated by the function in A1, that memory will be freed when the function exits. It would seem you could return some long integer which pointed to one of your rectangles while the function was executing, but what might be at that address later is anybody's guess, I would think.
Life is full of surprises. Just for kicks, I tried this. I used function names RectPtr and RectArea since Rectangle and Area seemed too generic, but here are the details:

In the idl (with a bunch of other stuff in this case, since I just added these functions to an old project):

Code: Select all

    long RectPtr([in] double x,[in] double y);
    double RectArea([in] long RectPtr);
A rectangle class (mostly from cplusplus.com)

Code: Select all

class CRectangle {
    double width, height;
  public:
    CRectangle (double,double);
    double area ();
};

CRectangle::CRectangle (double a, double b) {
  width = a;
  height = b;
}

double CRectangle::area()
{
	return (width*height);
}

And the add-in functions

Code: Select all

long SAL_CALL OldProjectImpl::RectPtr( double x, double y)
		throw (RuntimeException)
{
	CRectangle *rect;
	rect = new CRectangle(x,y);
	return (long) rect;
}

double SAL_CALL OldProjectImpl::RectArea( long RectPtr)
		throw (RuntimeException)
{
	CRectangle *rect;
	rect = (CRectangle *) RectPtr;
	return rect->area();
}

And it works!

If I put in A1

Code: Select all

=RECTPTR(10;20)
I get a long, like 247094384

and so in A2 I put

Code: Select all

=RECTAREA(A1)
I get the answer 200, and if I I edit the parameters in A1, the changes are reflected in A2.

I'll be amazed if this generalizes very well, and I wouldn't be surprised If it fails ignominiously at some point, but it does look like something worth playing around with, at least.
Apache OpenOffice 4.1.1
Windows XP
saleem145
Posts: 130
Joined: Mon Jul 02, 2012 4:47 pm

Re: Return an Object into a Cell from C++ Addin

Post by saleem145 »

Two comments --

1. Is it possible to return the pointer tugged away somewhere in the Any Data Structure. I would the cell to display "*" in the cell indicating that is a pointer. But we can hide the pointer value in the datastructure and access it when we want.

2. It would be cool if there were just a way to export the functions into a pluggin without having to write the wrappers, xcus etc...

Saleem
OpenOffice 3.4.0
Mac OS X 10.5.8
saleem145
Posts: 130
Joined: Mon Jul 02, 2012 4:47 pm

Re: Return an Object into a Cell from C++ Addin

Post by saleem145 »

One more question -- how would this work on a 64 bit machine -- I set the return type to hyper in the idl file and used sal_Int64 in the .cc. But the cell displays a #VALUE error. I think returning any 64 bit integer forces it to display #VALUE....

Saleem
OpenOffice 3.4.0
Mac OS X 10.5.8
User avatar
Charlie Young
Volunteer
Posts: 1559
Joined: Fri May 14, 2010 1:07 am

Re: Return an Object into a Cell from C++ Addin

Post by Charlie Young »

saleem145 wrote:One more question -- how would this work on a 64 bit machine -- I set the return type to hyper in the idl file and used sal_Int64 in the .cc. But the cell displays a #VALUE error. I think returning any 64 bit integer forces it to display #VALUE....

Saleem
HYPER is not an allowed return type for an add-in function. The numeric value in the cell is in fact a double, your precision there is limited to 15 places, and I think you need 20 or so for 64 bits. A wild idea is to store the number as a string (maybe hex?), and have the function convert it to a number before using it to access memory.

The pointer to the data structure is the cell value, so how are you going to access it if it's in the data structure?
Apache OpenOffice 4.1.1
Windows XP
saleem145
Posts: 130
Joined: Mon Jul 02, 2012 4:47 pm

Re: Return an Object into a Cell from C++ Addin

Post by saleem145 »

How do we ensure the destructor is called if new objects are created. Instead of feeding in a fixed width and depth, try feeding in rand() so every calculate creates a new object....

Saleem
OpenOffice 3.4.0
Mac OS X 10.5.8
User avatar
Charlie Young
Volunteer
Posts: 1559
Joined: Fri May 14, 2010 1:07 am

Re: Return an Object into a Cell from C++ Addin

Post by Charlie Young »

saleem145 wrote:How do we ensure the destructor is called if new objects are created. Instead of feeding in a fixed width and depth, try feeding in rand() so every calculate creates a new object....

Saleem
I tried that, I made about 10,000 rectangles with random dimensions, and never had a problem. Of course, our example so far is not much more than a roundabout way of multiplying two numbers, but you likely have something more ambitious in mind.

I've been playing with the 64 bit problem, using my "wild idea" incorporating hex strings. We just need some handy-dandy utility functions

Code: Select all

OUString Dec2OUHex(sal_uInt64 dec)
{
	static sal_Unicode hexdigits[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
	OUString hexStr = OUString();
	sal_uInt64 Quotient;
	int Remainder;

	if(dec > 0) {
		Quotient = dec;
		while(Quotient > 0)
		{
			Remainder = Quotient % 16;
			hexStr += OUString(hexdigits[Remainder]);
			Quotient /= 16;
		}
	} else {
		hexStr = OUString(hexdigits[0]);
	}
	return oureverse(hexStr);
}

OUString oureverse(OUString s)
{
	OUString r;
	r = OUString();
	long i;

	for(i = s.getLength() - 1;i >= 0; i--)
	{
		r += OUString(s[i]);
	}
	return r;
}

sal_uInt64 Hex2Dec64(OUString hexStr)
{
	OUString r = oureverse(hexStr);
	sal_uInt64 p,val = 0;
	long i,j;
	int d;
	for(i = 0;i < r.getLength();i++)
	{
		if(r[i] >= '0' && r[i] <= '9')
			d = r[i] - '0';
		else 
			d = r[i] - 'A' + 10;
		p = 1;
		for(j = 0;j < i;j++)
			p *= 16;

		val += d * p;
	}
	return val;
}
Then RectPtr and RectArea become

Code: Select all

OUString SAL_CALL ClassAddinsImpl::RectPtr( double width, double height)
		throw (RuntimeException)
{

	CRectangle *rect;
	rect = new CRectangle(width,height);
	return Dec2OUHex((sal_uInt64) rect);
}

double SAL_CALL ClassAddinsImpl::RectArea( const OUString & RectPtr)
		throw (RuntimeException)
{
	CRectangle *rect;
	sal_uInt64 ptr = Hex2Dec64(RectPtr);
	rect = (CRectangle *) ptr;
	return rect->area();
}

and it works (so far), but one thing to add is that since RectArea fetches the memory for whatever its argument points to, one should be careful with it.

Something like

Code: Select all

=RECTAREA(100)
Will very likely crash, as I've discovered.

Maybe something could (should) be done with try/catch.

A cell may be formatted to show * in place of a string, suppressing numbers altogether, with

Code: Select all

;;;"*"
Apache OpenOffice 4.1.1
Windows XP
saleem145
Posts: 130
Joined: Mon Jul 02, 2012 4:47 pm

Re: Return an Object into a Cell from C++ Addin

Post by saleem145 »

Thanks. I am working on the hex idea as well.

Saleem

BTW: it would be great if they extended the Any class to support user defined datatypes as well. And then the destructor would work as well.
OpenOffice 3.4.0
Mac OS X 10.5.8
User avatar
Charlie Young
Volunteer
Posts: 1559
Joined: Fri May 14, 2010 1:07 am

Re: Return an Object into a Cell from C++ Addin

Post by Charlie Young »

I always hate it when I post code and then realize I did something clunky.

Since we're using powers of 2, let's do bit shifting instead of multiplication and division.

Code: Select all

OUString Dec2OUHex(sal_uInt64 dec)
{
	static sal_Unicode hexdigits[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
	OUString hexStr = OUString();
	
	if(dec > 0) {
		while(dec > 0)
		{
			hexStr += OUString(hexdigits[dec % 16]);
			dec >>= 4;
		}
	} else {
		hexStr = OUString(hexdigits[0]);
	}
	return oureverse(hexStr);
}

OUString oureverse(OUString s)
{
	OUString r;
	r = OUString();
	long i;

	for(i = s.getLength() - 1;i >= 0; i--)
	{
		r += OUString(s[i]);
	}
	return r;
}

sal_uInt64 Hex2Dec64(OUString hexStr)
{
	OUString r = oureverse(hexStr);
	sal_uInt64 p,val = 0;
	long i;
	int d;
	for(i = 0;i < r.getLength();i++)
	{
		if(r[i] >= '0' && r[i] <= '9')
			d = r[i] - '0';
		else 
			d = r[i] - 'A' + 10;
		p = 1;
		p <<= 4*i;
		
		val += d * p;
	}
	return val;
}

int isOUxdigit(sal_Unicode c)
{
	static sal_Unicode hexdigits[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
	int d = 0, itsnot = 1;
	
	while(itsnot && d < 16)
	{
		itsnot = c != hexdigits[d++];
	}

	return !itsnot;
}

I use isOUxdigit in RectArea, where I also use a catch(...). It seems with vc++ that is about the only way to deal with all the things that might go wrong here, and even at that it requires a special compiler switch (/EHa).

Code: Select all

double SAL_CALL ClassAddinsImpl::RectArea( const OUString & RectPtr)
		throw (RuntimeException)
{
	long i = 0;
	while(i < RectPtr.getLength())
		if(!isOUxdigit(RectPtr[i++]))
			return -1;
	try {
		CRectangle *rect;
		sal_uInt64 ptr = Hex2Dec64(RectPtr);
		rect = (CRectangle *) ptr;
		return rect->area();
	} catch(...) {
		return -1;
	}
}
That assumes one doesn't want a rectangle with an area of -1.

It catches

Code: Select all

=RECTAREA("100")
and also

Code: Select all

=RECTAREA("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
RectPtr just checks for bad_alloc, which hasn't happened to me yet.

Code: Select all

OUString SAL_CALL ClassAddinsImpl::RectPtr( double width, double height)
		throw (RuntimeException)
{

	CRectangle *rect;
	try {
		rect = new CRectangle(width,height);
		return Dec2OUHex((sal_uInt64) rect);
	} catch (bad_alloc&) {
		return OUString(RTL_CONSTASCII_USTRINGPARAM("Can't allocate rectangle"));
	}
}

Edit:

Hmm, clunky code? Why isn't isOUxdigit just

Code: Select all

int isOUxdigit(sal_Unicode c)
{
	return (c >= '0' && c <= '9') || (c >='A' && c <= 'F');
}
?????????????

Actually, it's because I quickly adapted it from another program, but that one could use some improvement as well.
Apache OpenOffice 4.1.1
Windows XP
Post Reply