【问题标题】:How does this CGPDFDictionaryGetString translate into Monotouch?这个 CGPDFDictionaryGetString 是如何翻译成 Monotouch 的?
【发布时间】:2011-09-21 20:19:06
【问题描述】:

我有一段来自 GIT 上出色的 VFR PDF 查看器的 ObjC 代码。 它使用CGPDFDictionaryGetString 从 PDF 注释中获取指向字符串的指针。然后它使用一些字节指针转换来获得最终的字符串。 在 Monotouch 中没有 CGPDFDictionary.GetString() 而只有 .GetName() - 这是唯一返回字符串的方法,所以我认为它必须是正确的方法,但它不起作用。 我可以很好地检索数组、字典、浮点数和整数 - 只有字符串似乎不起作用。

请参阅下面的小代码示例。

CGPDFStringRef uriString = NULL;
// This returns TRUE in the ObjC version and uriString is a valid pointer to a string.
if (CGPDFDictionaryGetString(actionDictionary, "URI", &uriString) == true)
{
  // Do some pointer magic - how to do this in MT? Do I have to at all?
  const char *uri = (const char *)CGPDFStringGetBytePtr(uriString);
  // *uri now contains a URL, I can see it in the debugger.
}

我是这样翻译的:

string sUri = null;
// This returns FALSE. Hence my sUri is NULL. Seems like GetName() is not the analogy to CGPDFDictionaryGetString.
if(oActionDic.GetName("URI", out sUri))
{
  // I never get here.
}

编辑: 查看 Mono 源代码,我可以在 Master 分支中看到: // TODO: GetString -> 返回一个 CGPDFString

切换到分支 4.2 表明它似乎在那里。所以我从那里复制了代码,但有两个问题:

  • 我收到关于“不安全”关键字的错误。它告诉我添加“不安全”命令行选项。那是什么,添加它是个好主意吗?在哪里?
  • 它似乎仍然可以运行,但是在获取 CGPDFString 时应用程序挂起。

[DllImport (Constants.CoreGraphicsLibrary)] public extern static IntPtr CGPDFStringGetLength (IntPtr pdfStr);

    [DllImport (Constants.CoreGraphicsLibrary)]
    public extern static IntPtr CGPDFStringGetBytePtr (IntPtr pdfStr);

    public static string PdfStringToString (IntPtr pdfString)
    {
        if (pdfString == IntPtr.Zero)
            return null;

        int n = (int)CGPDFStringGetLength (pdfString);
        unsafe
        {
            return new String ((char *)CGPDFStringGetBytePtr (pdfString), 0, n);
        }
    }

    [DllImport (Constants.CoreGraphicsLibrary)]
    extern static bool CGPDFDictionaryGetString (IntPtr handle, string key, out IntPtr result);

    public static bool GetStringFromPdfDictionary (CGPDFDictionary oPdfDic, string key, out string result)
    {
        if (key == null)
            throw new ArgumentNullException ("key");
        IntPtr res;
        if (CGPDFDictionaryGetString (oPdfDic.Handle, key, out res))
        {
            result = PdfStringToString (res);
            return true;
        }
        result = null;
        return false;
    }

【问题讨论】:

  • 为什么要使用 unsafe?似乎没有必要。
  • 除了不安全块中允许的指针操作之外,还做什么?
  • 使用Marshal 类从空终止字符串复制到.net 字符串

标签: c# pdf xamarin.ios pinvoke cgpdfdictionaryref


【解决方案1】:

如果您在源代码中使用 unsafe 关键字,则需要在构建程序集时启用 unsafe。在 MonoDevelop 中,您可以这样做:

  • 右键单击项目;
  • 选择选项菜单;
  • 选择常规图标;
  • 点击允许“不安全”代码复选框
  • 点击确定按钮
  • 然后重建。

注意:如果没有这个,你之前的构建不应该工作。

mastermonotouch-4.2 之间的源代码在这种情况下应该是相同的。我会检查,但很可能您正在查看 GIT 中的特定修订版(在更新代码之前已推送)。我会确认并编辑帖子。

更新:这是master 的链接(即可用的最新代码),它显示:

public bool GetString (string key, out string result)

可用。但是,它确实取决于 unsafe 代码(在 PdfStringToString 内),如果在复制/粘贴此代码的程序集中不允许存在不安全代码,您应该无法编译这些代码。

UPDATE2 :返回的值是 UTF8 编码的,因此从它创建的字符串需要正确解码(另一个 System.String 构造函数允许这样做)。上面master的链接应该已经指向固定版本了。

【讨论】:

  • 同时我提交了一个错误。是 975。GetString() 存在问题,更准确地说是“new String ((char *)CGPDFStringGetBytePtr (pdfString), 0, n)”这一行
  • 在看到复选框之前,我在选项中添加了一个“不安全”参数。但这无济于事。我从 master 复制了代码并得到了与使用您提供的用于测试的 monotouch.dll 时相同的(不正确的)结果,因此很可能不是我的代码失败了,而是将字节转换为字符时出现了问题。
  • 感谢您填写错误报告。我会在几个小时内(晚餐后)查看它,并在错误报告中进一步发现(或修复:-)。
  • 如果您有一个固定的 DLL 或代码修复,那就太好了。好好吃饭吧,我现在就好好睡。
  • 已修复。返回的缓冲区是 UTF8 编码的,并且 System.String 必须知道它才能正确解码。重建 4.2 分支需要一些时间(因为我在 master 上工作),但一旦完成,我将使用更新的二进制文件更新错误 - 但这可能是“我的”明天:)
【解决方案2】:

我不太喜欢使用不安全的块,并且想出了一种不使用不安全块来实现此方法的方法。最初我确实尝试了不安全的样式,但是由于字符串存储在 UTF8 中,因此需要对其进行转换。

private bool PDFDictionaryGetString (IntPtr handle, string key, out string result)
{
    IntPtr stringPtr;
    result = null;

    if (CGPDFDictionaryGetString(handle, "URI", out stringPtr)) {

        if (stringPtr == IntPtr.Zero)
                return false;

        // Get length of PDF String
        uint n = (uint) CGPDFStringGetLength (stringPtr);

        // Get the pointer of the string
        var ptr = CGPDFStringGetBytePtr (stringPtr);
        // Get the bytes
        var data = NSData.FromBytes(ptr, n);
        // Convert to UTF8
        var value = NSString.FromData(data, NSStringEncoding.UTF8);

        result = value.ToString();
        return true;
    }
    return false;
} 

有一个完整的博客文章here 和工作示例,包括完整的源代码here,具有多页滑动导航和可点击链接。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-25
    • 2012-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多