shannah / Java-Objective-C-Bridge

A thin bridge that allows for two-way communication from Java to Objective-C.
123 stars 25 forks source link

Can't get it to work #3

Closed meydominic closed 8 years ago

meydominic commented 8 years ago

Hey guys, I need to work with some Objective-C classes from Java-8. I'm working with MacOs10.11

If I try the sample (high level api) code, it works fine. This is the code:

// Obtain reference to Singleton instance of Objective-C client
Client c = Client.getInstance();

// Create a new mutable array
Proxy array = c.sendProxy("NSMutableArray", "array");
array.send("addObject:", "Hello");
array.send("addObject:", "World");
array.send("addObject:", "Test String");

assertEquals(3, array.sendInt("count"));

String lastString = array.sendString("lastObject");
assertEquals("Test String", lastString);

But if I try it with other classes, it doesn't work and my application is crashin with this error:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007fff8ba47d32, pid=41313, tid=5891
#
# JRE version: Java(TM) SE Runtime Environment (8.0_66-b17) (build 1.8.0_66-b17)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.66-b17 mixed mode bsd-amd64 compressed oops)
# Problematic frame:
# C  [libsystem_c.dylib+0xd32]  strlen+0x12

I need to work with NSPrintInfo, NSPrintOperation and PDFDocument. That's my code:

Client c = Client.getInstance();
        Proxy nsPrintInfo = c.sendProxy("NSPrintInfo", "printinfo");
        Proxy pdfDocument = c.sendProxy("PDFDocument", "pdfDocument");
        Proxy nsPrintOperation = c.sendProxy("NSPrintOperation", "nsPrintOperation", "pdfDocument");

        nsPrintInfo.send("setTopMargin:", "0.0");
        nsPrintInfo.send("setBottomMargin:", "0.0");
        nsPrintInfo.send("setLeftMargin:", "0.0");
        nsPrintInfo.send("setRightMargin:", "0.0");
        nsPrintInfo.send("setHorizontalPagination:", "NSFitPagination");
        nsPrintInfo.send("setVerticalPagination:", "NSFitPagination");
        nsPrintInfo.send("setPaperSize:", "NSMakeSize(595.275591, 841.88976378)");

        pdfDocument.send("initWithURL:", filename);

        nsPrintOperation.send("setShowsPrintPanel:", "NO");
        nsPrintOperation.send("setShowsProgressPanel:", "NO");

        boolean succeed = nsPrintOperation.sendBoolean("runOperation");

I get the crash with Proxy nsPrintInfo = c.sendProxy("NSPrintInfo", "printinfo");

I hope you can help me.

Thanks :)

shannah commented 8 years ago

I see several problems with this.

When you all Client.sentProxy(String,String), there are a number of variants, but mostly, the first parameter is an Objective-C class name and the second argument is a message name, and subsequent arguments are parameters to the message.

E.g. the call

Proxy nsPrintInfo = c.sendProxy("NSPrintInfo", "printinfo");

Is the equivalent of calling id nsPrintInfo = [NSPrintInfo printinfo] in objective-C. Look at the docs for NSPrintInfo

https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSPrintInfo_Class/

There is no message printinfo.

Perhaps you are looking for sharedPrintInfo. I.e. [NSPrintInfo sharedPrintInfo] ?

Through the objective-c bridge this would be

Proxy nsPrintInfo = c.sendProxy("NSPrintInfo", "sharedPrintInfo");

You make similar errors throughout this code.

What I sometimes do is write the code that I want (or close to it) in objective-c, then translate it into java using the objective-c bridge. That way it is easier to debug the process incrementally.

meydominic commented 8 years ago

Thanks for your comment :+1: That helps me a lot :)

I edited my code a bit and it's working but not completly ^^

