在Swift中包装libcups C库

问题描述 投票:0回答:2

我正在尝试包装libcups库https://github.com/apple/cups以在我的Swift项目中使用。

我已经尝试了https://www.cups.org/doc/cupspm.html中的一些示例,但它们运行正常。

但是在包装要在Swift项目中使用的C代码时,我很挣扎。

我一直在网上搜索如何在Swift中包装C库,但进展不大。

这是C代码

#include <stdio.h>
#include <cups/cups.h>

typedef struct {
    int num_dests;
    cups_dest_t *dests;
} my_user_data_t;

int my_dest_cb(my_user_data_t *user_data, unsigned flags, cups_dest_t *dest) {
    if (flags & CUPS_DEST_FLAGS_REMOVED) {
        user_data->num_dests = cupsRemoveDest(dest->name, dest->instance, user_data->num_dests, &(user_data->dests));
    } else {
        user_data->num_dests = cupsCopyDest(dest, user_data->num_dests, &(user_data->dests));
    }
    return 1;
}

int my_get_dests(cups_ptype_t type, cups_ptype_t mask, cups_dest_t **dests) {
    my_user_data_t user_data = { 0, NULL };

    if (!cupsEnumDests(CUPS_DEST_FLAGS_NONE, 1000, NULL, type, mask, (cups_dest_cb_t)my_dest_cb, &user_data)) {
        cupsFreeDests(user_data.num_dests, user_data.dests);
        *dests = NULL;
        return 0;
    } else {
        *dests = user_data.dests;
        return user_data.num_dests;
    }
}

int main(int argc, const char * argv[]) {
    cups_dest_t *dests = NULL;
    int num_dests = my_get_dests(0, 0, &dests);
    printf("Destination found: %d\n", num_dests);

    cups_dest_t *dest;
    int i;
    const char *value;

    for (i = num_dests, dest = dests; i > 0; i--, dest++) {
        if (dest->instance == NULL) {
            value = cupsGetOption("printer-info", dest->num_options, dest->options);
            printf("%s (%s)\n", dest->name, value ? value : "No description");
        }
    }
    return 0;
}

这里是同一件事,但在Swift中

let destinationsCallback: cups_dest_cb_t = { user_data, flags, dest in
    // (void *user_data, unsigned flags, cups_dest_t *dest)
    var userDataPointer = user_data!.assumingMemoryBound(to: my_user_data_t.self).pointee
    var destData = dest!.pointee

    if destData.instance != nil {
        print("\(String(cString: destData.name))/\(String(cString: destData.instance))")
    } else {
        print(String(cString: destData.name))
    }

    if flags == CUPS_DEST_FLAGS_REMOVED {
        userDataPointer.num_dests = cupsRemoveDest(destData.name, destData.instance, userDataPointer.num_dests, &(userDataPointer.dests))
    } else {
        userDataPointer.num_dests = cupsCopyDest(dest, userDataPointer.num_dests, &(userDataPointer.dests))
    }
    return 1
}

func getDestinations(type: UInt32, mask: UInt32, dests: UnsafeMutablePointer<cups_dest_t>) -> Int32 {
    var userData = my_user_data_t(num_dests: 0, dests: nil)

    if cupsEnumDests(UInt32(CUPS_DEST_FLAGS_NONE), 1000, nil, type, mask, destinationsCallback, &userData) != 1 {
        return 0
    } else {
        return userData.num_dests
    }
}

我无法获得userData以返回正确的值,我认为这是由于我处理指针的方式。

非常感谢,如果我能得到一些建议。

swift cups
2个回答
0
投票

我已经用C编写了所有的库访问函数,然后从我的快速代码中调用这些 C函数。这是因为我已经有杯子从以前的项目访问代码,并且不需要更改。

这很容易做到,互联网上有足够的例子说明如何做到这一点-从swift快速调用c函数-包括传递返回值。

很抱歉,但这是几个月前的事情,所以我无法提供更多详细信息。但是您肯定会在这里和互联网上找到示例。

希望有帮助,罗伯特


0
投票

恕我直言,在Swift中使用此类C库的最佳方法是在Objective-C中使用它们。尽管如此,主要的问题似乎是您没有将对用户数据的更改写回,这就是为什么您总是得到初始值的原因。您需要像这样在回调中对其进行更新

let userDataPointer = user_data!.assumingMemoryBound(to: my_user_data_t.self)
var userData = userDataPointer.pointee
...
// make some changes to userData

userDataPointer.pointee = userData

return 1

而且您的C代码和Swift代码之间似乎也有一些区别,例如使用'flags == CUPS_DEST_FLAGS_REMOVED'检查标志,通常这是错误的检查标志的方式,并且将cupsEnumDests的结果与1进行比较您检查结果是否为0的原始代码。

© www.soinside.com 2019 - 2024. All rights reserved.