Smoke は、Qt フレームワークにイントロスペクティブ C++ API ラッパーを提供します。
https://techbase.kde.org/Development/Languages/Smoke
https://techbase.kde.org/Development/Languages/Smoke/API_Documentation
SmokeC は、Smoke ラッパーを C 関数でラップして、C からの Smoke API の使用を容易にします。
https://github.com/pankajp/pysmoke/blob/master/smokec/smokec.cpp
C で動作するサンプル アプリケーション (上記の最初のリンクの C++ の例と機能的に同じ):
https://github.com/pankajp/pysmoke/blob/master/examples/helloidget.c
このサンプル アプリケーションを変更して、オブジェクト メソッドへの呼び出しをさらに追加しようとしていますが、 などQWidget
の引数を取るメソッドを呼び出す方法がわかりません。QString
setWindowTitle
void setWindowTitle(const QString &);
これが私の最善の推測です:
/* Set the window title... Segfaults */
methId = Smoke_findMethod(classId.smoke, "QWidget", "setWindowTitle$");
klass = Smoke_classes(classId.smoke)[classId.index];
meth = Smoke_methods(methId.smoke)[Smoke_methodMaps(methId.smoke)[methId.index].method];
stack[1].s_voidp = (void*)"hello universe";
(*klass.classFn)(meth.method, widget, stack);
...しかし、これはセグメンテーション違反です。QString
SmokeCラッパーを使用して引数を作成する方法を教えてもらえますか?
私の完全な修正済みサンプル アプリケーションは次のとおりです。
/*
* File: hellowidget.c
* Author: pankaj
*
* Created on November 19, 2013, 2:41 PM
*/
#include <stdio.h>
#include <string.h>
#include "smokec.h"
#include "bindings.h"
/*
* In a bindings runtime, this should return the classname as used
* in the bindings language, e.g. Qt::Widget in Ruby or
* Qyoto.QWidget in C# or QtGui.QWidget in python
*/
char *className(CSmokeBinding binding, Index classId) {
return (char*) Smoke_classes(CSmoke_FromBinding(binding))[classId].className;
}
void deleted(CSmokeBinding binding, Index classId, void *obj)
{
}
cbool callMethod(CSmokeBinding binding, Index method, void *obj, Stack args, cbool isAbstract)
{
return 0;
}
int main(int argc, char **argv)
{
/* Initialize the Qt SMOKE runtime. */
init_qtcore_CSmoke();
init_qtgui_CSmoke();
CSmoke qtcore_smoke = qtcore_CSmoke();
CSmoke qtgui_smoke = qtgui_CSmoke();
/* Create a SmokeBinding for the Qt SMOKE runtime. */
CSmokeBinding qtcoreBinding = SmokeBinding_new(qtcore_smoke, deleted, callMethod, className);
CSmokeBinding qtguiBinding = SmokeBinding_new(qtgui_smoke, deleted, callMethod, className);
/* Find the 'QApplication' class. */
CModuleIndex classId = findClass("QApplication");
/* find the methodId. we use a munged method signature, where
* $ is a plain scalar
* # is an object
* ? is a non-scalar (reference to array or hash, undef) */
CModuleIndex methId = Smoke_findMethod(classId.smoke, "QApplication", "QApplication$?"); // find the constructor
/* Get the Smoke::Class */
Class klass = Smoke_classes(classId.smoke)[classId.index];
// findMethod() returns an index into methodMaps, which has
// information about the classId, methodNameId and methodId. we
// are interested in the methodId to get a Smoke::Method
Method meth = Smoke_methods(methId.smoke)[Smoke_methodMaps(methId.smoke)[methId.index].method];
StackItem stack[3];
// QApplication expects a reference to argc, so we pass it as a pointer
stack[1].s_voidp = &argc;
stack[2].s_voidp = argv;
// call the constructor, Smoke::Method::method is the methodId
// specifically for this class.
(*klass.classFn)(meth.method, 0, stack);
// the zeroth element contains the return value, in this case the
// QApplication instance
void *qapp = stack[0].s_voidp;
// method index 0 is always "set smoke binding" - needed for
// virtual method callbacks etc.
stack[1].s_voidp = qtguiBinding.binding;
(*klass.classFn)(0, qapp, stack);
// create a widget
classId = findClass("QWidget");
methId = Smoke_findMethod(classId.smoke, "QWidget", "QWidget");
klass = Smoke_classes(classId.smoke)[classId.index];
meth = Smoke_methods(methId.smoke)[Smoke_methodMaps(methId.smoke)[methId.index].method];
(*klass.classFn)(meth.method, 0, stack);
void *widget = stack[0].s_voidp;
// set the smoke binding
stack[1].s_voidp = qtguiBinding.binding;
(*klass.classFn)(0, widget, stack);
/* Show the widget maximized.*/
methId = Smoke_findMethod(classId.smoke, "QWidget", "showMaximized");
meth = Smoke_methods(methId.smoke)[Smoke_methodMaps(methId.smoke)[methId.index].method];
(*klass.classFn)(meth.method, widget, 0);
/* Raise the window to the foreground */
methId = Smoke_findMethod(classId.smoke, "QWidget", "raise");
meth = Smoke_methods(methId.smoke)[Smoke_methodMaps(methId.smoke)[methId.index].method];
(*klass.classFn)(meth.method, widget, 0);
/* Set the modified indicator. */
methId = Smoke_findMethod(classId.smoke, "QWidget", "setWindowModified$");
meth = Smoke_methods(methId.smoke)[Smoke_methodMaps(methId.smoke)[methId.index].method];
stack[1].s_bool = 1;
(*klass.classFn)(meth.method, widget, stack);
/* Set the window title... Segfaults */
methId = Smoke_findMethod(classId.smoke, "QWidget", "setWindowTitle$");
klass = Smoke_classes(classId.smoke)[classId.index];
meth = Smoke_methods(methId.smoke)[Smoke_methodMaps(methId.smoke)[methId.index].method];
stack[1].s_voidp = (void*)"hello universe";
(*klass.classFn)(meth.method, widget, stack);
// we don't even need findClass() when we use the classId provided
// by the MethodMap
methId = Smoke_findMethod(qtgui_smoke, "QApplication", "exec");
klass = Smoke_classes(methId.smoke)[Smoke_methodMaps(methId.smoke)[methId.index].classId];
meth = Smoke_methods(methId.smoke)[Smoke_methodMaps(methId.smoke)[methId.index].method];
// call QApplication::exec()
(*klass.classFn)(meth.method, 0, stack);
// store the return value of QApplication::exec()
int retval = stack[0].s_int;
// destroy the QApplication instance
methId = Smoke_findMethod(qtgui_smoke, "QApplication", "~QApplication");
meth = Smoke_methods(methId.smoke)[Smoke_methodMaps(methId.smoke)[methId.index].method];
(*klass.classFn)(meth.method, qapp, 0);
// destroy the smoke instance
CSmoke_delete(qtgui_smoke);
CSmoke_delete(qtcore_smoke);
// return the previously stored value
return retval;
}