Класний форум твого міста
Ви бажаєте відреагувати на цей пост? Створіть акаунт всього за кілька кліків або увійдіть на форум.

Класний форум твого міста

Форум для всіх
 
ФорумВідпочинок на пПошукОстанні зображенняЗареєструватисьВхід<<<ЧАТ>>>>>>НОВИНИ<<<

 

 Програмування С++

Перейти донизу 
АвторПовідомлення
Гість
Гість




Програмування С++ Empty
ПовідомленняТема: Програмування С++   Програмування С++ Icon_minitimeВт Квіт 01, 2008 8:58 pm

Думаю тема понятна
Повернутися до початку Перейти донизу
Гість
Гість




Програмування С++ Empty
ПовідомленняТема: Re: Програмування С++   Програмування С++ Icon_minitimeВт Квіт 01, 2008 9:04 pm

ActiveX Scripting Engines: Интерпретация внешнего скрипта в С++

Иногда очень хочется добавить в программу возможность интерпретации внешнего скрипта. Одна из сравнительно простых и мощных возможностей – использовать ActiveX Scripting Engines и использовать VBScript или JavaScript. На первый взгляд, для этого требуются глубокие знания OLE COM технологии. Имеющиеся на сайте Microsoft примеры могут отпугнуть чем-нибудь совсем непонятным, например, объявлением METHOD_PROLOGUE и последующим использованием непонятно откуда взявшегося указателя pThis. Meжду тем, реализовать поддержку ActiveScript совсем несложно. Глубоко понять внутренние скрытые механизмы труднее, но это и не нужно – цель совершенно другая: внедрить поддержку скрипта, не вдаваясь в тонкости. Для этого используем то, что уже реализовано, а именно MFC.

Полные файлы примера находятся в прикреплнном архиве. Здесь в описании приводятся только фрагменты для иллюстрации определенных принципов.
Начинаем работать.

Скрипт должен взаимодействовать с нашей С++ программой – использовать и изменять значения переменных, объявленных в С++ части программы, или вызывать функции. Скрипт наподобии такого:
PHP код:
dim k
k = 1
никому не нужен – его исполнение ничего не дает.
Нужно, чтобы переменная «k» была обьявлена не в пространстве имен самого скрипта как «dim k», а где-нибудь в C++ модуле как, например, long k, и после выполнения VBScript строки «k = 1» её значение стало равным 1.

Для реализации такой возможности используется класс, порожденный от базового MFC класса CCmdTarget. Этот класс обеспечивает механизм позднего связывания (late binding). Если не вдаваться в детали, всё довольно просто: есть таблица указателей на переменные и функции, а также строковые имена. Доступ к переменной или вызов метода осуществляется поиском соответствующего строкового идентификатора. Если в скрипте есть строка «k = 1», и существует некая long val, то в таблице есть что-то навроде:

PHP код:
struct ENTRY
{
CString name;
long* pval;
};

long val;
ENTRY table[] =
{
{ "k", &val }
};
UINT nEntryCount = 1;
Теперь строка скрипта «k = 1» исполняется так:

PHP код:
for (UINT nIndex = 0; nIndex < nEntryCount; nIndex++)
if ( table[nIndex].name == "k" )
{
*table[nIndex].pval = 1;
break;
}
Разумеется, приведенная выше модель очень грубая и только иллюстрирует общий принцип. На практике задача гораздо сложнее: вызов функций, передача параметров, возвращаемые значения, контроль типов и так далее.

Итак, создадим класс, порожденный от CCmdTarget.

PHP код:
#include <afx.h>
#include <afxdisp.h>
class CCodeObject : public CCmdTarget
{
public:
CCodeObject();
virtual ~CCodeObject();

private:
long m_nValue;

long GetMax(long, long);
void PrintValue(long);
void Message(LPCSTR);

enum
{
id_Value = 1,
id_PrintValue,
id_GetMax,
id_Message
};

DECLARE_DISPATCH_MAP()
};
Самое главное – это объявленные для диспетчеризации:
PHP код:
long m_nValue;
long GetMax(long, long);
void PrintValue(long);
void Message(LPCSTR);

Именно они используются из скрипта. Для каждого из них зарезервирован числовой идентификатор
в перечислении (enum):

