如何解决有没有办法在 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 举报,一经查实,本站将立刻删除。