Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 16, средняя оценка - 5.00
Said007
0 / 0 / 0
Регистрация: 02.09.2007
Сообщений: 209
#1

Помогите создать конструкцию как экспортируемую функцию shared DLL - C++

22.03.2009, 23:58. Просмотров 1980. Ответов 16
Метки нет (Все метки)

Я пишу на VB, но по некоторым причинам в VB невозможно реализовать необходимую мне конструкцию. И я прошу Вас помочь мне создать эту конструкцию средствами C++? Как экспортируемую функцию shared DLL.

Вот аналог на VB нужной мне функции:
Visual Basic
1
2
3
Public Sub toPrint(pDoc As Object, pArgs() As Variant)
    Call pDoc.Print(pArgs())
End Sub
В идеале я хотел бы получить файлы проекта C++, для создания такой DLL.
Обещаю ответить помощью на помощь.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
22.03.2009, 23:58
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Помогите создать конструкцию как экспортируемую функцию shared DLL (C++):

Building MFC application with /MD[d] (CRT dll version) requires MFC shared dll - C++
Здравствуйте. Подключил afx.h, появилась ошибка. Из-за чего? Что делать?

помогите создать загрузчик dll - C++
Пожалуйста кто чем сможет

Можно ли передать в функцию две переменных через 1 какую-нибудь конструкцию? - C++
Можно ли передать в функцию две переменных через 1 конструкцию чтобы вместо этого int a=5; int b=10; Func (a,b); ...

Перегрузка операций (Создать класс вещественных чисел (double); определить оператор +, как функцию-элемент и – как дружественную функцию) - C++
помогите решить пожалуйста Задание 2. Бинарная операция Создать класс вещественных чисел (double).. Определить оператор +, как...

литература shared objects & dynamic shared objects - C++
Привет, товариСЧи. Подкиньте пожалуйста пару тройку книженций по теме инглиш тоже пойдет, но лучше рус. Добавлено через 42 минуты ...

Как из DLL вызвать функцию, находящуюся в exe? - C++
Плз. скажите, как из DLL вызвать функцию, находящуюся в exe'шнике. Плз.! Плз.! Плз.!

16
Vita
Сообщений: n/a
23.03.2009, 09:34 #2
Объявление в VB:
Visual Basic
1
2
Private Declare Sub toPrint Lib 'moddll' Alias '_toPrint@8' _
            (pDoc As Object, pArgs() As Variant)
Объявление в VC++:
C++
1
2
3
4
extern 'C' __declspec(dllexport) void __stdcall toPrint(IDispatch* *ppDoc, SAFEARRAY* *pArgs)
{
...
}
Vita
Сообщений: n/a
23.03.2009, 09:37 #3
Вот вариант вызова как Call toPrint(Me,varr) ' для Dim varr(1) или больше
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
extern 'C' __declspec(dllexport) void __stdcall toPrint(IDispatch* *ppDoc, SAFEARRAY* *pArgs)
{
    IDispatch* pDoc = *ppDoc;
 
    DISPID dispid;
    LPOLESTR lpszEv = OLESTR('Caption');
    HRESULT hr = pDoc->GetIDsOfNames(IID_NULL, &lpszEv, 1, LOCALE_USER_DEFAULT, &dispid);
 
    VARIANT vResult;
    VariantInit(&vResult);
    DISPPARAMS dispparams = { NULL, NULL, 0, 0};
        
    hr = pDoc->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispparams, &vResult, NULL, NULL);
 
    dispparams.rgvarg = &vResult;
    vResult.bstrVal[0] = 'x'
    dispparams.cArgs = 1;
    DISPID dispidPut = DISPID_PROPERTYPUT;
    dispparams.rgdispidNamedArgs = &dispidPut;
    dispparams.cNamedArgs = 1;
    hr = pDoc->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
 
    if( *pArgs )
    {
        long index[1] = { 1 };
        hr = ::SafeArrayPutElement(*pArgs, index, &vResult );
    }
    VariantClear(&vResult);
    return;
}
Vita
Сообщений: n/a
23.03.2009, 11:29 #4
А в чем проблема?
Я вставил в твой проект в файл
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//              Step46
// Сайт Первые шаги (firststeps.narod.ru)
//          Каев Артем (1999-2001)
//          создано      1999 г.
//          обновление 10.07.2001
//            dllexcel.cpp
 
#include 'dllexcel.h'
 
void WINAPI MyTest()
{  
    MessageBox(0,'Hellos','Dll',MB_OK);
}
 