PHP код:
enum
{
id_Value = 1,
id_PrintValue,
id_GetMax,
id_Message
};

Затем в .cpp модуле объявлена таблица:

PHP код:
BEGIN_DISPATCH_MAP(CCodeObject, CCmdTarget)

DISP_PROPERTY_ID(CCodeObject, "VALUE", id_Value, m_nValue, VT_I4)
DISP_FUNCTION_ID(CCodeObject, "GetMax", id_GetMax, GetMax, VT_I4, VTS_I4 VTS_I4)
DISP_FUNCTION_ID(CCodeObject, "PrintValue", id_PrintValue, PrintValue, VT_EMPTY, VTS_I4)
DISP_FUNCTION_ID(CCodeObject, "Message", id_Message, Message, VT_EMPTY, VTS_BSTR)

END_DISPATCH_MAP()

Макрос DISP_PROPERTY_ID добавляет переменную m_nValue с типом данных VT_I4 в таблицу. Её строковый идентификатор "VALUE", числовой id_Value.

Макрос DISP_FUNCTION_ID добавляет функцию GetMax с возвращаемым типом VT_I4 и двумя параметрами VTS_I4 и VTS_I4, перечисленными через пробел.

Теперь понятно, как добавить новую переменную (свойство, property) или финкцию:
- объявить соответствующий член класса;
- добавить в enum новый id;
- добавить макрос где-нибудь между BEGIN_DISPATCH_MAP и END_DISPATCH_MAP.

Отметим важную вещь: в конструкторе класса обязательно должен присутствовать вызов метода EnableAutomation().
Повернутися до початку Перейти донизу
Гість
Гість




Програмування С++ Empty
ПовідомленняТема: Re: Програмування С++   Програмування С++ Icon_minitimeВт Квіт 01, 2008 9:05 pm

оздаем механизмы ActiveX Scripting

Забежим немного вперед. Предположим, у нас уже есть инстанциированный объект Microsoft ActiveX Scripting. Для простоты, условно обьявим его так:

PHP код:
СActiveXScriptEngine engine;
Теперь мы можем вызывать его методы, например:

PHP код:
engine.InitNew();
Но сам обьект «engine» не может взаимодействовать с нашей программой – он ничего о ней не знает. Реализовать механизм обратной связи можно было по-разному. Например, передать объекту «engine» указатели на функции (callback function).

Механизм обратной связи ActiveX Scripting построен на основе специального интерфейса (класса) IActiveScriptSite. Грубо говоря, существует объявленный базовый интерфейс (класс) IActiveScriptSite, содержащий набор заранее определенных виртуальных функций. Необходимо создать класс, унаследованный от IActiveScriptSite, и перегрузить его виртуальные функции:

PHP код:
class CScriptHost : public IActiveScriptSite
{

virtual HRESULT _stdcall OnEnterScript();
virtual HRESULT _stdcall OnLeaveScript();
//. . .
};
Теперь нужно создать экземпляр нашего класса CScriptHost и передать обьекту «engine» его адрес:

PHP код:
CScriptHost host;
engine.SetScriptSite(&host);
Совершенно очевидно, что метод SetScriptSite примерно такой:

PHP код:
HRESULT SetScriptSite(IActiveScriptSite *psite)
{
m_pActiveScriptSite = psite;
psite->AddRef();
}
Теперь внутри реализации самого ActiveX Scripting возможны вызовы методов через указатель m_pActiveScriptSite на основе механизмов виртуальности и преобразования типов:

PHP код:
m_pActiveScriptSite->OnLeaveScript();
//Реально был вызван CScriptHost:: OnLeaveScript();
Отметим, что все методы, обьявленные в IActiveScriptSite, являются чисто виртуальными:

PHP код:
virtual HRESULT STDMETHODCALLTYPE OnEnterScript( void) = 0;
Поэтому придется переопределять их все, иначе нельзя инстанциировать объект, содержащий чисто виртуальные функции. Вдобавок придется позаботится о методах класса IUnknown, от которого унаследован сам IActiveScriptSite (они тоже чисто виртуальные). В результате появляются функции, особо ничего не делающие, например:

PHP код:
HRESULT _stdcall
CScriptHost::GetDocVersionString(BSTR* pbstrVersionString)
{
return E_NOTIMPL ;
}

