I'm developing a macOS application to capture a specific window (e.g., an exam application like Pearson VUE or ProctorU) running inside VMware Horizon Client, but my script fails to capture the window. The goal is to programmatically capture the test window for monitoring purposes, but I suspect issues with VMware's rendering (Blast/PCoIP), anti-capture protections, or window ID misidentification are causing the failure.
Environment:
OS: macOS Sequoia 15.3 VMware Horizon Client: Version 2406 Build 8.13.0 (10025792799) Language: Objective-C or Python using Quartz (CGWindowListCopyWindowInfo) Display Protocol: VMware Blast Codec decoding and (H.264 decoding)
What I’ve Tried:
Objective-C Approach: I’m using CGDisplayCreateImage to capture the entire main display. The script saves the screenshot as a PNG, but when the exam software is active in VMware Horizon Client, the output is blank or shows the virtual desktop background.
#include <CoreGraphics/CoreGraphics.h>
#include <Foundation/Foundation.h>
void captureFullScreen() {
CGDirectDisplayID mainDisplay = CGMainDisplayID();
CGImageRef screenshot = CGDisplayCreateImage(mainDisplay, kCGDisplayStreamFrameRectNull);
if (screenshot == NULL) {
printf("Failed to capture screenshot.\n");
return;
}
// Create a bitmap representation
NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithCGImage:screenshot];
NSData *pngData = [bitmap representationUsingType:NSBitmapImageFileTypePNG properties:@{}];
// Save to file
NSString *filePath = @"screenshot.png";
[pngData writeToFile:filePath atomically:YES];
printf("Screenshot saved as %s\n", [filePath UTF8String]);
// Clean up
CGImageRelease(screenshot);
[bitmap release];
}
int main() {
@autoreleasepool {
captureFullScreen();
}
return 0;
}
Python Approach: I’m also using PyObjC with Quartz to capture the full screen. The script works for normal macOS applications but fails similarly (blank or background) when capturing the exam software in VMware Horizon Client.
import Quartz
import Cocoa
def capture_screenshot():
# Get the main display's bounds
main_display_id = Quartz.CGMainDisplayID()
display_bounds = Quartz.CGDisplayBounds(main_display_id)
# Capture the entire screen
screenshot_image = Quartz.CGWindowListCreateImage(
display_bounds,
Quartz.kCGWindowListOptionOnScreenOnly,
Quartz.kCGNullWindowID,
Quartz.kCGWindowImageDefault
)
# Check if the image was captured successfully
if screenshot_image is None:
print("Failed to capture screenshot")
return
# Create a destination for the screenshot
destination_url = Cocoa.NSURL.fileURLWithPath_("screenshot.png")
# Create a bitmap context to draw the image
bitmap_rep = Cocoa.NSBitmapImageRep.alloc().initWithCGImage_(screenshot_image)
png_data = bitmap_rep.representationUsingType_properties_(Cocoa.NSBitmapImageFileTypePNG, None)
# Write the PNG data to file
png_data.writeToURL_atomically_(destination_url, True)
print(f"Screenshot saved as {destination_url.path()}")
if __name__ == "__main__":
capture_screenshot()