微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

有没有办法在 Mac OS X 上的主/子进程之间共享 NSWindows/NSView?

如何解决有没有办法在 Mac OS X 上的主/子进程之间共享 NSWindows/NSView?

我们使用 qt(https://www.qt.io) 来开发应用程序。

Qt 通过传递 QWidget::winId() 来共享小部件(QWidget),接收方调用 QWindow::fromID() 来取回小部件。 像下面的代码

Code A:
    WId winId = this->winId(); //QWidget::winId()
    SendToB(winId)

Code B:
    WId winId = ReceiveFromA()
    QWindow *window = QWindow::fromWinId( winId );
    QWidget* widgetofA = QWidget::createWindowContainer(window,this,Qt::Widget );

然后 QWidget::winId() 在 Windows 操作系统上获取 HWND,这是有效的,因为 Windows 上的 HWND 由操作系统全局管理。所以“代码B”可以从“代码A”中获取HWND/QWidget并渲染进去。

我们的qt app是按照“进程A获取进程B的widget并管理它”的设计构建的。

但在 Mac OS X 上,QWidget::winId() 是通过将 NSView* 的地址作为 QWidget::winId() 传递,并使用 (NSView*)winID 将其转换回 NSView* 来实现的。

这并不优雅,但它确实在相同的过程中起作用。

当然,当“代码A”和“代码B”属于两个主/子进程时。这不起作用。

当我们尝试通过从其他进程的地址转换来访问 NSView* 时,我们的应用程序会崩溃。

Exception Type:        EXC_BAD_ACCESS (SIGSEGV)
Exception Codes:       KERN_INVALID_ADDRESS at 0x00007fea7e8d9770
Exception Note:        EXC_CORPSE_NOTIFY

我尝试使用 [NSWindow windowNumber] 和 [[NSApplication sharedApplication] windowWithWindowNumber:windowNumber] 如下:

- (void)applicationDidFinishLaunching()
{
    NSWindow* mainWindow =  [[NSApplication sharedApplication] windows] [0];  //the NSWindow* to be shared.
    mainWindow.sharingType = NSWindowSharingReadWrite; //to allow other process access its content.

    if (fork() > 0 )   //create a sub process
    {
        // the original/main process
        NSInteger windowNumber = mainWindow.windowNumber;
        SendToSubProcess(windowNumber);
    }
    else
    {
        NSInteger windowNumber = ReceiveFromMainProcess();
        NSWindow * receivedWindow = [[NSApplication sharedApplication] windowWithWindowNumber:windowNumber];
        /*
            We Could get the correct NSWindow* here (Only if sharingType has been set to NSWindowSharingReadWrite)
            But we Could not add sub-ui to receivedWindow, otherwise we'll get following error:

            The process has forked and you cannot use this CoreFoundation functionality safely.
            You MUST exec(). Break on __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_
            COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC__() to debug.

            so we have to use execv() here
        */

        char        execPath[PATH_MAX];
        uint32_t    execPathSize = sizeof(execPath);
        (void) _NSGetExecutablePath(execPath,&execPathSize);
        const char * args[] = {execPath,"in_subprocess",windowNumber.c_str(),nullptr};
        (void) execv(execPath,(char * const *) args);

        kill(getpid(),SIGKILL);
    }

}


int main(int argc,const char * argv[]) {
    @autoreleasepool {
        if (argc >= 3)
        {
            if (strcmp(argv[1],"in_subprocess") == 0)
            {
                //launched by execv() of sub process
                intptr_t windowNumber = atoll(argv[2]);
                

            
                NSWindow * mainWindow = [[NSApplication sharedApplication] windowWithWindowNumber:windowNumber];
                //mainWindow is nil because it's another NSApplication
                //How Could we shared it here?
                
                return 0;
            }
        }
    }
    return NSApplicationMain(argc,argv);
}
    

我也试过CGWindowXXX函数,还没有结果。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。