HRESULT _stdcall
CScriptHost::OnScriptTerminate(const VARIANT* pvarResult,
const EXCEPINFO* pexcepinfo)
{
return S_OK; // successful
}
Повернутися до початку Перейти донизу
Гість
Гість




Програмування С++ Empty
ПовідомленняТема: Re: Програмування С++   Програмування С++ Icon_minitimeВт Квіт 01, 2008 9:05 pm

Передача объекта

Вспомним описанный ранее объект, порожденный от CCmdTarget и служащий, напомню, для позднего связывания:
PHP код:
class CCodeObject : public CCmdTarget
{
. . .
Пришло его время.

Один из методов интерфейса IActiveScriptSite имеет следующий прототип:

PHP код:
HRESULT _stdcall CScriptHost::GetItemInfo(LPCOLESTR pstrName,
DWORD dwReturnMask,
IUnknown** ppunkItem,
ITypeInfo** ppTypeInfo);
Во время исполнения скрипта метод GetItemInfo будет вызван с определенными параметрами, говорящими о том, что в ответ нужно вернуть указатель на интерфейс IUnknown*. Это как раз и есть тот момент, когда для дальнейшего исполнения скрипта понадобился экземпляр объекта CCodeObject – например, чтобы «поискать» там какую-нибудь переменную, имя которой использовано в скрипте.
К этому моменту в каком-нибудь модуле трансляции уже существует экземпляр класса CCodeObjecе. Например, обьявленный как глобальный – сейчас стиль программирования не особо важен, главное – проиллюстрировать суть происходящего. Итак, где-то объявлен и находится в зоне видимости:

PHP код:
CCodeObject codeobj;
Теперь в реализации CScriptHost::GetItemInfo() происходит следующее:

PHP код:
HRESULT _stdcall CScriptHost::GetItemInfo(LPCOLESTR pstrName,
DWORD dwReturnMask,
IUnknown** ppunkItem,
ITypeInfo** ppTypeInfo)
{
// . . .

*ppunkItem = codeobj.GetIDispatch(TRUE);
// . . .
}
Заметим важный ньюанс – следующая строка НЕПРАВИЛЬНАЯ:
PHP код:
*ppunkItem = (IUnknown*)&codeobj; // так нельзя!!!
Компилятор проглотит, но, хотя наш обьект и унаследован от CCmdTarget, сам класс CCmdTarget не унаследован от IUnknown.
Ранее мы создавали CScriptHost, унаследованный от IActiveScriptSite, а сам IActiveScriptSite был унаследован от IUnknown. Это действительно допускает преобразование CScriptHost к IUnknown.
Но в случае с классом CCodeObject, порожденным от CCmdTarget, преобразование к типу IUnknown невозможно.
Класс CCmdTarget может вернуть указатель на интерфейс IUnknown (или интефейс IDispatch, действительно порожденный от IUnknown). Но делается это путем вызова

PHP код:
IUnknown* punk = CCmdTarget::GetInterface(&IID_IUnknown);
или

PHP код:
IUnknown* punk = CCmdTarget::GetIDispatch(TRUE);
В основу положен другой механизм. В очень грубом приближении, в классе CCmdTarget объявлен член класса, имеющий тип IDispatch, а метод GetIDispatch возвращает его адрес:

PHP код:
class CCmdTarget:
{
// . . .
IDispatch m_xxIDispatch;

IUnknown* GetIDispatch(BOOL bAddRef)
{
if ( bAddRef ) m_xxIDispatch.AddRef();
return &m_xxIDispatch;
}
};
На самом деле всё несколько сложнее – применена некоторая арифметика указателей и смещений. Проиллюстрируем это на примере:

PHP код:
class IClassA
{
};

class ClassB
{
int dummy1, dummy2, dummy3;

IClassA m_xxIClassA;

static int m_offs;

public:

IClassA* GetIClassA()
{
IClassA* pia = (IClassA*)((BYTE*)this + m_offs);
return pia;
}
};

int ClassB::m_offs = (size_t)&(((ClassB *)0)->m_xxIClassA);


int main(int argc, char* argv[])
{

ClassB b;
IClassA* pA = b.GetIClassA();

return 0;
}
Не будем углубляться дальше. Продолжим работу над главной задачей – запуском скрипта. Осталось совсем немного.
Повернутися до початку Перейти донизу
Гість
Гість




Програмування С++ Empty
ПовідомленняТема: Re: Програмування С++   Програмування С++ Icon_minitimeВт Квіт 01, 2008 9:06 pm

Собираем всё вместе

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

PHP код:
// Не забываем инициализировать COM библиотеку
CoInitializeEx(NULL, COINIT_MULTITHREADED);

// А это наш скрипт.
CString script =
"k = 10 \r\n"
"dim x \r\n"
"dim y \r\n"
"x = 10 \r\n"
"y = 20 \r\n"
"VALUE = GetMax(x, y)\r\n"
"PrintValue(VALUE)\r\n"
"Message \"Hello, Script!\" \r\n";


// Об этих объектах уже столько сказано:
CCodeObject codeobj;
CScriptHost host;


// Глобальное имя объекта скрипта. Это и есть та строка, которая
// (помните?) передается потом как параметр при вызове
// CScriptHost::GetItemInfo(LPCOLESTR pstrName, ... )
LPCOLESTR pstrObjectName = L"CodeObject";

// Передадим наш codeobj, вернее, его IDispatch интерфейс.
// обьект host его запомнит, а потом, когда будет нужно, передаст в
// при вызове CScriptHost::GetItemInfo(), как говорилось ранее.
host.AssociateNamedObject( codeobj.GetIDispatch(TRUE),
pstrObjectName );


// Создаем (инстанциируем) обьекты ActiveX Scripting Engine для
// VBScript. При желании, можно заменить L"VBScript" на L"JScript" для
// JavaScript. В документации Microsoft указано, что возможно
// использовать также Perl и Lisp, но я не пробовал.

IActiveScript *pASEngine = NULL;
IActiveScriptParse *pISParser = NULL;

CLSID EngineClsid;
CLSIDFromProgID(L"VBScript", &EngineClsid);
CoCreateInstance(EngineClsid, NULL, CLSCTX_INPROC_SERVER,
IID_IActiveScript, (void **)&pASEngine);

pASEngine->QueryInterface(IID_IActiveScriptParse, (void**)&pISParser);

// Передаем наш хост-объект – как уже говорилось, engine будет вызывать
// его методы.
pASEngine->SetScriptSite(&host);


// Здесь важен флаг видимости имен SCRIPTITEM_GLOBALMEMBERS.
// Если этот флаг не указывать, нужно потом вызывать ParseScriptText с
// обязательным pstrObjectName в качестве второго параметра:
// pISParser->ParseScriptText( pParseText,
// pstrObjectName,
// NULL, NULL, 0, 0, 0, NULL, &ei);

pASEngine->AddNamedItem( pstrObjectName, SCRIPTITEM_ISVISIBLE |
SCRIPTITEM_ISSOURCE |
SCRIPTITEM_GLOBALMEMBERS);

pISParser->InitNew();

// Ну что ж, передаем скрипт для парсинга.
EXCEPINFO ei = {0};
BSTR pParseText = script.AllocSysString();
pISParser->ParseScriptText(pParseText, NULL, NULL, NULL, 0, 0, 0, NULL,
&ei);
SysFreeString(pParseText);


// Всё, пора. Запускаем скрипт на выполнение!!!
pASEngine->SetScriptState(SCRIPTSTATE_CONNECTED);


// Ну вот и всё...
pASEngine->Close();
pISParser->Release();
pASEngine->Release();
Повернутися до початку Перейти донизу
Eton
Сержант
Сержант
Eton


К-ть повідомлень : 63
Age : 35
Reputation : 11
Points : 11
Registration date : 27.01.2008

Програмування С++ Empty
ПовідомленняТема: Re: Програмування С++   Програмування С++ Icon_minitimeСб Квіт 12, 2008 1:29 pm

#include <world.h>

int main(int argc, char* argv[])
{

cout <<'Я б Змінив СВІТ но Бог ніяк не дає ІСХОДНІКІВ';
return 0;
}
Повернутися до початку Перейти донизу
Гість
Гість




Програмування С++ Empty
ПовідомленняТема: Re: Програмування С++   Програмування С++ Icon_minitimeСр Квіт 16, 2008 9:25 am

ЕМБЛЕМА

#include<iostream.h>
#include<stdlib.h>
#include<conio.h>
#include<graphics.h>
int main()
{
int gdrive=DETECT, gmode, errorcode;
initgraph(&gdrive,&gmode, "");
errorcode=graphresult();
if (errorcode!=grOk)
{
cout<<"ERROR:"<<grapherrormsg(errorcode);
cout<<"\n press button";
getch();
exit(1);
}
setbkcolor(0);
setcolor(3);
rectangle(100,0,300,200);
setfillstyle(1,3);
floodfill(200,100,3);
setcolor(14);
circle(200,100,100);
settextstyle (0,0,3);
outtextxy(140,95,"Kocmoc");
getch();
closegraph();
return 0;
}
Повернутися до початку Перейти донизу
Гість
Гість




Програмування С++ Empty
ПовідомленняТема: Re: Програмування С++   Програмування С++ Icon_minitimeСр Квіт 16, 2008 9:26 am

ГРАФІК ФУНКЦІЇ

#include<iostream.h>
#include<stdlib.h>
#include<conio.h>
#include<GRAPHICS.H>
#include<math.h>
float f(float x);
void main()
{
const float a=0, b=2*3.14, h=0.1;
const int h1=5, x0=60, y0=240, M=50;
int gdriver=DETECT, gmode, errorcode;
int x1, y1;
float x, y;
initgraph(&gdriver,&gmode,"");
errorcode=graphresult();
if (errorcode!=grOk)
{
cout<<"ERROR"<<grapherrormsg(errorcode);
cout<<"PRESS BUTTON";
getch();
exit(1);
}
setbkcolor(1);
setcolor(14);
line(20,y0,600,y0);
line(x0,400,x0,20);
x=a;
x1=x0+M*x;
y=f(x);
y1=y0-M*y;
moveto(x1,y1);
setcolor(15);
do
{
y=f(x);
y1=y0-(M*y);
lineto(x1,y1);
x1+=h1;
x=x+h;
}
while (x<=b);
settextstyle(0,0,1);
outtextxy(60,245,"0");
outtextxy(360,245,"6.3");
settextstyle(0,0,2);
outtextxy(100,380, "GRAPHIK FUNKCII sinxcosxsin(x+1.4)/0.85+7.14");
getch();
closegraph();
}
float f(float x)
{
float func;
func=sin(x)*cos(x)*sin(x+1.4)/0.85+7.14;
return func;
}
Повернутися до початку Перейти донизу
Гість
Гість




Програмування С++ Empty
ПовідомленняТема: Re: Програмування С++   Програмування С++ Icon_minitimeСр Квіт 16, 2008 9:26 am

АНІМАЦІЯ

#include<iostream.h>
#include<stdlib.h>
#include<conio.h>
#include<graphics.h>
#include<dos.h>
int main()
{
int gdrive=DETECT, gmode, errorcode;
initgraph(&gdrive,&gmode, "");
errorcode=graphresult();
if (errorcode!=grOk)
{
cout<<"ERROR:"<<grapherrormsg(errorcode);
cout<<"\n press button";
getch();
exit(1);
}
setbkcolor(BLACK);
setcolor(GREEN);
int y=60,sy=4,r=50;
int x=getmaxx()/2;
do
{
circle(x,y,r);
delay(30);
setcolor(BLACK);
circle(x,y,r);
setcolor(GREEN);
y+=sy;
if (y<60||y>getmaxy()-60)
sy=-sy;
}
while(!kbhit());
getch();
closegraph();
}
Повернутися до початку Перейти донизу
Гість
Гість




Програмування С++ Empty
ПовідомленняТема: Re: Програмування С++   Програмування С++ Icon_minitimeПн Черв 09, 2008 6:36 pm

1
Повернутися до початку Перейти донизу
Спонсорований контент





Програмування С++ Empty
ПовідомленняТема: Re: Програмування С++   Програмування С++ Icon_minitime

Повернутися до початку Перейти донизу
 
Програмування С++
Повернутися до початку 
Сторінка 1 з 1

Права доступу до цього форумуВи не можете відповідати на теми у цьому форумі
Класний форум твого міста :: Hardware Software :: Електронний світ-
Перейти до: