Извините, ничего не найдено.

Не расстраивайся! Лучше выпей чайку!
Регистрация
Справка
Календарь

Вернуться   forum.boolean.name > Программирование игр для компьютеров > C++

Ответ
 
Опции темы
Старый 16.05.2013, 05:09   #1
DarkMedveD
ПроЭктировщик
 
Аватар для DarkMedveD
 
Регистрация: 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
HolyDel
 
Регистрация: 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 за это полезное сообщение:
DarkMedveD (17.05.2013), St_AnGer (17.05.2013)
Старый 16.05.2013, 17:58   #3
DarkMedveD
ПроЭктировщик
 
Аватар для DarkMedveD
 
Регистрация: 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
HolyDel
 
Регистрация: 26.09.2006
Сообщений: 6,035
Написано 1,474 полезных сообщений
(для 2,707 пользователей)
Ответ: Передача указателя на интерфейс через DLL

пока не понятно. такто код рабочий.

проверь на функции.
создай функцию тупо возвращающую инт и посмотри как она будет линковаться.
(Offline)
 
Ответить с цитированием
Старый 16.05.2013, 20:59   #5
DarkMedveD
ПроЭктировщик
 
Аватар для DarkMedveD
 
Регистрация: 26.12.2008
Адрес: Питер
Сообщений: 151
Написано 5 полезных сообщений
(для 6 пользователей)
Ответ: Передача указателя на интерфейс через DLL

Как проверить линкование функции?
По-моему дело в интерфейсах. С ними косяки, остальные функции нормально работали и раньше.
__________________
Фантазия плохого программиста ограничивается его знанием языка. Фантазия хорошего программиста ограничивается возможностями языка и компилятором. Фантазия гениального программиста не ограничивается ничем.
(Offline)
 
Ответить с цитированием
Старый 16.05.2013, 21:37   #6
HolyDel
 
Регистрация: 26.09.2006
Сообщений: 6,035
Написано 1,474 полезных сообщений
(для 2,707 пользователей)
Ответ: Передача указателя на интерфейс через DLL

хм. странно. как они работали без dllimport-а.

покажи как используешь.
(Offline)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
DarkMedveD (17.05.2013)
Старый 16.05.2013, 21:49   #7
DarkMedveD
ПроЭктировщик
 
Аватар для DarkMedveD
 
Регистрация: 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
impersonalis
Зануда с интернетом
 
Аватар для impersonalis
 
Регистрация: 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)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
DarkMedveD (17.05.2013)
Старый 17.05.2013, 01:34   #9
HolyDel
 
Регистрация: 26.09.2006
Сообщений: 6,035
Написано 1,474 полезных сообщений
(для 2,707 пользователей)
Ответ: Передача указателя на интерфейс через DLL

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

один компилятор - совместимая компоновка и одинаковое декорирование.

поставь точку останова в начало loadShader, посмотри доходит ли твоя программа до туда.
(Offline)
 
Ответить с цитированием
Эти 2 пользователя(ей) сказали Спасибо HolyDel за это полезное сообщение:
DarkMedveD (17.05.2013), impersonalis (17.05.2013)
Старый 17.05.2013, 02:30   #10
DarkMedveD
ПроЭктировщик
 
Аватар для DarkMedveD
 
Регистрация: 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
HolyDel
 
Регистрация: 26.09.2006
Сообщений: 6,035
Написано 1,474 полезных сообщений
(для 2,707 пользователей)
Ответ: Передача указателя на интерфейс через DLL

чйорт! что ты понимаешь под указателями на интерфейс? что значит "значения интерфейсов никак не меняются. "?


раз метод вызывается - значит с линковкой все в порядке. this нормальный.
может метод кривой?

и почему у тебя shader - типа твой Shader, а не дх-ский?
(Offline)
 
Ответить с цитированием
Старый 17.05.2013, 17:47   #12
Samodelkin
Мастер
 
Регистрация: 12.01.2009
Сообщений: 979
Написано 388 полезных сообщений
(для 631 пользователей)
Ответ: Передача указателя на интерфейс через DLL

