Russian Qt Forum
Ноябрь 24, 2024, 15:38 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: qsahredmemory проблема (разные указатели на data)  (Прочитано 7451 раз)
stima
Гость
« : Апрель 03, 2012, 11:55 »

Я хочу написать, что-то наподобии моста (мостом будет bridg.dll). Мой код:
Код:
@
/*************
bridg.dll
************/
//sharedobject.h

#ifndef SHAREDOBJECT
#define SHAREDOBJECT

class ISharedObject {
public:
 virtual void set(int data) = 0;
 virtual int get() const = 0;
 virtual ~ISharedObject() {}
};

class SharedObject : public ISharedObject {

public:
 SharedObject() : data(-1) {}

 void set(int data) { this->data = data; }
 int get() const { return data; }

private:
 int data;
};

#endif //SHAREDOBJECT

//main

#include <QSharedMemory>
#include "sharedobject.h"
#include "SLogger.h"

static QSharedMemory* sharedMemory = NULL;

const char* slogger::fileName = "bridg.log";

extern "C" __declspec(dllexport) bool createSharedMemory(const char* key)
{
 DEBUG() << "Key is: " << key;
 sharedMemory = new QSharedMemory(key);

 if ( !sharedMemory->create(sizeof(SharedObject)) ) return false;

 SharedObject *obj = new SharedObject();
 SharedObject *sharedObj = (SharedObject*) sharedMemory->data();
 DEBUG() << "Shared instance pointer: " << std::hex << obj;
 DEBUG() << "Data pointer: " << std::hex << sharedObj;

 memcpy(sharedObj, obj, sizeof(SharedObject));

 return true; //все нормально!
}

extern "C" __declspec(dllexport) bool destroySharedMemory()
{
 if ( sharedMemory->detach() )
 {
  delete sharedMemory;
  return true;
 }

 return false;
}

extern "C" __declspec(dllexport) ISharedObject* getSharedObject(const char* key)
{
 DEBUG() << "Key is: " << key; //key is valid

 QSharedMemory sm(key);

 if ( !sm.attach() ) return NULL; //attach is ok

 ISharedObject *obj = (ISharedObject*)sm.data(); //<--- локальная sharedmemory возвращает невалидный(другой!!, но не NULL) поинтер
 //ISharedObject *obj = (ISharedObject*)sharedMemory->data(); //<--- с глобальным все ок!
 DEBUG() << "Shared instance " << std::hex << obj;

 return obj;
}

/*************
wincons.exe //my test
*************/
#include <windows.h>
#include <iostream>

class ISharedObject {
public:
 virtual void set(int data) = 0;
 virtual int get() const = 0;
 virtual ~ISharedObject() {}
};

typedef bool (*FCreate)(const char*);
typedef bool (*FDestroy)();
typedef ISharedObject* (*FGet)(const char*);

static const char* key = "test";

int main()
{
 HINSTANCE dll =  LoadLibrary(L"bridg.dll");

 if ( dll )
 {
  FCreate  _create  = (FCreate)GetProcAddress(dll, "createSharedMemory");
  FDestroy _destroy = (FDestroy)GetProcAddress(dll, "destroySharedMemory");
  FGet     _get     = (FGet) GetProcAddress(dll, "getSharedObject");

  if ( _create )
  {
   bool ret =  _create(key);

   if ( ret )
   {
    ISharedObject* obj = _get(key);

    if ( obj ) // <---не валиден (!!но не NULL)
    {
     //obj->set(42);
     //std::cout << "Data: " << obj->get() << std::endl;
    } else std::cout << "Can not get shared instance." << std::endl;
   }
   else std::cout << "Can not get create shared memory. Error: " << GetLastError() << std::endl;
  }
  else std::cout << "Can not get create function pointer. Error: " << GetLastError() << std::endl;

  FreeLibrary(dll);
 }
 else std::cout << "Can not load library. Error: " << GetLastError() << std::endl;

 std::getchar();
 return 0;
}

