LINUX.ORG.RU

Как правильно писать dll


0

0

Здраствуйте.

Понимаю что вопрос примитивный, но нигде не могу найти внятного ответа.

Мне нужно написать dll в которой будет функция которая будет возвращать строку.

При вызове функции неизвестно каков размер этой строки.

Как это правильно все организовать?

anonymous

А в чём проблема? Напиши функцию сначала для екзешника, отладь её, чтобы работала так, как тебе нужно, потом следующее (я COM-объекты запихивал в дл-ку, ну по аналогии разберёшься):

(main.cpp)

typedef IUnknown*(*pCreateInstance)(void);//указатель на ф-ю в дл-ке

HINSTANCE hModule=LoadLibrary("./d.dll");

char mod[255];

GetModuleFileName((HMODULE)hModule,(LPTSTR)mod,255);//загружаешь дл-ку

pCreateInstance pCI=(pCreateInstance)GetProcAddress(hModule,"CreateInstance");//получа ешь указатель на ф-ю

IUnknown* pIU=pCI();//используешь его

BOOL b=FreeLibrary(hModule);//отстрел дл-ки, работа окончена

(dll.cpp)

extern "C" __declspec(dllexport) IUnknown* CreateInstance() {//это функция в дл-ке, на которую указатель был IUnknown* pI=static_cast<IX*>(new CA); pI->AddRef(); return pI; }

(Makefile)

REMOVE = rm -f

INDLL = dll

OUTDLL = d

INEXECUTE = workDll

OUTEXECUTE = a

$(OUTDLL) : $(INDLL).o

g++ -shared -o $(OUTDLL).dll $(INDLL).o -L"e:/MinGW/lib" -luuid

dlltool -l $(OUTDLL).a $(INDLL).o

$(INDLL).o : $(INDLL).cpp

g++ -c $(INDLL).cpp

$(OUTEXECUTE) : $(INEXECUTE).o

g++ -o $(OUTEXECUTE) $(INEXECUTE).o -L"e:/MinGW/lib" -luuid

$(INEXECUTE).o : $(INEXECUTE).cpp

g++ -c $(INEXECUTE).cpp

dll :

$(MAKE) $(OUTDLL)

exe :

$(MAKE) $(OUTEXECUTE)

clean :

$(REMOVE) $(OUTDLL).dll

$(REMOVE) $(INDLL).o

$(REMOVE) $(OUTDLL).a

$(REMOVE) $(INEXECUTE).o

$(REMOVE) $(OUTEXECUTE).exe

ALL : clean exe dll

Вот, подробнее некуда, разбирайся ;-)

anonymous
()
Ответ на: комментарий от anonymous

блин.

Не совсем корректно задал вопрос.

Функция будет возвращать строку неизвестной на момент вызова функции длинны.

Поэтому статический буфер не годится.

В функции (которая в dll) приходится делать malloc, а следовательно и free желательно сделать в ней же.

Сейчас нашел как вариант, сделать функцию в длл, которая подчищала бы всю память которую выделяли...

Как же это правильно организовать?

anonymous
()
Ответ на: комментарий от anonymous

В виндовой реализации разделяемых библиотек в функции DllMain есть возможность отслеживать присоединение и отсоединение этой дл-ки на адресные пространства процессов и потоков.

extern "C" BOOL APIENTRY DllMain(HINSTANCE hModule,DWORD fdwReason,LPVOID lpReserved)

{

switch(fdwReason)

{

case DLL_PROCESS_ATTACH:

std::cout<<"DllMain attached to process"<<std::endl;

break;

case DLL_PROCESS_DETACH:

std::cout<<"DllMain detached at process"<<std::endl;

break;

case DLL_THREAD_ATTACH:

std::cout<<"DllMain attached to thread"<<std::endl;

break;

case DLL_THREAD_DETACH:

std::cout<<"DllMain detached at thread"<<std::endl;

break;

}

return TRUE;

anonymous
()
Ответ на: комментарий от Zmacs

почему оффтопокодинга. изначальный вопрос был про dinamyc load library.

если бы я написал so было бы проще?

anonymous
()
Ответ на: комментарий от Zmacs

Врага нужно знать в лицо ;-), кроме того, что плохого, если умеешь кодить и под оффтоп, и под никсы?

anonymous
()
Ответ на: комментарий от anonymous

Да, не парься с зачисткой. Кто получает строку, тот пусть и удаляет её. Нормальный сишный подход.

yz
()
Ответ на: комментарий от anonymous

блин... вопрос не про винду а вообще про разделяемые библиотеки...

anonymous
()
Ответ на: комментарий от yz

>Кто получает строку, тот пусть и удаляет её. Нормальный сишный подход.

Читал что это фигово. Вроде кто выделил память, тот ее очистить должен...

А нормально ли очистится память из проги если она была выделена из библиотеки?

Ну там адресные пространства... (не силен я в этом) :(

anonymous
()

Советую посмотреть на PKCS11. Там сделано в таком духе:

|int get_string(char * str, int * len)
|{
| char s[] = "TEST";
| int l = strlen(s);
|
| if (!str) {
| *len = l + 1; // Возвращаем длинну
| return 0; // Ok
| }
| if (*len < l + 1)
| return -1; // Маленький буфер
| strcpy(str, s); // Копируем результат
| *len = l;
| return 0;
|}

Использование:
char * str = NULL;
int len;
ASSERT(get_string(NULL, &len) == 0);
str = malloc(len);
ASSERT(str);
ASSERT(get_string(str, &len) == 0);

Я привык, очень удобно. Сама библиотека никогда не выделяет/освобождает память, что дает большую гибкость.

rymis ★★
()
Ответ на: комментарий от anonymous

А как ты представляешь себе написание dll из питона? Это же интерпретируемый язык.

anonymous
()
Ответ на: комментарий от anonymous

Там все равно придется писать обертку на C. Для PKCS11 есть интерфейсы, по крайней мере, к Python, Java, C#, Perl, C++. Может и еще есть, но я о них не знаю, так что проблем нет.

rymis ★★
()
Ответ на: комментарий от rymis

Не, я не про обращение из питона к дл-ке, понятно, что в этом случае используются какие-то привязки, разговор ведь был про "изготовление" дл-ки средствами питона. Или я неправильно понял вопрос?

anonymous
()
Ответ на: комментарий от anonymous

не правиьно.

вопрос был как раз про использование библиотеки питоном

anonymous
()
Ответ на: комментарий от rymis

спасибо. буду смотреть исходники PKCS11

anonymous
()
Ответ на: комментарий от anonymous

> В функции (которая в dll) приходится делать malloc, а следовательно и free желательно сделать в ней же.

Если malloc/free находятся в dll (другой, совместо используемой и dll ит exe), то так делать можно.

k_andy ★★★
()

Как вариант - завести для строки структуру (заодно там и длину можно 
хранить) и хранить в ней указатель на функцию для уничтожения строки.
Соответственно уничтожать строку через этот указатель а инициализировать его при создании структуры. Тогда будет гарантированно вызываться нужная функция.
т.е. примерно такой код:

struct String {
  char* data;
  void (*free)(void*);
};

struct String str;
my_dll_function_get_str(&str);
fputs(str.data, stderr);
str.free(str.data);

Ну и можно на этой основе маленькую библиотечку для работы со строками сделать. Или поискать готовую.

anonymous
()
Ответ на: комментарий от anonymous

А потом сделать: h = dlopen(...); f = dlsym(h, "getstring"); s = s(...); dlclose(h); s->free(s);

Следить за таким очень сложно...

rymis ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.