extern 'C' __declspec(dllexport) void __stdcall toPrint(IDispatch* *ppDoc, SAFEARRAY* *pArgs)
{
... весь текст ...
}
и он скомпилировался и собрался. Точно также как и без функции toPrint.

PS
Пиши лучше в форум. Так всем полезней будет!
Said007
0 / 0 / 0
Регистрация: 02.09.2007
Сообщений: 209
23.03.2009, 12:44  [ТС] #5
Я очень благодарен Вам Vita за помощь. После вашего разъяснения и у меня компиляция прошла без ошибок (раньше я пытался вставить объявление и в dllexcel.h)

Но теперь, после того как я подключил созданную DLL к моей программе, я получаю следующую ошибку:

Can't find DLL entry point toPrint in DllExcel.dll

А что теперь я сделал не так? :P
0
Vita
Сообщений: n/a
23.03.2009, 13:18 #6
Нужно было запостить код на VB, где ты объеявляешь функцию toPrint. Для примера, если просто запостить код вышеприведенный код toPrint в файл DllExcel.cpp, то
Visual Basic
1
2
Private Declare Sub toPrint Lib 'DllExcel' Alias '_toPrint@8' _
      (pDoc As Object, pArgs() As Variant)
Если 'корежить' имена через dllexcel.def, то так как описано в нем.
Said007
0 / 0 / 0
Регистрация: 02.09.2007
Сообщений: 209
23.03.2009, 14:56  [ТС] #7
Это невероятно, действительно функция заработала. Еще раз благодарю и еще раз прошу о помощи.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
extern 'C' __declspec(dllexport) void __stdcall toPrint(IDispatch* *ppDoc,
SAFEARRAY* *pArgs)
{
        
    IDispatch* pDoc = *ppDoc;
    
    DISPID dispid;
    LPOLESTR lpszEv = OLESTR('Caption');
    HRESULT hr = pDoc->GetIDsOfNames(IID_NULL, &lpszEv, 1,
    LOCALE_USER_DEFAULT, &dispid);
 
    VARIANT vResult;
    VariantInit(&vResult);
    DISPPARAMS dispparams = { NULL, NULL, 0, 0};
 
    hr = pDoc->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT,
    DISPATCH_PROPERTYGET, &dispparams, &vResult, NULL, NULL);
 
    dispparams.rgvarg = &vResult;
    vResult.bstrVal[0] = 'x'
    dispparams.cArgs = 1;
    DISPID dispidPut = DISPID_PROPERTYPUT;
    dispparams.rgdispidNamedArgs = &dispidPut;
    dispparams.cNamedArgs = 1;
 
    //Где-то в этом месте происходит исключение
        hr = pDoc->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT,
    DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
    //Где-то в этих двух строчках
 
    if( *pArgs )
    {
    long index[1] = { 1 };
    hr = ::SafeArrayPutElement(*pArgs, index, &vResult );
    }
    VariantClear(&vResult);
    return;
}
0
Vita
Сообщений: n/a
23.03.2009, 15:52 #8
Надо сказать было сразу, зачем я запостил функцию с реальным содержанием! Просто показать, что работает, да и самому убедиться, что лажу не предлагаю.

Итак, там есть две проверки: IDispatch-а и SAFEARRAY-я. Все это без какого-либо контроля, кроме Отладчика.

1. В первом случае я читаю свойство 'Caption' и пытаюсь установить его, изменив самам что ни на есть простым способом - vResult.bstrVal[0] = 'x'. Поскольку я передаю Форму Me (Form1) в качестве первого параметра, то свойство такое у него есть и допускает изменение.

2. Во втором я пытаюсь проверить, переписав в одномерном массиве его элемент с номером 1. Для этого передавал массив после 'ReDim varr(1)' массива 'Dim varr()', поскольку чтение(передачу внутрь функции) видно в Отладчике).

Итак, тебе нужно смотреть каковы значения hr. По идее они должны быть всегда равны 0 (S_OK). И если они <0, то произошла ошибка и делать ее обработку.

Еще неплохо постить код на VB. Но не весь, а только то, который влияет на (или позволяет восстановить) ошибку.
Said007
0 / 0 / 0
Регистрация: 02.09.2007
Сообщений: 209
23.03.2009, 16:58  [ТС] #9
Ага, ну теперь понятно.
А что если без всех проверок (я все проверки реализую на VB), а просто вызвать метод Ptint объекта pDoc, передав ему параметром весь массив pArgs
<code>
pDoc.Print pArgs
</code>
Боюсь, что сам я пока все равно не смогу правильно это сделать
0
Vita
Сообщений: n/a
23.03.2009, 17:54 #10
Это проще сделать в VB непосредственно, чем тащить это в VC.