Here the code:

        Client c = Client.getInstance();

        Proxy nsPrintInfo = c.sendProxy("NSPrintInfo", "sharedPrintInfo");

        nsPrintInfo.send("setTopMargin:", 0);
        nsPrintInfo.send("setBottomMargin:", 0);
        nsPrintInfo.send("setLeftMargin:", 0);
        nsPrintInfo.send("setRightMargin:", 0);
        nsPrintInfo.send("setHorizontalPagination:", "NSFitPagination");
        nsPrintInfo.send("setVerticalPagination:", "NSFitPagination");
        nsPrintInfo.send("setPaperSize:", "NSMakeSize(595.275591, 841.88976378)");

        Proxy nsUrl = c.sendProxy("NSURL", "fileURLWithPath:", filename);

        Proxy pdfDocument = c.sendProxy("PDFDocument", "initWithURL:", nsUrl);
        Proxy nsPrintOperation = c.sendProxy("NSPrintOperation", "nsPrintOperation", pdfDocument); // this line is still wrong

        nsPrintOperation.send("setShowsPrintPanel:", false);
        nsPrintOperation.send("setShowsProgressPanel:", false);

        boolean succeed = nsPrintOperation.sendBoolean("runOperation");

I know, that some nsPrintInfo calls are not right, but that's not the problem for now.

My question is, how can I pass a created Object/Proxy as argument to another call/function like Proxy pdfDocument = c.sendProxy("PDFDocument", "initWithURL:", nsUrl);

The obj-c code for creating a pdfdocument is: PDFDocument *pdfDocument = [[[PDFDocument alloc] initWithURL:fileURL] autorelease]; Ho do I get [PDFDocument alloc] initWithUrl to work?

Proxy pdfalloc = c.sendProxy("PDFDocument", "alloc"); does not work for me :/

PDFDocument is placed in sub-framework PDFKit in #import <Quartz/Quartz.h> Do I have to do something special first?

And another question. I found a line of code on stackoverflow: NSPrintOperation *op = [myPDFDoc getPrintOperationForPrintInfo:info autoRotate:YES];

How can I get this to work? Something like: Proxy nsPrintOperation = c.sendProxy([Pointer to my pdfdocument], "getPrintOperationForPrintInfo:autoRotate:", [Pointer to my printinfo], true);

I hope you can help me again, thanks :)

shannah commented 8 years ago

My question is, how can I pass a created Object/Proxy as argument to another call/function like Proxy pdfDocument = c.sendProxy("PDFDocument", "initWithURL:", nsUrl);

Proxy pdfalloc = c.sendProxy("PDFDocument", "alloc");
pdfalloc.setProxy("initWithURL:", nsUrl);
pdfalloc.setProxy("autorelease");

The Client.chain() method may allow you to do this all in one shot, but I'm out of practice and don't remember the exact semantics off the top of my head.

NSPrintOperation *op = [myPDFDoc getPrintOperationForPrintInfo:info autoRotate:YES];

becomes

Proxy op = pdfalloc.sentProxy("getPrintOperationForPrintInfo:autoRotate:", info, true);

PDFDocument is placed in sub-framework PDFKit in #import <Quartz/Quartz.h> Do I have to do something special first?

I think that is imported by default. But if you need to import a library, you can do that using the Native.loadLibrary method. See the example with webkit here: https://github.com/shannah/Java-Objective-C-Bridge/blob/master/java/test/ca/weblite/objc/TestWebView.java#L20-L22

shannah commented 8 years ago

One other tip. Constants like NSFitPagination can't be passed as the string constant name. You'll need to find their values and pass them that way. E.g.

https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSPrintInfo_Class/#//apple_ref/c/tdef/NSPrintingPaginationMode

enum {
   NSAutoPagination = 0,
   NSFitPagination  = 1,
   NSClipPagination = 2
};

So Instead of

nsPrintInfo.send("setHorizontalPagination:", "NSFitPagination");

you would do

nsPrintInfo.send("setHorizontalPagination:", 1);
meydominic commented 8 years ago

At first, thanks for answering :) I looked into your webkit example and adapted it to my needs for PDFKit, but I didn't get it to work. In my obj-c testproject I need to include "Quartz" Framework to get PDFDocument. But even with or without Native.Loadlibrary for Quartz, I can't get PDFDocument to work.

