Недопустимый доступ к памяти местоположения с помощью Rococoa

StackOverflow https://stackoverflow.com/questions/1655145

  •  11-09-2019
  •  | 
  •  

Вопрос

Я пытался закодировать простое приложение для создания скриншотов, используя rococoa (java to osx cocoa api library), и мне удалось дойти до того, что фактически сделать снимок экрана, а затем сохранить его в файл.К сожалению, время от времени приложение завершается сбоем с ошибкой "Недопустимый доступ к памяти местоположения ...".Я предполагаю, что это связано с тем, что что-то собирается из мусора, потому что мне не удается сохранить ссылку живой.Строка, которая вызывает сбой, является:int[] данные = указатель.getIntArray(0, bytesPerPlane / 4);

Я действительно ничего не кодировал с Objective C и только начинаю с rococoa, так что я просто запутался в этом.Я скопировал соответствующий код ниже и был бы очень признателен за любую помощь в этом!


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"));
    }
}
Это было полезно?

Решение

Нашел проблему.

Последнее использование 'imageRep' находится в строке "com.sun.jna.Pointer указатель = imageRep.BitmapData();".После этого imageRep становится честной игрой для сборщика мусора Java.И если он попадет в до того, как мы закончим использовать 'pointer', резервный буфер, на который он указывает, может / будет освобожден , что приведет к возникновению плохих вещей.Чтобы исправить это, добавление дополнительного набора retain / release для imageRep выполняет свою работу, или альтернативно добавление любой ссылки на него в конец метода.

Другие советы

Возможно, связаны, возможно, нет:NSBitmapImageRep происходит от NSImageRep, а не непосредственно от NSObject.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top