代码之家  ›  专栏  ›  技术社区  ›  Sami

洛可可的位置内存访问无效

  •  1
  • Sami  · 技术社区  · 16 年前

    我一直试图用RoCOCOA(Java到OSX COCOA API库)编写一个简单的屏幕截图应用程序,并设法获取屏幕截图,然后将其保存到一个文件中。不幸的是,应用程序偶尔会因“位置的无效内存访问…”错误而失败。我假设这是由于垃圾收集造成的,因为我无法保持引用的活动状态。导致碰撞的线路是: int[]data=pointer.getIntaray(0,bytesperplane/4);

    我真的没有用目标C来编码任何东西,只是从洛可可学开始,所以我发现自己对这个很困惑。我已经复制了下面的相关代码,非常感谢您的帮助!


    public interface QuartzLibrary extends Library {
    
        QuartzLibrary INSTANCE = (QuartzLibrary) Native.loadLibrary("Quartz", QuartzLibrary.class);
    
        class CGPoint extends Structure {
            public double x;
            public double y;
        }
    
        class CGSize extends Structure {
            public double width;
            public double height;
        }
    
        class CGRect extends Structure implements Structure.ByValue {
            public static class CGRectByValue extends CGRect { }
    
            public CGPoint origin;
            public CGSize size;
        }
    
        int kCGWindowListOptionIncludingWindow = (1 << 3);
        int kCGWindowImageBoundsIgnoreFraming = (1 << 0);
    
        ID CGWindowListCreateImage(CGRect screenBounds, int windowOption, int windowId, int imageOption);
    }
    
    public interface NSBitmapImageRep extends NSObject {
    
        public static final _Class CLASS = Rococoa.createClass("NSBitmapImageRep", _Class.class);
    
        public interface _Class extends NSClass {
            NSBitmapImageRep alloc();
        }
    
        NSBitmapImageRep initWithCGImage(ID imageRef);
        com.sun.jna.Pointer bitmapData();
        NSSize size();
    }
    
    public class Screenshot {
    
        public static void getScreenshot(int windowId) throws IOException {
            QuartzLibrary.CGRect bounds = new QuartzLibrary.CGRect.CGRectByValue();
            bounds.origin = new QuartzLibrary.CGPoint();
            bounds.origin.x = 0;
            bounds.origin.y = 0;
            bounds.size = new QuartzLibrary.CGSize();
            bounds.size.width = 0;
            bounds.size.height = 0;
            ID imageRef = QuartzLibrary.INSTANCE.CGWindowListCreateImage(bounds, QuartzLibrary.kCGWindowListOptionIncludingWindow, windowId, QuartzLibrary.kCGWindowImageBoundsIgnoreFraming);
    
            NSBitmapImageRep imageRep = NSBitmapImageRep.CLASS.alloc();
            imageRep = imageRep.initWithCGImage(imageRef);
            NSSize size = imageRep.size();
            com.sun.jna.Pointer pointer = imageRep.bitmapData();
    
            int width = size.width.intValue();
            int height = size.height.intValue();
    
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
            // The crash always happens when calling 'getIntArray' in the next line.
            int[] data = pointer.getIntArray(0, bytesPerPlane / 4);
            int idx = 0;
            for(int y = 0; y < height; y++)
                for(int x = 0; x < width; x++)
                    image.setRGB(x, y, data[idx++]);
    
            ImageIO.write(image, "png", new File("foo.png"));
        }
    }
    
    2 回复  |  直到 16 年前
        1
  •  2
  •   Sami    16 年前

    发现了问题。

    “imagerep”的最后一个用法是 “com.sun.jna.pointer pointer=imagerep.bitmapdata();”。 此后,IMAGERP是Java垃圾收集器的公平游戏。如果它击中 在我们使用“指针”之前,它指向的备份缓冲区可能会 释放,导致坏事情发生。 要修复它,请为ImageRep添加一组额外的保留/释放,或者 在方法的末尾添加对它的任何引用。

        2
  •  0
  •   Peter Hosey    16 年前

    可能相关,可能不相关:nsBitmapImageRep从nsImageRep下降,而不是直接从nsObject下降。