Разработка DLL на языке С++, страница 5

~Geometry ();

char* Say();

};

__declspec(dllimport) void AllocMatrix (double**& a, int ny, int nx);

__declspec(dllimport) void ClearMatrix (double**& a, int n);

__declspec(dllimport) bool Gauss (double** a, double* x, int n);

__declspec(dllimport) bool Solve (Geometry* p, double**& u, int ny, int nx);

void FillMatrix (double **a, int n)   // Генерирование расширенной матрицы

{

for (int i=0; i<n; i++)

{

for (int j=0; j<n; j++)

a[i][j] = sin((i+j+.2) / 20.) + log (i + j + 1.);

}

for (int i=0; i<n; i++)       // Вектор правых частей

{

for (int j=0, a[i][n]=0.; j<n; j++)

a[i][n] += a[i][j] * (j+1);

}

for (int i=0; i<n; i++)  // Вывод плохой матрицы

{

cout <<   endl;

for (int j=0; j<n+1; j++)

cout <<  a[i][j] << ", ";

}

}

void main ()

{

Geometry g (2, 3);  // Этот код просто иллюстрирует возможности DLL

cout << g.Say() << "\nExported progress: "<< progress<< endl

<< "\nExported error: "<< error<< endl;

double** a;

int n = 1;

Solve (&g, a, 10, 10);

cout << "\nExported error: "<< error<< endl;

while (true) // Этот цикл позволяет исследовать решение линейных систем с плохо-обусловленной матрицей

{

cout <<"\n\nEnter matrix dimension: ";

cin >> n;

if (n < 2 || 15 < n)

break;

AllocMatrix (a, n, n+1);

double* x = new double[n];

FillMatrix (a, n);

Gauss (a, x, n); // Исключение по Гауссу

ClearMatrix (a, n);

cout << "\n\nProgress: " << progress <<'%';

cout << "\n\n\tSolution\n\n";

for (int i=0; i<n; i++)

cout << x[i] << ",  ";

}

cout << "\n\n";

}

Для запуска клиентского процесса в окне Solution Explorer выделите новый проект MyDLLClient и в его контекстном меню выберите команду Set as StartUp Project. Эта установка говорит построителю, что выполнение должно начаться с запуска клиентского проекта. Запустите и отладьте работу обоих проектов. Заметьте, что отладчик (F5) и пошаговое выполнение (F10, F11 и т.д.) доступны как в клиентском, так и в серверном проектах.

Доступ к DLL из управляемого кода

В .NET Framework существует специальная служба PInvoke (Platform Invocation Services), которая позволяет из управляемого кода  (managed code) программы на C# вызывать функции, созданные и существующие в неуправляемом коде DLL. Главным оружием службы PInvoke являются атрибуты функций и параметров, то есть те незнакомые конструкции в квадратных скобках, которые вы иногда видите стоящими перед методами. Вспомните, например, атрибут [STAThread], стоящий перед функцией Main программы на языке C#. Он указывает, что потоковая модель приложения соответствует модели STA (Single-Threaded Apartment), определенной в технологии COM. Платформа .NET различает два способа вызова неуправляемых функций:

¨  Прямой вызов функции, экспортируемой DLL.

¨  Вызов метода, который определен в COM-интерфейсе и реализован COM-объектом.

Оба способа предполагают наличие декларации импортируемых функций с помощью атрибута DllImport, а также возможно необходимого уточнения способа передачи параметров как в сторону клиента, так и в сторону DLL. Процедура передачи параметров (marshaling) из управляемого кода в неуправляемый и обратно, может оказаться болезненной, так как новые типы данных не всегда соответствуют старым. Типы данных управляемого приложения определены значительно более строго, поэтому иногда требуется установить точное соответствие между типами передаваемых данных.

Рассмотрим на примере как осуществляется прямой вызов функции, экспортируемой DLL. Создайте новый проект консольного приложения типа Visual C# Projects с именем MyDLLClientCSharp. Если имя проекта совпадает с именем предыдущего, то целесообразно изменить местоположение проекта. Внесите изменения в заготовку проекта. Файл Class1.cs назовите GaussTest.cs и измените его код.