В позапрошлом посте рассказывалось о создании экземпляров объектов GObject по имени класса, где, кроме всего прочего, было сказано:
Лично у меня данный пример как есть в Windows не заработал (собирал компилятором mingw). Не удавалось найти указатель на функцию cow_get_type. Опытным путем выяснилось, что работает такой механизм при соблюдении двух условий:
Получается: либо типы всех потенциально загружаемых из файла объектов должны быть заранее зарегистрированы, т.е. все (обязательно все) и явно (в каком-то виде) типы должны быть прописаны в коде разработчиком, либо же нужен неизящный и непортабельный механизм вроде поиска в таблице символов исполняемого файла для имени каждого подгружаемого из файла класса соответствующего метода foo_bar_get_type... и вызова этого метода.Все почти так и есть, но в коде GtkBuilder случайно был найден довольно изящный и портабельный механизм поиска foo_bar_get_type. Идея простая: нужно создать объект GModule не для динамически загружаемого модуля, а для самой программы. Для чего в метод g_module_open(const gchar *file_name, GModuleFlags flags) вместо имени файла нужно передать NULL:
file_name — the name of the file containing the module, or NULL to obtain a GModule representing the main program itself.Пример на Vala на основе идей из GtkBuilder (механизм получения типа по имени класса иллюстрирует функция type_from_name_lazy):
public abstract class Animal : Object
{
public abstract string to_string();
}
public class Cow : Animal
{
public override string to_string()
{
return "I'm a cow!";
}
}
public class Dog : Animal
{
public override string to_string()
{
return "I'm a dog!";
}
}
int main()
{
Animal a;
Type type;
a = new Dog(); //< Явно создаем Dog, имя типа зарегистрировано в системе типов.
print("1) %s\n", a.to_string());
if((type = Type.from_name("Dog")) != Type.INVALID)
{
a = Object.new(type) as Animal;
print("2) %s\n", a.to_string());
}
else
print("2) Failed to get type!\n");
if((type = Type.from_name("Cow")) != Type.INVALID)
{
a = Object.new(type) as Animal;
print("3) %s\n", a.to_string());
}
else
{
print("3) Failed to get type! Trying type_from_name_lazy...\n");
if((type = type_from_name_lazy("Cow")) != Type.INVALID)
{
a = Object.new(type) as Animal;
print("3) %s\n", a.to_string());
}
else
print("3) Failed to get type!\n");
}
return 0;
}
[CCode (has_target = false)]
delegate Type TypeGetFunc();
Type type_from_name_lazy(string name)
{
void *func = null;
if(Module.open(null, 0).symbol(ascii_camel_to_snake(name) + "_get_type", out func))
return ((TypeGetFunc)func)();
else
return Type.INVALID;
}
string ascii_camel_to_snake(string input)
{
var sb = new StringBuilder();
for(int i = 0; input[i] != '\0'; i++)
{
if(
( input[i].isupper() && i > 0 && !input[i - 1].isupper() ) ||
( (i > 2 && input[i].isupper()) && input[i - 1].isupper() && input[i - 2].isupper() )
)
sb.append_c('_');
sb.append_c(input[i].tolower());
}
return sb.str;
}
Вывод программы: 1) I'm a dog!И немного про Windows
2) I'm a dog!
3) Failed to get type! Trying type_from_name_lazy...
3) I'm a cow!
Лично у меня данный пример как есть в Windows не заработал (собирал компилятором mingw). Не удавалось найти указатель на функцию cow_get_type. Опытным путем выяснилось, что работает такой механизм при соблюдении двух условий:
- Объект должен быть реализован в отдельной dll;
- До попытки поиска указателя должна быть вызвана хотя бы одна функция из этой dll.
Подписаться на:
Комментарии (Atom)