Everytime on Proxy pdfalloc = c.sendProxy("PDFDocument", "alloc"); the application crashes with nearly same error message as in my first comment.

And I don't know how I can load a library/framework inside another one. Native.loadLibrary("Quartz") works, but I don't get PDFDocument. But quartz.h includes PDFKit Native.loadLibrary("PDFKit") doesn't work, because it can't find PDFKit. PDFKit.Framework is inside Quartz.Framework/Frameworks/.

Any idea? Thanks :)

shannah commented 8 years ago

Native.loadLibrary("Quartz") gets PDFDocument for me.

What happens when you do something like:

Native.loadLibrary("Quartz", PDFKit.class); Proxy pdfalloc = c.sendProxy("PDFDocument", "alloc");

(Where PDFKit is just a dummy interface you created with no methods).

On Sun, Nov 15, 2015 at 3:41 AM, Dominic Eubel notifications@github.com wrote:

At first, thanks for answering :) I looked into your webkit example and adapted it to my needs for PDFKit, but I didn't get it to work. In my obj-c testproject I need to include "Quartz" Framework to get PDFDocument. But even with or without Native.Loadlibrary for Quartz, I can't get PDFDocument to work.

Everytime on Proxy pdfalloc = c.sendProxy("PDFDocument", "alloc"); the application crashes with nearly same error message as in my first comment.

And I don't know how I can load a library/framework inside another one. Native.loadLibrary("Quartz") works, but I don't get PDFDocument. But quartz.h includes PDFKit Native.loadLibrary("PDFKit") doesn't work, because it can't find PDFKit. PDFKit.Framework is inside Quartz.Framework/Frameworks/.

Any idea? Thanks :)

— Reply to this email directly or view it on GitHub https://github.com/shannah/Java-Objective-C-Bridge/issues/3#issuecomment-156806443 .

Steve Hannah Web Lite Solutions Corp.

meydominic commented 8 years ago

Native.loadLibrary("Quartz") gets PDFDocument for me.

This means:

Native.loadLibrary("Quartz");
Proxy pdfdocument = c.sendProxy("PDFDocument", "alloc");

should be enough to get PDFDocument? I need to test again at work on monday.

What happens when you do something like:

Native.loadLibrary("Quartz", PDFKit.class); Proxy pdfalloc = c.sendProxy("PDFDocument", "alloc");

(Where PDFKit is just a dummy interface you created with no methods).

Do you mean like in WebKit example? :

    public static interface WebKit extends Library {
        public final static TestWebView.WebKit INSTANCE = (TestWebView.WebKit)Native.loadLibrary("WebKit", TestWebView.WebKit.class);
    }

Could look like adapted:

    public static interface Quartz extends Library {
        public final static TestClass.Quartz INSTANCE = (TestClass.Quartz)Native.loadLibrary("Quartz", TestClass.Quartz.class);
    }

and then Native.loadLibrary("Quartz", TestClass.Quartz.class); ?

shannah commented 8 years ago

On Sun, Nov 15, 2015 at 8:18 AM, Dominic Eubel notifications@github.com wrote:

Native.loadLibrary("Quartz") gets PDFDocument for me.

This means:

Native.loadLibrary("Quartz");Proxy pdfdocument = c.sendProxy("PDFDocument", "alloc");

Yes. Except loadLibrary takes a second parameter. Pass it a dummy interface. E.g. Native.loadLibrary("Quartz", MyInterface.class);

Steve

should be enough to get PDFDocument? I need to test again at work on monday.

— Reply to this email directly or view it on GitHub https://github.com/shannah/Java-Objective-C-Bridge/issues/3#issuecomment-156825451 .

Steve Hannah Web Lite Solutions Corp.

meydominic commented 8 years ago

I updated my last comment :) Thanks :+1:

