|
16.05.2013, 05:09
|
#1
|
ПроЭктировщик
Регистрация: 26.12.2008
Адрес: Питер
Сообщений: 151
Написано 5 полезных сообщений (для 6 пользователей)
|
Передача указателя на интерфейс через DLL
Есть класс, в котором есть некоторые методы и члены-интерфейсы, с которыми надо работать. Сами классы находятся в заголовочном файле, их реализация в исходнике. Все это собрано в библиотеку и подключено к другому проекту. Во время работы с проектом любое использование интерфейса из подключенной библиотеки приводит к ошибке доступа к памяти.
Может указатели на интерфейсы надо тоже как-то передавать по-особенному, как методы, например?
class Shader
{
public:
ID3DXBuffer* shader;
ID3DXBuffer* errorBuffer;
IDirect3DVertexShader9* DiffuseShader;
ID3DXConstantTable* DiffuseConstTable;
D3DXMATRIX View;
D3DXMATRIX Proj;
__declspec(dllexport) HRESULT loadShader(LPCSTR,LPCSTR,LPCSTR);
};
Причем ошибка вылетает при использовании метода, который, казалось бы, к члену своего класса обращается.
Заранее огромное спасибо за помощь.
__________________
Фантазия плохого программиста ограничивается его знанием языка. Фантазия хорошего программиста ограничивается возможностями языка и компилятором. Фантазия гениального программиста не ограничивается ничем.
|
(Offline)
|
|
16.05.2013, 12:40
|
#2
|
☭
Регистрация: 26.09.2006
Сообщений: 6,035
Написано 1,474 полезных сообщений (для 2,707 пользователей)
|
Ответ: Передача указателя на интерфейс через DLL
для клиентского кода должно быть __declspec(dllimport).
определи дефайн для проекта своей библиотеки. например MY_SUPERLIB.
определи макрос типа:
#ifdef MY_SUPERLIB
#define SUPERLIB_API __declspec(dllexport)
#else
#define SUPERLIB_API __declspec(dllimport)
#endif
замени __declspec(dllexport) на SUPERLIB_API
SUPERLIB_API HRESULT loadShader(LPCSTR,LPCSTR,LPCSTR);
таким образом при компиляции либки у тебя там будет экспорт а при компиляции приложения, используещего либку - импорт.
Последний раз редактировалось HolyDel, 16.05.2013 в 14:39.
|
(Offline)
|
|
Эти 2 пользователя(ей) сказали Спасибо HolyDel за это полезное сообщение:
|
|
16.05.2013, 17:58
|
#3
|
ПроЭктировщик
Регистрация: 26.12.2008
Адрес: Питер
Сообщений: 151
Написано 5 полезных сообщений (для 6 пользователей)
|
Ответ: Передача указателя на интерфейс через DLL
К сожалению, безрезультатно.
Абсолютно никакой реакции на данные манипуляции не возникло.
Только предупреждение выдает:
несовместимая компоновка dll
Может я что-то сделал не так?
В заголовок библиотеки добавил
#ifdef MY_SUPERLIB
#define SUPERLIB_API __declspec(dllexport)
#else
#define SUPERLIB_API __declspec(dllimport)
#endif
В классах спецификаторы заменил на SUPERLIB_API.
И все, никаких изменений в основном проекте я не производил.
UPD:
Добавил #define MY_SUPERLIB к проекту - никакой реакции.
__________________
Фантазия плохого программиста ограничивается его знанием языка. Фантазия хорошего программиста ограничивается возможностями языка и компилятором. Фантазия гениального программиста не ограничивается ничем.
|
(Offline)
|
|
16.05.2013, 19:16
|
#4
|
☭
Регистрация: 26.09.2006
Сообщений: 6,035
Написано 1,474 полезных сообщений (для 2,707 пользователей)
|
Ответ: Передача указателя на интерфейс через DLL
пока не понятно. такто код рабочий.
проверь на функции.
создай функцию тупо возвращающую инт и посмотри как она будет линковаться.
|
(Offline)
|
|
16.05.2013, 20:59
|
#5
|
ПроЭктировщик
Регистрация: 26.12.2008
Адрес: Питер
Сообщений: 151
Написано 5 полезных сообщений (для 6 пользователей)
|
Ответ: Передача указателя на интерфейс через DLL
Как проверить линкование функции?
По-моему дело в интерфейсах. С ними косяки, остальные функции нормально работали и раньше.
__________________
Фантазия плохого программиста ограничивается его знанием языка. Фантазия хорошего программиста ограничивается возможностями языка и компилятором. Фантазия гениального программиста не ограничивается ничем.
|
(Offline)
|
|
16.05.2013, 21:37
|
#6
|
☭
Регистрация: 26.09.2006
Сообщений: 6,035
Написано 1,474 полезных сообщений (для 2,707 пользователей)
|
Ответ: Передача указателя на интерфейс через DLL
хм. странно. как они работали без dllimport-а.
покажи как используешь.
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
16.05.2013, 21:49
|
#7
|
ПроЭктировщик
Регистрация: 26.12.2008
Адрес: Питер
Сообщений: 151
Написано 5 полезных сообщений (для 6 пользователей)
|
Ответ: Передача указателя на интерфейс через DLL
Проект библиотеки:
Файл заголовка:
class Shader
{
public:
ID3DXBuffer* shader;
ID3DXBuffer* errorBuffer;
IDirect3DVertexShader9* DiffuseShader;
ID3DXConstantTable* DiffuseConstTable;
D3DXMATRIX View;
D3DXMATRIX Proj;
SUPERLIB_API Shader();
SUPERLIB_API HRESULT loadShader(LPCSTR,LPCSTR,LPCSTR);
SUPERLIB_API void UpdateShader(D3DXMATRIX, D3DXMATRIX);
SUPERLIB_API void SetVector(LPCSTR, D3DXVECTOR4);
SUPERLIB_API void SetMatrix(LPCSTR, D3DXMATRIX);
SUPERLIB_API void SetFloat(LPCSTR, FLOAT);
SUPERLIB_API void SetInt(LPCSTR, INT);
};
Файл исходного кода:
HRESULT Shader::loadShader(LPCSTR sourse, LPCSTR point, LPCSTR version)
{
HRESULT hr=0;
hr = D3DXCompileShaderFromFile(
sourse,
0,
0,
point, // имя точки входа
version,
D3DXSHADER_AVOID_FLOW_CONTROL,
&shader,
&errorBuffer,
&DiffuseConstTable);
if(errorBuffer)
{
::MessageBox(0, (char*)errorBuffer->GetBufferPointer(), 0, 0);
Release<ID3DXBuffer*>(errorBuffer);
}
if(FAILED(hr))
{
::MessageBox(0, "Ошибка компиляции шейдера", 0, 0);
return false;
}
if(Device)
Device->CreateVertexShader((DWORD*)shader->GetBufferPointer(), &DiffuseShader);
if(FAILED(hr))
{
::MessageBox(0, "CreateVertexShader - FAILED", 0, 0);
return false;
}
Release<ID3DXBuffer*>(shader);
DiffuseConstTable->SetDefaults(Device);
return true;
}
После подключения библиотеки, в проекте пишу:
diffuse.loadShader("VertexShader.hlsl", "main","vs_1_1");
Результата, разумеется, нет.
Кстати, во время ошибки вылазит некоторая служебная информация от студии. Там указаны значения каждого из объектов. Что странно - вроде в объекте шейдера все в порядке, а вот объект Device всегда содержит 0x00000000.
__________________
Фантазия плохого программиста ограничивается его знанием языка. Фантазия хорошего программиста ограничивается возможностями языка и компилятором. Фантазия гениального программиста не ограничивается ничем.
Последний раз редактировалось DarkMedveD, 17.05.2013 в 00:06.
|
(Offline)
|
|
17.05.2013, 01:23
|
#8
|
Зануда с интернетом
Регистрация: 04.09.2005
Сообщений: 14,014
Написано 6,798 полезных сообщений (для 20,935 пользователей)
|
Ответ: Передача указателя на интерфейс через DLL
Хочется спать, потому же нет состояния разобраться в коде, но смазанные воспоминания и обронённое упоминание компоновки поднимает следующее (если ничего не даст - не серчать):
Соглашение вызова ("Во время работы с проектом любое использование интерфейса из подключенной библиотеки приводит к ошибке доступа к памяти.")?
например
HRESULT SUPERLIB_API __cdecl loadShader(LPCSTR,LPCSTR,LPCSTR);
coff omf ("несовместимая компоновка ")?
декорирование?
__________________
http://nabatchikov.com
Мир нужно делать лучше и чище. Иначе, зачем мы живем? tormoz
А я растила сына на преданьях
о принцах, троллях, потайных свиданьях,
погонях, похищениях невест.
Да кто же знал, что сказка душу съест?
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
17.05.2013, 01:34
|
#9
|
☭
Регистрация: 26.09.2006
Сообщений: 6,035
Написано 1,474 полезных сообщений (для 2,707 пользователей)
|
Ответ: Передача указателя на интерфейс через DLL
один хидер - соглашение вызова одинаковое, + автор говорил что на обычных функциях это работает. хотя глянуть настройки компилятора в проекте таки можно.
один компилятор - совместимая компоновка и одинаковое декорирование.
поставь точку останова в начало loadShader, посмотри доходит ли твоя программа до туда.
|
(Offline)
|
|
Эти 2 пользователя(ей) сказали Спасибо HolyDel за это полезное сообщение:
|
|
17.05.2013, 02:30
|
#10
|
ПроЭктировщик
Регистрация: 26.12.2008
Адрес: Питер
Сообщений: 151
Написано 5 полезных сообщений (для 6 пользователей)
|
Ответ: Передача указателя на интерфейс через DLL
Да, доходит до начала загрузки шейдера.
Потом, после загрузки его из файла, значения интерфейсов никак не меняются.
Попробовал создавать указатель на интерфейс прямо в программе - работает.
Попробовал в тестирующем приложении обратиться к указателю на интерфейс Device, который содержится в заголовке, - не разрешает.
UPD: Господа, все прекрасно работает с некоторыми исправлениями. HolyDel, я преклоняюсь перед твоим опытом, но боюсь, что для корректной работы приложения нужно было написать в заголовке следующее:
#ifdef MY_SUPERLIB
#define SUPERLIB_API __declspec(dllimport)
#else
#define SUPERLIB_API __declspec(dllexport)
#endif
(Если есть define, то импорт, ибо в проекте-то я создаю эту константу)
А так же просто добавить спецификатор SUPERLIB_API к главному интерфейсу приложения. Как оказалось - это то, что было нужно.
Спасибо огромное за помощь. Что бы я без вас делал.
__________________
Фантазия плохого программиста ограничивается его знанием языка. Фантазия хорошего программиста ограничивается возможностями языка и компилятором. Фантазия гениального программиста не ограничивается ничем.
Последний раз редактировалось DarkMedveD, 17.05.2013 в 03:36.
|
(Offline)
|
|
17.05.2013, 03:24
|
#11
|
☭
Регистрация: 26.09.2006
Сообщений: 6,035
Написано 1,474 полезных сообщений (для 2,707 пользователей)
|
Ответ: Передача указателя на интерфейс через DLL
чйорт! что ты понимаешь под указателями на интерфейс? что значит "значения интерфейсов никак не меняются. "?
раз метод вызывается - значит с линковкой все в порядке. this нормальный.
может метод кривой?
и почему у тебя shader - типа твой Shader, а не дх-ский?
|
(Offline)
|
|
17.05.2013, 17:47
|
#12
|
Мастер
Регистрация: 12.01.2009
Сообщений: 979
Написано 388 полезных сообщений (для 631 пользователей)
|
Ответ: Передача указателя на интерфейс через DLL
Эй, DarkMedveD, твой главный косяк в отсутствии нормального конструктора класса Shader. Ты не зануляешь указатели, в частности errorBuffer. В итоге если функция D3DXCompileShaderFromFile завершается нормально, буфер по переданному ей указателю не создается. А после функции у тебя сразу стоит if ( errorBuffer ), который сработает если у тебя в errorBuffer будет мусор, и далее вызовется Release несуществующего буфера.
Я думаю в твоем проекте уместно разделить реализацию и интерфейс. Например сделать абстрактный класс и от него наследовать класс реализацию. В абстрактном классе сделать только методы ( чисто виртуальные ). А в реализацию уже добавить все данные-члены. Добавить функцию которая будет создавать объект типа Реализация, но возвращать указатель на класс типа Интерфейс. Так как в этом случае будет использоваться RTTI то указывать dllexport вообще не понадобиться.
Ну или найти другие паттерны которые делают интерфейс и реализацию раздельно. У тебя сейчас очень плохо - класс вообще не защищен, и пользователь может его испортить как угодно.
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
17.05.2013, 21:04
|
#13
|
☭
Регистрация: 26.09.2006
Сообщений: 6,035
Написано 1,474 полезных сообщений (для 2,707 пользователей)
|
Ответ: Передача указателя на интерфейс через DLL
Я думаю в твоем проекте уместно разделить реализацию и интерфейс.
я в своем движке так делал. очень удобно.
+ можно будет не подулючть дх к результирующему проекту (не надо будет ставить дхсдк)
|
(Offline)
|
|
18.05.2013, 00:40
|
#14
|
Мастер
Регистрация: 12.01.2009
Сообщений: 979
Написано 388 полезных сообщений (для 631 пользователей)
|
Ответ: Передача указателя на интерфейс через DLL
я в своем движке так делал. очень удобно.
|
Да в моем движке тоже так сделано, но есть недостаток всетаки один - интерфейс должен быть хорошо продуман с самого начала, что бывает очень редко. Я вот смотрел паттерны и мне понравился паттерн типа мост - можно наследовать интерфейсы и реализации отдельно друг от друга, и каждый развивать по своему, еще можно несколько интерфейсов цеплять на одну реализацию. Я уже сделал несколько объектов таким образом: например существует реализация камеры, и для нее есть три интерфейса - один сделан для управления камерой в играх от третьего лица, второй для управления свободной камерой и первого лица, третий - для стратегий. У каждого интерфейса свои уникальные наборы методов, общие методы можно объеденить в абстрактный класс интерфейса. Вобщем один и тот же объект-реализация может нацеплять на себя разные интерфейсы в зависимости от контекста в котором он используется, объект при этом не нужно удалять/пересоздавать - интерфейсы меняются прямо в рантайме.
Так как в этом случае будет использоваться RTTI...
|
Тут я имел ввиду что функция будет вызываться не напрямую, а через vtable и например реализация msvs вызывает методы из dll даже если они не экспортируемые.
|
(Offline)
|
|
18.05.2013, 16:07
|
#15
|
ПроЭктировщик
Регистрация: 26.12.2008
Адрес: Питер
Сообщений: 151
Написано 5 полезных сообщений (для 6 пользователей)
|
Ответ: Передача указателя на интерфейс через DLL
У меня, парни, так и сделано.
Когда создается объект класса Shader все его переменные обнуляются, с чего вы взяли, что у меня нет конструктора? Так же есть и класс, от которого все наследуется, только он никак не относится к шейдерам. От него я наследую все объекты сцены.
А виртуальные методы, свои интерфейсы и все те вкусные штуки, о которых вы говорили - пока слишком сложно для меня.
Спасибо за советы, я постараюсь прислушаться. Если соображалки хватит.
__________________
Фантазия плохого программиста ограничивается его знанием языка. Фантазия хорошего программиста ограничивается возможностями языка и компилятором. Фантазия гениального программиста не ограничивается ничем.
|
(Offline)
|
|
Ваши права в разделе
|
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 09:08.
|