Ở mức cơ bản nhất, bạn có thể tạo mã hoạt động bằng cách sử dụng phần cpointer.i của thư viện SWIG để cho phép tạo đối tượng "con trỏ trỏ tới" trực tiếp trong Java.
Ví dụ cho các tập tin tiêu đề:
#include <stdlib.h>
typedef struct sp_session sp_session;
typedef struct {} sp_session_config;
typedef int sp_error;
inline sp_error sp_session_create(const sp_session_config *config, sp_session **sess) {
// Just for testing, would most likely be internal to the library somewhere
*sess = malloc(1);
(void)config;
return sess != NULL;
}
// Another thing that takes just a pointer
inline void do_something(sp_session *sess) {}
Bạn có thể bọc nó với:
%module spotify
%{
#include "test.h"
%}
%include "test.h"
%include <cpointer.i>
%pointer_functions(sp_session *, SessionHandle)
Mà sau đó cho phép chúng tôi viết một cái gì đó như:
public class run {
public static void main(String[] argv) {
System.loadLibrary("test");
SWIGTYPE_p_p_sp_session session = spotify.new_SessionHandle();
spotify.sp_session_create(new sp_session_config(), session);
spotify.do_something(spotify.SessionHandle_value(session));
}
}
trong Java. Chúng tôi sử dụng SessionHandle_value()
để tạo ra con trỏ kép và new_SessionHandle()
để tạo đối tượng con trỏ kép cho chúng ta. (Có các chức năng khác để làm việc với đối tượng con trỏ kép).
Các công trình trên và rất đơn giản để bọc, nhưng hầu như không "trực quan" đối với một lập trình viên Java và lý tưởng là chúng tôi sẽ trưng ra toàn bộ thư viện trong một cái gì đó trông giống Java hơn.
Một lập trình viên Java dự kiến rằng đối tượng xử lý phiên mới sẽ được trả về từ hàm tạo và rằng một ngoại lệ sẽ được sử dụng để chỉ ra các lỗi. Chúng tôi có thể làm cho SWIG tạo mà giao diện với một vài typemaps và một số sử dụng cẩn thận của %exception
, bằng cách thay đổi các tập tin giao diện hơi:
%module spotify
%{
#include "test.h"
%}
// 1:
%nodefaultctor sp_session;
%nodefaultdtor sp_session;
struct sp_session {};
// 2:
%typemap(in,numinputs=0) sp_session ** (sp_session *tptr) {
$1 = &tptr;
}
// 3:
%typemap(jstype) sp_error sp_session_create "$typemap(jstype,sp_session*)"
%typemap(jtype) sp_error sp_session_create "$typemap(jtype,sp_session*)"
%typemap(jni) sp_error sp_session_create "$typemap(jni,sp_session*)";
%typemap(javaout) sp_error sp_session_create "$typemap(javaout,sp_session*)";
// 4:
%typemap(out) sp_error sp_session_create ""
%typemap(argout) sp_session ** {
*(sp_session **)&$result = *$1;
}
// 5:
%javaexception("SpotifyException") sp_session_create {
$action
if (!result) {
jclass clazz = JCALL1(FindClass, jenv, "SpotifyException");
JCALL2(ThrowNew, jenv, clazz, "Failure creating session");
return $null;
}
}
%include "test.h"
Các ý kiến đánh số tương ứng với những điểm sau:
- Chúng tôi muốn
sp_session
loại đục để ánh xạ tới loại Java "đẹp" nhưng không cho phép tạo/xóa loại trực tiếp trong Java.(Nếu có một hàm sp_session_destroy
để có thể sắp xếp để có được tự động gọi khi đối tượng Java bị phá hủy nếu đó là mong muốn bằng cách sử dụng kiểu chữ javadestruct). fake, empty definition combined with %nodefaultctor
and %nodefaultdtor
sắp xếp cho việc này.
- Đối với thông số đầu vào mà chúng tôi đang thực hiện trở lại thay vào đó chúng ta cần phải ẩn nó từ giao diện Java (sử dụng
numinputs=0
) và sau đó cung cấp một cái gì đó để diễn ra của nó trong phần C tạo ra của giao diện.
- Để trả về
sp_session
thay vì mã lỗi, chúng ta cần phải điều chỉnh các kiểu chữ để trả về từ hàm - cách đơn giản nhất để thay thế chúng là các bản đồ đã được sử dụng nếu hàm được khai báo là trả về a sp_session
sử dụng $typemap
.
- Theo như đầu ra có liên quan, chúng tôi không muốn làm bất cứ điều gì mà nó thường được sắp xếp, nhưng chúng tôi muốn trả lại con trỏ mà chúng tôi đã sử dụng làm trình giữ chỗ cho tham số nhập bổ sung trong 2.
Cuối cùng, chúng tôi muốn gửi toàn bộ cuộc gọi đến sp_session_create
trong một số mã sẽ kiểm tra giá trị trả lại thực và ánh xạ tới một ngoại lệ Java nếu nó cho biết lỗi. Tôi đã viết những lớp ngoại lệ sau bằng tay cho đó là tốt:
public class SpotifyException extends Exception {
public SpotifyException(String reason) {
super(reason);
}
}
Sau khi thực hiện tất cả các công việc này ngay bây giờ chúng ta đang ở trong một vị trí để sử dụng trong mã Java như sau:
public class run {
public static void main(String[] argv) throws SpotifyException {
System.loadLibrary("test");
sp_session handle = spotify.sp_session_create(new sp_session_config());
spotify.do_something(handle);
}
}
Đó là đơn giản hơn và trực quan hơn so với bản gốc nhưng đơn giản hơn để viết giao diện. Độ nghiêng của tôi sẽ sử dụng advanced renaming feature để làm cho các tên kiểu "cũng giống Java hơn".
Bạn có lỗi trong tệp giao diện, 'pointer_functions (sp_session *, SessionHandle)'. Xóa '*'. Tôi nhận được lỗi biên dịch nếu có. Tuy nhiên, khi gỡ bỏ nó, tôi không còn tạo ra một con trỏ nữa. Làm thế nào để giải quyết điều này –
nếu '% pointer_functions (sp_session *, SessionHandle)' không hoạt động thì nhiều khả năng có vấn đề với 'sp_session' hoặc cái gì đó khác trong giao diện của bạn. Tôi chỉ cần kiểm tra gấp đôi và bit đó chắc chắn hoạt động đúng với SWIG 2.0.11. – Flexo
Cảm ơn. Bằng cách chỉnh sửa thủ công nguồn _wrap tôi có thể làm cho nó hoạt động. Tôi sử dụng SWIG 2.0.7.3. Tôi nghĩ rằng tôi sẽ cố gắng cài đặt một SWIG mới hơn. Không bao giờ thành công với con trỏ kép. Nó chèn một số const * & phôi –