А если конкретно по коду VC вызвать pDoc.Print pArgs, то
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
extern 'C' __declspec(dllexport) void __stdcall toPrint(IDispatch* *ppDoc, SAFEARRAY* *pArgs)
{
    if( *ppDoc == NULL || *pArgs == NULL )
        return E_INVALIDARG;
 
    IDispatch* pDoc = *ppDoc;
 
    // Определяем номер метода Print
    DISPID dispid;
    LPOLESTR lpszEv = OLESTR('Print');
    HRESULT hr = pDoc->GetIDsOfNames(IID_NULL, &lpszEv, 1, LOCALE_USER_DEFAULT, &dispid);
    if( SUCCEEDED(hr) )
    {
        VARIANT vResult;
        VariantInit(&vResult);
        VARIANT vParam;
        // Определяем тип массива
        hr = ::SafeArrayGetVartype(*pArgs, &vParam.vt);
        if( SUCCEEDED(hr) )
        {
            vParam.vt |= VT_BYREF|VT_ARRAY;
            vParam.pparray = pArgs;
            DISPPARAMS dispparams = { &vParam, 1, 0, 0};
            // Вызываем метод Print, передавая параметром переданный массив
            hr = pDoc->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, &vResult, NULL, NULL);
            VariantClear(&vResult);
        }
    }
    return hr;
}
Said007
0 / 0 / 0
Регистрация: 02.09.2007
Сообщений: 209
23.03.2009, 18:47  [ТС] #11
В том и заключается вся проблема, что в VB это сделать невозможно. В VB метод Print зарезервирован системой, и компилятор требует определенного синтаксиса, который не соответствует синтаксису метода Print объекта, с которым я работаю. И вот поэтому такую тривиальную задачу приходится решать таким не тривиальным способом.

Я безгранично Вам благодарен, что Вы потратили на меня целый день, помогая мне решить эту задачу. Я запустил на компиляцию ваш код, но в строке:

DISPPARAMS dispparams = { &vParam, 1, 0, 0};

Получил сообщение об ошибке:
error C2440: 'initializing' : cannot convert from 'const int' to 'long *'
Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast

Подскажите что не так, please 8
0
Vita
Сообщений: n/a
23.03.2009, 19:37 #12
C++
1
    DISPPARAMS dispparams = { &vParam, NULL, 1, 0};
И убрать коды возврата около return.

А насчет метода Print, то в СОМе нет зарезервированных слов после '.', хотя я и не смог сделать такое свойство в самом VB. И вызвать такой метод Print у объекта, сделанного на С. _xz_ Видимо, баг в VB.

Но никто не мешает использовать другое имя, раз это недоступно.
Said007
0 / 0 / 0
Регистрация: 02.09.2007
Сообщений: 209
23.03.2009, 19:49  [ТС] #13
Использовать что-либо кроме Print не могу, так как элемент сторонних разработчиков, и я могу вызывать лишь то, что есть. ;(
0
Said007
0 / 0 / 0
Регистрация: 02.09.2007
Сообщений: 209
23.03.2009, 19:58  [ТС] #14
Ура!!! Все заработало! Моей радости нет границ.

В очередной раз благодарю Вас за помощь и подтверждаю свои намерения ответить помощью на помощь. Если Вы когда-либо посчитаете, что я могу Вам чем-либо помочь, не стесняйтесь – обращайтесь. С большим удовольствием буду рад услужить Вам.

С уважением Гнатюк Андрей.
0
Vita
Сообщений: n/a
23.03.2009, 20:00 #15
Пока, как вариант для раннего связывания, obj.[Print]
Это работает.
Для позднего - попозже.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
23.03.2009, 20:00
Привет! Вот еще темы с ответами:

Как создать DLL в с++ - C++
Добрый день - вообщем прочитал тут книжку про создание DLL в с++ но не могу ее создать расматриваю такой вариант (динамическое подключение)...

Как экспортировать функцию из dll? У меня ошибка выдаётся - C++
Как экспортировать ф-ю из dll? У меня ошибка выдаётся

Как создать dll на VS2010? - C++
Добрый день! Уважаемые спец. помогите горю, леплю dll на VS2010 prof.rus для VB6 /

Как создать dll библиотеку - C++
Не могу разобраться как зоздать библиотеку ! Захожу в File-&gt;New project-&gt;Consol Application Win32-&gt; Ставлю галочку DLL Мне генерится...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
15
Yandex
Объявления
23.03.2009, 20:00
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru