-3

Edit: To future googlers abarnert's answer works giving a NSHIObject (from HIToolbox, HI standing for human interface), I can find little more documentation on this, the only mention on apple.com (there is ZERO, ZIP, NADA documentation on a class called NSHI object as of this point https://www.google.com/#q=%22NSHIObject%22+site%3Aapple.com&filter=0 ) is In object c if I have the following http://lists.apple.com/archives/webkitsdk-dev/2010/Sep/msg00007.html which doesn't work for this object the NSWindow isn't created. Yay for apples api documentation.

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

Original Question about loading the pointer given from wxPython


C Code

// 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);

How do I do this syntax in pyobjc? I see it mentions 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.

So what do I do? This (if the object type is NSInt)?

arg = _C_PTR + "NSInt" + "1776"

Objective C Code (Added later) Please note you have to somehow inject this into the python process other wise it won't work

#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;
}
4

2 回答 2

4

根据您对 bbum 回答的评论:

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

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

view = objc.objc_object(c_void_p=ptr)

当然,我认为不会wxPython为您ctypes.c_void_p用来获取指针的任何函数提供值。我不知道它了你什么,但最有可能的是 a 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"

我不确定你为什么首先要构建一个类型字符串,但是……</p>

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

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


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


同时,从您的评论和代码来看,您尝试做的事情实际上没有任何意义,而且不可能工作。您现在成功地做到了这一事实就是您崩溃的原因。

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

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

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

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

于 2013-06-03T01:43:53.507 回答
2

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

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

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

于 2013-06-02T23:12:01.157 回答