Эй, DarkMedveD, твой главный косяк в отсутствии нормального конструктора класса Shader. Ты не зануляешь указатели, в частности errorBuffer. В итоге если функция D3DXCompileShaderFromFile завершается нормально, буфер по переданному ей указателю не создается. А после функции у тебя сразу стоит if ( errorBuffer ), который сработает если у тебя в errorBuffer будет мусор, и далее вызовется Release несуществующего буфера.

Я думаю в твоем проекте уместно разделить реализацию и интерфейс. Например сделать абстрактный класс и от него наследовать класс реализацию. В абстрактном классе сделать только методы ( чисто виртуальные ). А в реализацию уже добавить все данные-члены. Добавить функцию которая будет создавать объект типа Реализация, но возвращать указатель на класс типа Интерфейс. Так как в этом случае будет использоваться RTTI то указывать dllexport вообще не понадобиться.
Ну или найти другие паттерны которые делают интерфейс и реализацию раздельно. У тебя сейчас очень плохо - класс вообще не защищен, и пользователь может его испортить как угодно.
(Offline)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
HolyDel (17.05.2013)
Старый 17.05.2013, 21:04   #13
HolyDel
 
Регистрация: 26.09.2006
Сообщений: 6,035
Написано 1,474 полезных сообщений
(для 2,707 пользователей)
Ответ: Передача указателя на интерфейс через DLL

Я думаю в твоем проекте уместно разделить реализацию и интерфейс.
я в своем движке так делал. очень удобно.

+ можно будет не подулючть дх к результирующему проекту (не надо будет ставить дхсдк)
(Offline)
 
Ответить с цитированием
Старый 18.05.2013, 00:40   #14
Samodelkin
Мастер
 
Регистрация: 12.01.2009
Сообщений: 979
Написано 388 полезных сообщений
(для 631 пользователей)
Ответ: Передача указателя на интерфейс через DLL

я в своем движке так делал. очень удобно.
Да в моем движке тоже так сделано, но есть недостаток всетаки один - интерфейс должен быть хорошо продуман с самого начала, что бывает очень редко. Я вот смотрел паттерны и мне понравился паттерн типа мост - можно наследовать интерфейсы и реализации отдельно друг от друга, и каждый развивать по своему, еще можно несколько интерфейсов цеплять на одну реализацию. Я уже сделал несколько объектов таким образом: например существует реализация камеры, и для нее есть три интерфейса - один сделан для управления камерой в играх от третьего лица, второй для управления свободной камерой и первого лица, третий - для стратегий. У каждого интерфейса свои уникальные наборы методов, общие методы можно объеденить в абстрактный класс интерфейса. Вобщем один и тот же объект-реализация может нацеплять на себя разные интерфейсы в зависимости от контекста в котором он используется, объект при этом не нужно удалять/пересоздавать - интерфейсы меняются прямо в рантайме.

Так как в этом случае будет использоваться RTTI...
Тут я имел ввиду что функция будет вызываться не напрямую, а через vtable и например реализация msvs вызывает методы из dll даже если они не экспортируемые.
(Offline)
 
Ответить с цитированием
Старый 18.05.2013, 16:07   #15
DarkMedveD
ПроЭктировщик
 
Аватар для DarkMedveD
 
Регистрация: 26.12.2008
Адрес: Питер
Сообщений: 151
Написано 5 полезных сообщений
(для 6 пользователей)
Ответ: Передача указателя на интерфейс через DLL

У меня, парни, так и сделано.

Когда создается объект класса Shader все его переменные обнуляются, с чего вы взяли, что у меня нет конструктора? Так же есть и класс, от которого все наследуется, только он никак не относится к шейдерам. От него я наследую все объекты сцены.

А виртуальные методы, свои интерфейсы и все те вкусные штуки, о которых вы говорили - пока слишком сложно для меня.

Спасибо за советы, я постараюсь прислушаться. Если соображалки хватит.
__________________
Фантазия плохого программиста ограничивается его знанием языка. Фантазия хорошего программиста ограничивается возможностями языка и компилятором. Фантазия гениального программиста не ограничивается ничем.
(Offline)
 
Ответить с цитированием
Ответ


Опции темы

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


Часовой пояс GMT +4, время: 09:08.


vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot
Style crйe par Allan - vBulletin-Ressources.com