【问题标题】:Equivalent Objective C syntax in python using pyobjc使用pyobjc在python中等效的Objective C语法
【发布时间】:2013-05-29 02:05:42
【问题描述】:

编辑:对于未来的 googlers abarnert 的回答作品提供 NSHIObject(来自 HIToolbox,HI 代表人机界面),我可以找到更多关于此的文档,在 apple.com 上唯一提及(那里是关于一个名为 NSHI 对象的类的零、ZIP、NADA 文档,截至目前https://www.google.com/#q=%22NSHIObject%22+site%3Aapple.com&filter=0) 是 在对象 c 中,如果我有以下 http://lists.apple.com/archives/webkitsdk-dev/2010/Sep/msg00007.html 不适用于此对象,则不会创建 NSWindow。是的,苹果 api 文档。

NSWindow.initWithWindowRef_(nshi_object)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: Expecting instance of NSWindow as self, got one of NSHIObject

关于加载从 wxPython 给出的指针的原始问题


C 代码

// our data
int a = 42;
// create a pointer to that data
int *p = &a;
// p now contains the address (say 1776) and that address has the integer 42
// get the data back
int ret_a = *p;

// now if we already have an address
int* manual_pointer = (int*) 1776; 
int man_a = *manual_pointer;

printf("%d,%d\n", ret_a, man_a);

如何在 pyobjc 中执行此语法?我看到它提到了here

More complex types can be represented using longer type strings:

    a pointer to some type is _C_PTR followed by the type string of the pointed-to type.

那我该怎么办?这个(如果对象类型是 NSInt)?

arg = _C_PTR + "NSInt" + "1776"

Objective C 代码(稍后添加) 请注意,您必须以某种方式将其注入 python 进程,否则它将无法工作

#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>

int main(int argc, const char * argv[])
{

    @autoreleasepool {

        char line[2048];
        // this will store are address
        long adr;
        printf("According to \n- http://forums.wxwidgets.org/viewtopic.php?f=23&t=31778\n- http://forums.wxwidgets.org/viewtopic.php?f=23&t=18645\n");
        printf("This will prompt you for a pointer address; please paste in the long you received from GetHandle()\n");
        printf("Please enter pointer address: ");
        fgets(line, sizeof(line), stdin);
        sscanf(line, "%ld", &adr);
        printf("Using address: %ld\n", adr);

        printf("Grabbing view...");

        // our NSView    
        NSView *view =  (__bridge NSView *)((void *)adr);

        NSRect f = view.frame;
        int w = f.size.width;
        int h = f.size.height;
        printf("Size(%d, %d)", w, h);

    }
    return 0;
}

【问题讨论】:

  • 您展示的代码是纯C,其中没有ObjC。指向 Objective-C 类型字符串的链接在这里似乎根本不相关。你到底想做什么?
  • 你没有提到你真正想要做什么,这让你很难告诉你该做什么。
  • 无论如何,您所指的 PyObjC 文档是用于描述函数/方法参数类型的 Objective-C 类型编码的文档。作为 PyObjC 的用户,您应该没有理由实际使用这些类型编码。

标签: python objective-c macos pyobjc


【解决方案1】:

来自您对 bbum 回答的评论:

问题是我从 C++ 库 (wxPython) 中获取了一个指针地址,该地址指向我想要获取的 NSView 对象。

为此,只需使用objc_object 构造函数:

view = objc.objc_object(c_void_p=ptr)

当然,我认为wxPython 不会为您用于获取指针的任何函数提供ctypes.c_void_p 值。我不知道它做了什么给你,但最有可能的是int,在这种情况下你可以这样做:

view = objc.objc_object(c_void_p=ctypes.c_void_p(ptr))

您没有提及您使用的是哪个版本的 PyObjC。如果它在 2.5 之前(您可以查看 objc.version),您要么必须手动构建 PyCapsule 对象,要么从桥的另一侧执行此操作。我没有要测试的旧副本或旧文档,所以这是凭记忆编写的,但看起来像这样:

view = NSView.objectWithSomethingOrOther_(ptr)

同时,根据您的原始问题:

arg = _C_PTR + "NSInt" + "1776"

我不确定你为什么首先尝试构建类型字符串,但是……

指向某个类型 X 的指针的类型字符串是 _C_PTR,后跟 X 的类型字符串,而不是 X 的名称。此外,没有类型 NSInt。如果你的意思是像NSNumber 这样的类类型,你可以只使用_C_ID(就像你可以在本机ObjC 中使用id 而不是NSNumber *)。如果您的意思是整数类型NSInteger,那就是_C_PTR + _C_NSInteger。如果您的意思是一个没有特殊名称的整数类型,您必须找出它是 typedef 的类型并使用它——例如,_C_PTR + _C_LNG 将适用于 64 位 Mac 上的 NSInteger *

同时,一个类型字符串命名一个类型,而不是一个值,所以如果 1776 应该是指向的位置,或者那个位置的值,或者我能想到的任何其他东西,那不会甚至没有意义。


最后,我不知道你的 C 代码(在任何地方都没有 ObjC)应该演示什么,但我敢打赌,如果你真的运行它,它会出现段错误。


同时,根据您的评论和your code,您尝试做的事情实际上没有任何意义,而且不可能工作。您现在成功的事实就是您崩溃的原因。

每个进程都有自己的虚拟地址空间。当您从一个进程的地址空间中获取一个指针并在另一个进程中使用它时,它并没有指向相同的对象。它指向完全不同的对象,或者根本没有。这就是为什么会出现段错误:0x000000007a6e5c90 指向 wxPython 程序地址空间中的 NSView,但相同的地址指向交互式解释器地址空间中未映射的内存。

此外,虽然有一些 API 可以从其他进程映射内存区域,或者直接读写其他进程的地址空间,但这在这里对您没有帮助,因为如果有任何指针(包括不透明的内部指针)在您指向的对象,您还必须明确映射 那些。而且,对于 ObjC 对象,即使是 that 也不起作用,因为 ObjC 依赖于(进程)全局对象工作空间。 (理论上,您可以编写直接操作其他进程的 ObjC 工作区的 C 代码,而不是使用 ObjC,但是……您不想这样做。)

如果您想从另一个进程中的一个进程访问NSView,有两种方法可以做到。要么您必须使用高级跨进程 API 来操作窗口,要么您必须将代码注入另一个进程并触发它(例如,F-Script Anywhere 所做的)——或者,作为第二,作为调试器附加到另一个进程。

但是,如果您自己编写这两个程序,则有一种更简洁的方法。将您的 GUI 应用程序编写为可通过某种方式进行外部控制。在 Mac 上执行的一种方法是使用 AppleScript 界面。使用 CocoaScripting 导出允许其他应用程序执行诸如移动窗口之类的操作的 API。然后使用 appscript 或 ScriptingBridge,或通过 NSAppleScript 使用双语言方法来使用该 API,而不是尝试直接与您的 NSView 对象对话。 (如果你真的想的话,你实际上可以通过 CocoaScripting 导出整个 NSView 界面,但这可能不是最好的答案。)

【讨论】:

  • 不,c 代码可以正常工作,当然不能使用 1776,但如果使用实际输入的地址,它就可以正常工作。我有那个代码的原因是 wxPython 给了我一个整数,它应该是一个指向 Mac OS X 上的 NSView 的指针
  • 感谢您的详细解答。
  • @bbum:我认为你不应该删除你的答案; Python 有意不处理指针的信息(因此 PyObjC、ctypes、win32api 等库如果愿意,必须解决这个问题)是相关的。
  • @Zimm3r:我在答案的主要部分解决了这个用例。这不是你要找的吗? (如果您告诉我们您正在调用什么 wxPython 函数,返回值的类型是什么等,这会有所帮助。但我猜它类似于 getHandle(),它返回一个 int 或 long,并且没有其他选择返回任何其他内容。)
  • 是的,对不起,我只是在解决最后一点,而不是试图说这是我的错,是我的错,是的,它是 GetHandle()
【解决方案2】:

Python 根本不处理指针。事实上,它积极阻止以各种方式使用它们。您可以使用id() 函数来检索 Python 对象的地址,但没有相应的函数可以反其道而行之(这不是开玩笑)。

现在,假设你有一个指向 C 语言的指针,你应该能够用 ctypes 模块描述那个东西,然后将地址视为指针并随意解码。但这很棘手。

不是最具体的例子,但是知道 Python、Objective-C 和熟悉 ctypes 的人的维恩图是一个相当小的群体(这就是为什么你通常最好坚持使用原生 ObjC 的一个重要原因对于 iOS/Cocoa)。

【讨论】:

  • 问题是我从 C++ 库 (wxPython) 中获取了一个指向我想要获取的 NSView 对象的指针地址,通常 api 处理它(在 windows 和 X11 上它使用它作为处理并继续前进,但可悲的是对象 C 和苹果不同。
  • PyObjC 对象的id 是 Python 包装器,而不是 ObjC 对象。为此,您可以使用objc.pyobjc_id。而这确实有一个反向操作。
  • 另外,我认为了解 Python、ObjC 和 ctypes 的人的交集可能在 PyObjC 社区的 75% 左右。而且我强烈不同意您最好坚持使用本机 ObjC。这就像说你最好坚持在 linux 上使用本机 C 或在 Windows 上使用 C++。如果你的代码比 Cocoa GUI 的东西有更多的逻辑,那么 Python 是比 ObjC 更好的语言。即使处理 Cocoa,如果没有 PyObjC(或 FScript 或 MacRuby),您也没有交互式解释器可供探索。
猜你喜欢
  • 2012-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多