Что я делаю не так?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Апрель 03, 2012, 12:31 »

Код:
 ISharedObject *obj = (ISharedObject*)sm.data(); //<--- локальная sharedmemory возвращает невалидный(другой!!, но не NULL) поинтер
 //ISharedObject *obj = (ISharedObject*)sharedMemory->data(); //<--- с глобальным все ок!
Почему если "другой" так сразу "невалидный"? Вам обещали доступ к одному и тому же содержимому, а не один и тот же адрес. И второе: за то что лезете у данным без lock/unlock можно очень хорошо получить по рогам
Записан
stima
Гость
« Ответ #2 : Апрель 03, 2012, 12:41 »

lock и unlock это ясно, просто это тестовый пример. Но дело в том, что когда я вызываю метод set(42) идет краш (т.е как я понял указатель не тот).
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Апрель 03, 2012, 13:04 »

lock и unlock это ясно, просто это тестовый пример. Но дело в том, что когда я вызываю метод set(42) идет краш (т.е как я понял указатель не тот).
А тут наблюдается "ляпсус манус". Создали локальный QSharedMemory, замапились, вернули адрес. Конечно деструктор его размапит, он и будет невалидный когда выйдет из getSharedObject
Записан
stima
Гость
« Ответ #4 : Апрель 03, 2012, 13:32 »

Кхм.. вообщето я хотел чтобы этот локальный QSharedMemory обьект, просто получал адресс указателя. Это понятно что в деструкторе у него детач. Но как тогда сделать, чтобы например 2 приложения получали по одинаковому ключу один поинтер?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Апрель 03, 2012, 14:37 »

Кхм.. вообщето я хотел чтобы этот локальный QSharedMemory обьект, просто получал адресс указателя. Это понятно что в деструкторе у него детач. Но как тогда сделать, чтобы например 2 приложения получали по одинаковому ключу один поинтер?
"2 приложения" имеют 2 разных адресных пр-ва и передавать pointer нет смысла. Если же 2 модудя (dll), то делайте один (глобальный) QSharedMemory и замапленный адрес уже раздавайте кому надо. А так Вы как бы "начинаете еще одну сессию маппинга" (уже с новым адресом).
Записан
stima
Гость
« Ответ #6 : Апрель 03, 2012, 15:06 »

Про адресные права понял. А как сделать QSharedMemory глобально?) Очнь прошу маленький примерчик.

п.с. вообще хочу реализовать связь winapi dll с qt приложением. Хотел через промежуточную dll к которой прилинкован qtcore (чтобы отделить qt и winapi). Вообще буду ооочень признателен за пример, ибо qt пример убог.
п.с.с. Заранее, сокеты не подходят.
п.с.с.с. Вообще обычная строка прокидываеться, но возможно ли прокинуть обьект?
« Последнее редактирование: Апрель 03, 2012, 15:13 от stima » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Апрель 03, 2012, 15:46 »

Схемка такая (псевдокод)
Код
C++ (Qt)
// пользователь (WinAPI приложение)
typedef void * TSHandle;
struct CSharedUser {
public
TSHandle Create( const char * key, size_t size, int access );
void Destroy( void );
void * Acquire( void );
void  Release( void );
 
// data
TSHandle mData;
};
 
// хост (Qt приложение) экспортирует
TSHandle TS_Create( const char * key, size_t size, int access )
{
 QSharedMemory * sm = new QSharedMemory(key);
// здесь create, attach
return sm;
}
 
void TS_Destroy( TSHandle h )
{
delete (QSharedMemory *) h;
}
 
void * TS_Acquire( TSHandle h )
{
QSharedMemory * sm = (QSharedMemory *) h;
void * data = sm->data();
sm->lock();
return data;
}
 
void  TS_Release( TSHandle h  )
{
((QSharedMemory *) h)->unlock();
}
 
Пользователь получает через acquire, читает/пишет, потом обязан сделать release

