accès mémoire non valide de l'emplacement avec Rococoa
Question
J'ai essayé de coder une application simple capture d'écran à l'aide Rococoa (java à osx bibliothèque api de cacao), et a réussi à aller aussi loin que de prendre réellement la capture d'écran, et l'enregistrement puis dans un fichier. Malheureusement, une fois dans un certain temps, l'application échoue avec un « accès mémoire non valide de l'emplacement ... » erreur. Je présume que cela est dû à quelque chose d'être ordures collectées, parce que je ne pas conserver une référence en vie. La ligne qui est à l'origine du crash est: int [] data = pointer.getIntArray (0, bytesPerPlane / 4);
Je l'ai vraiment pas quoi que ce soit avec un code Objective C, et débutez avec Rococoa, donc je me trouver juste confondu avec cela. J'ai copié le code correspondant ci-dessous, et apprécierais vraiment d'aide avec cela!
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"));
}
}
La solution
Nous avons trouvé le problème.
La dernière utilisation de « imageRep » est sur la ligne "Pointeur com.sun.jna.Pointer = imageRep.bitmapData ();". Après cela, imageRep est un jeu juste pour le garbage collector Java. Et si elle frappe en avant que nous ne l'utilisez « pointeur », le tampon de support, il pointe vers mai / va se libéré, ce qui provoque de mauvaises choses se passent. Pour résoudre ce problème, l'ajout d'un jeu supplémentaire de conserver / mise en imageRep fait le travail, ou bien l'ajout de toute référence à ce à la fin de la méthode.
Autres conseils
Peut-être lié, peut-être pas. NSBitmapImageRep descend de NSImageRep, pas directement de NSObject