Maybe you can post here a/your minimal code, with class, dummy interface and loadlibrary and pdfdocument alloc. So I only need to import it in my IDE and run it for testing.

shannah commented 8 years ago

Here is a gist. https://gist.github.com/shannah/2640dc55aadb988a51c0

I just used the WebView test and added some calls to instantiate a PDFDocument. It doesn't actually do anything with it, but it compiles and runs fine, which means that PDFDocument was loaded ok.

On Sun, Nov 15, 2015 at 8:25 AM, Dominic Eubel notifications@github.com wrote:

I updated my last comment :) Thanks [image: :+1:]

— Reply to this email directly or view it on GitHub https://github.com/shannah/Java-Objective-C-Bridge/issues/3#issuecomment-156825986 .

Steve Hannah Web Lite Solutions Corp.

meydominic commented 8 years ago

Thank you so much :) Will test it tomorrow :+1:

meydominic commented 8 years ago

So, I have tested it, but it doesn't really work. It can create a PDFDocument object but it crashes directly after creating proxy:

Proxy pdfAlloc = c.sendProxy("PDFDocument", "alloc");

I get :

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007fff9291f93e, pid=46611, tid=5891
#
# JRE version: Java(TM) SE Runtime Environment (8.0_66-b17) (build 1.8.0_66-b17)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.66-b17 mixed mode bsd-amd64 compressed oops)
# Problematic frame:
# C  [PDFKit+0x893e]  -[PDFDocument pageCount]+0x16
shannah commented 8 years ago

That crash doesn't look like it happens there. Do you do anything with the pfdalloc object after creating it? On Nov 15, 2015 10:46 PM, "Dominic Eubel" notifications@github.com wrote:

So, I have tested it, but it doesn't really work. It can create a PDFDocument object but it crashes directly after creating proxy:

Proxy pdfAlloc = c.sendProxy("PDFDocument", "alloc");

I get :

#

A fatal error has been detected by the Java Runtime Environment:

#

SIGSEGV (0xb) at pc=0x00007fff9291f93e, pid=46611, tid=5891

#

JRE version: Java(TM) SE Runtime Environment (8.0_66-b17) (build 1.8.0_66-b17)

Java VM: Java HotSpot(TM) 64-Bit Server VM (25.66-b17 mixed mode bsd-amd64 compressed oops)

Problematic frame:

C [PDFKit+0x893e] -[PDFDocument pageCount]+0x16

— Reply to this email directly or view it on GitHub https://github.com/shannah/Java-Objective-C-Bridge/issues/3#issuecomment-156937889 .

meydominic commented 8 years ago

It's not possible for me to work with it because it crashes directly after/with Proxy pdfAlloc = c.sendProxy("PDFDocument", "alloc");

shannah commented 8 years ago

Please post test case. I can't reproduce. Works fine for me. On Nov 16, 2015 6:22 AM, "Dominic Eubel" notifications@github.com wrote:

It's not possible for me to work with it because it crashes directly after/with Proxy pdfAlloc = c.sendProxy("PDFDocument", "alloc");

— Reply to this email directly or view it on GitHub https://github.com/shannah/Java-Objective-C-Bridge/issues/3#issuecomment-157045339 .

meydominic commented 8 years ago

Mhhh, thats curious :/ I can post the test case tomorrow when I'm at work. But I believe, that I only imported your gist in my IDE (IntelliJ) and ran it. My Environment: MacOsX 10.11 with JDK 1.8.0_66

meydominic commented 8 years ago

I did a test again.

I used your gist and found out:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007fff9291f93e, pid=50122, tid=2571
#
# JRE version: Java(TM) SE Runtime Environment (8.0_66-b17) (build 1.8.0_66-b17)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.66-b17 mixed mode bsd-amd64 compressed oops)
# Problematic frame:
# C  [PDFKit+0x893e]  -[PDFDocument pageCount]+0x16

but if I put the breakpoint in another method (like someFuncWithMultipleArgs) then it runs fine and no crash.

Can you reproduce this case?