но возможно ли прокинуть обьект?
В общем случае нет, нужен код объекта на обеих сторонах. Но Вы можете слить его (сериализовать) в shared память и прочитать на приемной стороне. Здесь правда понадобятся семафоры (чтобы узнать когда объект готов)
Записан
stima
Гость
« Ответ #8 : Апрель 03, 2012, 16:28 »

Если чесно я не совсем понял чем Ваш пример отличаеться от моего), можно пожалуйста поподробней.

п.с. Возможно я лезу в дебри, и есть какой-то другой вариант? Но не сокеты!
« Последнее редактирование: Апрель 03, 2012, 16:29 от stima » Записан
V1KT0P
Гость
« Ответ #9 : Апрель 03, 2012, 16:36 »

Если чесно я не совсем понял чем Ваш пример отличаеться от моего), можно пожалуйста поподробней.

п.с. Возможно я лезу в дебри, и есть какой-то другой вариант? Но не сокеты!
Есть еще pipe. Но это типа сокетов.

добавлено:
Вот почитай про возможные способы: http://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D0%B6%D0%BF%D1%80%D0%BE%D1%86%D0%B5%D1%81%D1%81%D0%BD%D0%BE%D0%B5_%D0%B2%D0%B7%D0%B0%D0%B8%D0%BC%D0%BE%D0%B4%D0%B5%D0%B9%D1%81%D1%82%D0%B2%D0%B8%D0%B5
« Последнее редактирование: Апрель 03, 2012, 16:40 от V1KT0P » Записан
stima
Гость
« Ответ #10 : Апрель 03, 2012, 16:52 »

2Igors
Вообще вот это строчка: "Но Вы можете слить его (сериализовать) в shared память и прочитать на приемной стороне" особенно не понятна.
Записан
V1KT0P
Гость
« Ответ #11 : Апрель 03, 2012, 16:57 »

2Igors
Вообще вот это строчка: "Но Вы можете слить его (сериализовать) в shared память и прочитать на приемной стороне" особенно не понятна.
Это значит что объект будет записан в виде массива байт, а на другой стороне его из этого массива надо будет восстановить.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Апрель 03, 2012, 17:02 »

Если чесно я не совсем понял чем Ваш пример отличаеться от моего), можно пожалуйста поподробней.
Отличается только тем что Вы хотите передавать указатель на сами данные, а лучше передавать указатель на QSharedMemory (или класс его) и пусть он указатель на данные (уже залоченные) возвращает.

Конечно это работает только в 1 адресном пр-ве (host + dll(s)), для обмена между 2 приложениями передается ключ (или устанавливаются соглашения какой ключ)

2Igors
Вообще вот это строчка: "Но Вы можете слить его (сериализовать) в shared память и прочитать на приемной стороне" особенно не понятна.
Напр на Qt стороне Вы передаете QVector. Записали его в shared. На приемной прочитали, создали здесь уже std::vector. Конечно нужны какие-то соглашения по формату данных - как и при любом обмене

п.с. Возможно я лезу в дебри, и есть какой-то другой вариант? Но не сокеты!
Вариант для чего? Вы упомянули о какой-то (интимной) связи winapi/qt, но что та связь должна делать - хз Улыбающийся.  Поэтому мне лучше от рекомендаций воздержаться
Записан
stima
Гость
« Ответ #13 : Апрель 03, 2012, 17:19 »

2Igors Спасибо дошло!!!
Записан
stima
Гость
« Ответ #14 : Апрель 03, 2012, 18:49 »

Еще один вопрос. Можно реализовать что-то наподобии этого?)
Код:

class Manager {
    typedef void (*FFoo)();

public:
   FFoo foo;

   bool initialize()
   {
        dll_instance = LoadLibrary("some.dll");
        
        if ( !dll_instance ) return false;
        foo = (FFoo)GetProccessAdress(dll_instance, "foo");
        
        if ( !foo ) return false;

        return true;
   }

  ~Manager()
   {
      FreeLibrary(dll_instance);
   }

private:
    HMODULE dll_instance;
};

Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.075 секунд. Запросов: 23.