На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное DigiMania RSS
msm.ru
Модераторы: maxim84_, juice
Страницы: (2) [1] 2  все  ( Перейти к последнему сообщению )  
> Использование DLL в проекте C#WPF, DLL-ка на Си
Уважаемые форумчане , помогите с вопросом по использованию функций DLL(написана на Си) ,
проект очень простенький все на одной кнопочке и пару текстЕдитов
весь код линейный в одной кнопке
MainWindow.xaml.cs
Скрытый текст

ExpandedWrap disabled
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
     
    using System.Reflection;
     
    using System.Runtime.InteropServices;
     
    namespace ComHyTech
    {
     
     
        public partial class MainWindow : Window
        {
     
     
     
            public MainWindow()
            {
                InitializeComponent();
            }
     
            struct hcSqlParmT
            {
                public ushort size;
            };
     
            [StructLayout(LayoutKind.Sequential)]
            unsafe struct hcSqlDstInfoT     // Структура "Информация о колонках результата"
            {
                public int aliasno;
                public int fieldno;
                public int type;
                public uint len;
                public uint off;
                public fixed char coder[32];
                public fixed char fname[32];
                public int func;
                public fixed char asname[32];
                public int key;
                public int resno;
            };
        
            [DllImport("hscli.dll")]
            static extern int hcSqlInit(IntPtr dummy);
     
            [DllImport("hscli.dll")]
            static extern int hcSqlCheckInit();
            
            [DllImport("hscli.dll")]
            static unsafe extern int hcSqlAllocConnect(out int pdb);
            //static unsafe extern int hcSqlAllocConnect(int* pdb);
     
            [DllImport("hscli.dll")]
            static unsafe extern int hcSqlConnect(int pdb, string server, string login , string password);
     
            [DllImport("hscli.dll")]                        
            static unsafe extern int hcSqlAllocStmt(int pdb, int * pOper);// Создать оператор
     
            [DllImport("hscli.dll")]
            static unsafe extern int hcSqlSetStmtAttr(int pOper, uint option, void* pValue, uint size);
     
            [DllImport("hscli.dll")]
            static unsafe extern int hcSqlExecDirect(int pOper, string strSQL);// Выполняем SQLзапрос
     
     
            [DllImport("hscli.dll")]
            static unsafe extern int hcSqlNumResultCols(int pOper, int*  pCol);
     
            [DllImport("hscli.dll")]
            static unsafe extern int hcSqlRowCount(int pOper, long* pStr);
     
            [DllImport("hscli.dll")]
            static unsafe extern int hcSqlOpenResults(int pOper, uint *pRecSize);
            
            [DllImport("hscli.dll")]
            static unsafe extern int hcSqlGetStmtAttr(int pOper, uint option, int pos, hcSqlDstInfoT[] pValue, uint size, uint* cnt);
     
            [DllImport("hscli.dll")]
            static unsafe extern int hcSqlReadResults(int pOper, long gStart, byte[] pBuf, uint wBufSize, uint * cnt);
            
     
            [DllImport("hscli.dll")]
            static unsafe extern int hcSqlCloseResults(int pOper); // Закрытие доступа к результатам
            [DllImport("hscli.dll")]
            static unsafe extern int hcSqlFreeConnect(int pdb); // Освободить соединение
            [DllImport("hscli.dll")]
            static unsafe extern int hcSqlDone();// Завершение работы
     
            private unsafe void button_Click(object sender, RoutedEventArgs e)
            {
                int err = -300000;// код ошибки заведомо не существующий
                
                int       pdb = 0 ;
                int     pOper = 0 ; // идетификатор оператора
                int      pCol = 0 ; // кол-во колонок
                long     pStr = 0 ; // кол-во строк
                uint pRecSize = 0 ; // размер записи
                uint    cntOp = 0 ; //  сколько байтов записали в буфер
     
                long   gStart = 0 ; // с какой записи начинаем читать
     
                if ((err = hcSqlInit(IntPtr.Zero)) != 0)  { return; } // Инициализация клиентской части
                
                textBox_Copy3.AppendText("Инициализация клиентской части err = " + err.ToString() + "\r\n");
     
                err = hcSqlCheckInit();                  // Проверка завершения инициализации
                
                textBox_Copy3.AppendText("Проверка завершения инициализации err = " + err.ToString() + "\r\n") ;
     
                unsafe
                {
                    err = hcSqlAllocConnect  (out pdb ) ;           //  Создать соединение
                    textBox_Copy3.AppendText ("Создать соединение err = " + err.ToString() + "\r\n" );
                    textBox_Copy3.AppendText ("соединение         pdb = " + pdb.ToString() + "\r\n" );
                    err = hcSqlConnect       (pdb, textBox.Text.ToString() , textBox1.Text.ToString(), textBox2.Text.ToString()); //Установить связь с СУБД
                    textBox_Copy3.AppendText ("Установить связь с СУБД err = " + err.ToString() + "\r\n");
                    err = hcSqlAllocStmt     (pdb,   &pOper                                         ); // Создать оператор
                    textBox_Copy3.AppendText ("Создать оператор err = " + err.ToString()   + "\r\n" );
                    textBox_Copy3.AppendText ("оператор       pOper = " + pOper.ToString() + "\r\n" );
                    err = hcSqlSetStmtAttr   (pOper,  1001,   (void*)1,   0                         ); // ф-ция "Изменение параметров оператора"
                    textBox_Copy3.AppendText ("ф-ция  Изменение параметров оператора  err = " + pOper.ToString() + "\r\n");
                    err = hcSqlExecDirect    (pOper, textBox3.Text.ToString()                       ); // Выполняем SQLзапрос
                    textBox_Copy3.AppendText ("Выполняем SQLзапрос = " + pOper.ToString() + "\r\n"  );
     
                    err = hcSqlNumResultCols (pOper, &pCol);     // Получить кол-во колонок результата
                    textBox_Copy3.AppendText("кол-во колонок = " + pCol.ToString() + "\r\n");
                    err = hcSqlRowCount      (pOper, &pStr);     // Получить кол-во строк   результата
                    textBox_Copy3.AppendText("кол-во строк = " + pStr.ToString() + "\r\n");
                    err = hcSqlOpenResults   (pOper, &pRecSize); // Открытие результатов для чтения
                    textBox_Copy3.AppendText("размер записи = " + pRecSize.ToString() + "\r\n");
              
                    hcSqlDstInfoT[] infCol  =  new hcSqlDstInfoT[pCol]; // Структура "Информация о колонках результата"
                    
                    err = hcSqlGetStmtAttr(pOper, 107, 0,  infCol, (uint)pCol * 128 , &cntOp);// Получить информацию об операторе
                    
                    byte[] bufOut = new byte[pRecSize * pStr]; // Адрес буфера для присылаемых записей.
     
                    uint cntOut = 0;
     
                    err = hcSqlReadResults(pOper, 0, bufOut, pRecSize * (uint)pStr, &cntOut);// Чтение результатов
     
                    // byte  p = bufOut;
     
                    for (long i = 0; i < pStr; i++) // идем по строкам
                    {
     
                        for (int j = 0; j < pCol; ++j)// идем по колонкам
                        {
     
                            switch (infCol[j].type)// в зависимости от типа колонки преобразовываем в соответствующий тип
                            {
                                case 0: // 0 Массив символов длиной не более заданной
                                       //string s(p, infCol[j].len);
                                       textBox_Copy3.AppendText( infCol[j].type  + " ");  
                                       break;
     
                    //            case 1: // 1 Массив байтов заданной длины
        //                        textBox_Copy3.AppendText(*reinterpret_cast < unsigned char *> (p) + " ");  
        //                               break;
     
                    //            case 2: // 2 Элемент - unsigned char (короткое целое)  short
        //                               std::cout << *reinterpret_cast < unsigned char*> (p) << "  ";
        //                               break;
     
                    //            case 3: // 3 Элемент - signed short  
        //                                     std::cout << *reinterpret_cast < signed short*> (p) << "  ";
        //                                break;
     
                    //case 4: // 4 Элемент - unsigned short  
        //        std::cout << *reinterpret_cast < unsigned short*> (p) << "  ";
        //        break;
     
                    //case 5: // 5 Дата    - unsigned short  
        //        std::cout << *reinterpret_cast < unsigned short*> (p) << "  ";
        //        break;
     
                    //case 6: //6  Номер   - 3-х байтовое целое без знака  
        //                                // std::cout << *reinterpret_cast<  *>(p);
        //        break;
     
                    //case 7: //7 Элемент - long int
        //        std::cout << *reinterpret_cast < long int*> (p) << "  ";
        //        break;
     
                    //case  8: // 8 Элемент - unsigned long int  в БД это dword          
        //        std::cout << *reinterpret_cast < unsigned long int*> (p) << "  ";
        //        break;
     
                    //case 9: //    9  Элемент - float
        //        std::cout << *reinterpret_cast<float*>(p) << "  ";
        //        break;
     
                    //case 10: //   10 Деньги (double)  
        //        std::cout << *reinterpret_cast<double*>(p) << "  ";
        //        break;
     
                    //case 1: // 11 Элемент - double  
        //        std::cout << *reinterpret_cast<double*>(p) << "  ";
        //        break;
     
                    //case 12: //   12 Элемент - signed __int64
        //        std::cout << *reinterpret_cast < signed __int64 *> (p) << "  ";
        //        break;
                    //case 13: //   13 Элемент - unsigned __int64
        //        std::cout << *reinterpret_cast < unsigned __int64 *> (p) << "  ";
        //        break;
            }
     
           // p += infCol[j].len;
     
            }
            textBox_Copy3.AppendText( "\r\n");  
        }
     
     
                    hcSqlCloseResults(pOper); // Закрытие доступа к результатам
     
                    hcSqlFreeConnect(pdb);    // Освободить соединение
     
                    hcSqlDone();              // Завершение работы
      
     
                }
     
     
     
            }
     
     
     
     
     
     
        }
    }



затык произошел на функции
err = hcSqlReadResults(pOper, 0, bufOut, pRecSize * (uint)pStr, &cntOut);// Чтение результатов

помогите пожалуйста разобраться с вопросом
ошибку выдает такую
ExpandedWrap disabled
    Помощник отладки управляемого кода "PInvokeStackImbalance" обнаружил неполадку в " \bin\x86\Debug\ComHyTech.vshost.exe".
     
    Дополнительные сведения: Вызов функции PInvoke "ComHyTech!ComHyTech.MainWindow::hcSqlReadResults" разбалансировал стек. Вероятно, это вызвано тем, что управляемая сигнатура PInvoke не совпадает с неуправляемой целевой сигнатурой. Убедитесь, что соглашение о вызовах и параметры сигнатуры PInvoke совпадают с неуправляемой целевой сигнатурой.


Добавлено
проект https://yadi.sk/d/Y5YtmjjK3GrG6f
Помогите вопрос очень актуален
Начать имеет смысл с явного задания в C#-сигнатуре того calling convention, который использует функция hcSqlReadResults в DLL
https://msdn.microsoft.com/en-us/library/sy...(v=vs.110).aspx
Windows as usual - my "wau" Windows experience
Всем спасибо вопрос решен
Цитата Mr.Delphist @
Начать имеет смысл с явного задания в C#-сигнатуре того calling convention, который использует функция hcSqlReadResults в DLL

извините как то получилось что не прочитал Ваше сообщение, теперь начал разбиратся и немного не понял вот
эти слова
Цитата Mr.Delphist @
C#-сигнатуре того calling convention, который использует функция hcSqlReadResults в DLL

извините не очень силен поетому и переспрашиваю, что это значит и как это моно реализовать применительно к моему случаю

на данный момент дошел вот до этого если будет интересно , https://github.com/vovakms/dbms-HyTech_edition_CSharp код закончен , только надо теперь оптимизировать и дорабатывать нюансы
У каждой функции есть, кроме параметров и результата, так называемое "соглашение о вызовах". Оно определяет, в числе прочего, как используется стэк, кто ответственен за его менеджмент, в каком формате передаются параметры и результат. Поэтому попытка использовать функцию с иным calling convention, нежели с которым она скомпилирована, приведёт к ошибке (функция будет искать не там свои параметры, класть результат не туда, память будет либо утекать, либо дербаниться чужая).
Например, сишные функции по умолчанию предполагают cdecl, однако WinAPI ставит в качестве стандарта stdcall.

Подробнее:
https://msdn.microsoft.com/en-us/library/984x0h58.aspx
Windows as usual - my "wau" Windows experience
Цитата kms @
Уважаемые форумчане , помогите с вопросом по использованию функций DLL(написана на Си) ,
проект очень простенький все на одной кнопочке и пару текстЕдитов
весь код линейный в одной кнопке

Я же тебе еще в соседней теме, в этом разделе дал ссылки на нужную литературу. Если ты будешь вот так эспортировать каждую функцию - то выйдет громоздко, не красиво и не в ООП стиле. Я тебе предлагал написать класс обертку над этими функциями, потом его экспортировать в DLL

ExpandedWrap disabled
    class DLL_EXPORT MyClass
    {...}

Где DLL_EXPORT - это макрос, который в зависимости от режима будет равен либо __declspec(dllexport), либо __declspec(dllimport)

Потом на С++/CLI набросать точно такой же класс, но который будет оберткой над этим классом:
ExpandedWrap disabled
    class MyWrapper
    {
    private:
     MyClass m_myClass;
    };

Методы у него будут называться точно так же, по сути это внешне копия С++ класса, но в качестве реализации ты будешь просто вызывать методы своего С++ сного класса.
А дальше, уже то, что у тебя получится на С++/CLI ты без всяких заморочек уже можешь использовать в C#
Сообщение отредактировано: KILLER -
Цитата KILLER @
Я же тебе еще в соседней теме, в этом разделе дал ссылки на нужную литературу. Если ты будешь вот так эспортировать каждую функцию - то выйдет громоздко, не красиво и не в ООП стиле. Я тебе предлагал написать класс обертку над этими функциями, потом его экспортировать в DLL

Не-не-не, батенька, чтобы начать бегать и прыгать, надо научиться ходить. Давайте автор сперва твёрдо разберётся с экспортированием отдельных функций, а затем уже можно и классы попробовать экспортировать (не забывая про манглинг имён, ABI и прочие радости).
Windows as usual - my "wau" Windows experience
Цитата KILLER @
Я же тебе еще в соседней теме, в этом разделе дал ссылки на нужную литературу.

спасибо , литературу изучаю ,
Цитата KILLER @
Если ты будешь вот так эспортировать каждую функцию - то выйдет громоздко, не красиво и не в ООП стиле.

понять и простить

Цитата KILLER @
Я тебе предлагал написать класс обертку над этими функциями, потом его экспортировать в DLL

на С++ почти доделал , не хватает все времени и мозгов закончить , уже приготовил проекты и с одним классом и с двумя , делаю DLL-ку подключаю DLL-ку к тестовому проекту а оно че то не работает , я это дело пока оставил , еще на пару недель, а сейчас пока на С# пробую

Скрытый текст

Цитата KILLER @
де DLL_EXPORT - это макрос, который в зависимости от режима будет равен либо __declspec(dllexport), либо __declspec(dllimport)

Потом на С++/CLI набросать точно такой же класс, но который будет оберткой над этим классом:

class MyWrapper
{
private:
 MyClass m_myClass;
};

Методы у него будут называться точно так же, по сути это внешне копия С++ класса, но в качестве реализации ты будешь просто вызывать методы своего С++ сного класса.
А дальше, уже то, что у тебя получится на С++/CLI ты без всяких заморочек уже можешь использовать в C#




я всетаки решил попробывать обойти С++/CLI , а сразу шпарить на С#, я подумал так если получится значит класс, если не получится так хоть немножко чето изучу , вот и по тихому там там по немногу собрал и вот что пулучилось и оно работает и вроде не плохо загляни на досуге глянь
https://github.com/vovakms/dbms-HyTech_edition_CSharp

Добавлено
Цитата Mr.Delphist @
Давайте автор сперва твёрдо разберётся с экспортированием отдельных функций, а затем уже можно и классы попробовать экспортировать

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

Цитата Mr.Delphist @
(не забывая про манглинг имён, ABI и прочие радости).

это для меня вооще дремучий лес

Добавлено
еще сейчас пытаюсь на github сделать доступ на редактирование гостям , но в интернете не где нету инфы , хочется сделать так чтобы любой зашел посмотрел и подправил , не регистрируясь на github, а так как гость

если вы в курсе как подскажите , или там только зарегиным надо быть чтобы редактировать ????
Ну у тебя Сшный подход к задаче на C#, я этот код уже видел на С++ в разделе С++. Просто у тебя вообще концептуально не верный подход конкретно на C#, поэтому и говорю, проще все вот эти потроха от базы спрятать в С++ класс. Ну а так, ты по сути не пользуешься плюшками C#, я бы наверное не делал всех этих циклов с добавлением рядков/колонок, обошолся каким нибудь BindingList'ом ну или что то подобное бы использовал, это ближе к C#, чем цикл. Да вот и саму гриду ты не так готовишь, опять же на биндингах было бы проще, создав класс/структуру с необходимыми полями. Пусть лучше шарписты что подскажут. Они лучше тут шарят.
Сообщение отредактировано: KILLER -
Цитата KILLER @
Ну у тебя Сшный подход к задаче на C#, я этот код уже видел на С++ в разделе С++.

да эт точно , я и не отрицаю у меня линейное мышление , я же чукча , что вижу то и пою (на полном серьезе без сарказма)

Цитата KILLER @
Ну а так, ты по сути не пользуешься плюшками C#, я бы наверное не делал всех этих циклов с добавлением рядков/колонок, обошолся каким нибудь BindingList'ом ну или что то подобное бы использовал, это ближе к C#, чем цикл

хоть маленький намек , или направление куда двигатся ,
дело в том что я начинал уже смотреть в сторону " Тип BindingList<T> предоставляет следующие члены."
только как обойти Т ему же надо задать тип , а в моем случае надо динамически разобрать динамический массив байтов и все это не зная заранее какие будут типы и размеры у полей

вот такие пироги , я уже не на первом форуме по десятому кругу объясняю , но наверное с меня плохой объяснялщик , или не кто наверное не разбирал байтовые массивы (без обид это я так к слову )

Цитата KILLER @
Пусть лучше шарписты что подскажут. Они лучше тут шарят.

их тут очень мало наверно , человек когда дорастает до определенного уровня , то уже не лазит по форумам, и тем более не отвечает на глупые вопросы, потому что думает "вот я же выучился познал таинство и мастерство кодера , и теперь эту тайну ни кому не скажу" :)

вот такие пироги (прошу прощения за свой Гарвардский )

Добавлено
Цитата KILLER @
Да вот и саму гриду ты не так готовишь, опять же на биндингах было бы проще, создав класс/структуру с необходимыми полями.

вот это я сейчас как раз и делаю , вот только что такое "биндингах "
Цитата kms @
только как обойти Т ему же надо задать тип , а в моем случае надо динамически разобрать динамический массив байтов и все это не зная заранее какие будут типы и размеры у полей

Создай структуру с типами колонок. У тебя есть БД, в ней есть таблицы - ты работаешь с этой БД - ты не знаешь типов данных и какие у нее колонки? Если так, значит БД не твоя, и ты пишешь всего лишь юзер интерфейс для работы с ее таблицами. Как ты узнал какие таблицы там есть ? Вообще странный подход.
В любом случае типы в таблице можно узнать. Далее создаешь свою структуру с нужными типами данных, передаешь ее в BindingList, связываешь его с таблицей, все. Примеры использования BindingList со всякими BindingSource и т.д. в интере есть полно.
Цитата kms @
вот это я сейчас как раз и делаю , вот только что такое "биндингах "

Ок, вот я накидал простенький пример, как примерно оно должно выглядеть у тебя, или по крайней мере как бы делал я:
Прикреплённый файлПрикреплённый файлBindings.zip (15,96 Кбайт, скачиваний: 2)

_data - это массив твоих структур, куда ты будешь вычитывать из БД инфу.

Добавлено
Так же, если внимательно посмотришь, то не увидишь где я гриде добавляю колонки. Они через DataSource автоматически берутся из типа ManGridData
Цитата KILLER @
Создай структуру с типами колонок.

не возможно , я не знаю типы колонок до момента выполнения запроса,

Цитата KILLER @
У тебя есть БД, в ней есть таблицы - ты работаешь с этой БД - ты не знаешь типов данных и какие у нее колонки?

я делаю клиентскую часть к СУБД HyTech как например "MySQL Workbench" или вообще универсальное средство "EMS SQL Management Studio"
т.е. я делаю менеджер управления не одной базы данных а клиентскую часть СУБД HyTech для того чтобы иметь доступ к самому ядру сервера СУБД чтобы создавать БазыДанных, таблицы и др.объекты СУБД, чтобы управлять не только БД а и самой СУБД, чтобы делать разные запросы на выборку не только с одной таблицы а настоящие запросы , HyTech поддерживает SQL-89 , вообщем все по настоящему все по взрослому

Добавлено
Цитата KILLER @
Ок, вот я накидал простенький пример, как примерно оно должно выглядеть у тебя, или по крайней мере как бы делал я:
Прикреплённый файлBindings.zip (15,96 Кбайт, скачиваний: 2)

ОК спасибо , посмотрел пример , но к сожалению это статика ,
как создавать типы динамически , во время выполнения программы , после получения ответа на SQL-запрос ?

Добавлено
если бы как то не так
ExpandedWrap disabled
    public class ManGridData
        {
            public string Name { get; set; }
            public string City { get; set; }
            public string Street { get; set; }
     
            public string Billing { get; set; }
            public string Description { get; set; }
        }


а как бы в цикле если бы можно было задать вот абстрактный такой код ,
ExpandedWrap disabled
    byte[]
     
    // pCol - кол-во колонок результата  
     
    bufOut = new byte[(int)wBufSize];   // буфер для результата
     
    public class ClasPriemData ;// создать новый класс приемник под буфер
     
     for (int j=0; j< pCol; j++) // задаем поля класса приемника
    {
     ClasPriemData.ДобавитьНовоеПолеСтипом = infCol[j].type ;  
    }
     
    ClasPriemData = bufOut ; // одним махом закидываем весь буфер в класс-приемник


если бы так сделать это бфло бы волшебство фантастика

Добавлено
Цитата KILLER @
Так же, если внимательно посмотришь, то не увидишь где я гриде добавляю колонки. Они через DataSource автоматически берутся из типа ManGridData

эт я понял
ExpandedWrap disabled
    for (int i = 0; i < 50; ++i)
                {
                    ManGridData dt = new ManGridData();
                    dt.Name = "KILLER_" + i.ToString();
                    dt.Street = "Beverly Hills_" + i.ToString();
                    dt.City = "USA_" + i.ToString();
                    dt.Billing = "12345567788_" + i.ToString();
                    dt.Description = "Description_" + i.ToString();
     
                    _data.Add(dt);
                }
Сообщение отредактировано: kms -
Цитата kms @
их тут очень мало наверно , человек когда дорастает до определенного уровня , то уже не лазит по форумам, и тем более не отвечает на глупые вопросы, потому что думает "вот я же выучился познал таинство и мастерство кодера , и теперь эту тайну ни кому не скажу" :)

не шарписты как правило это молодняк, который сразу начал с C#, так что они просто не знают как быть в твоём случае ;)
Гавнокод -> рефакторинг -> гавнокод -> рефакторинг => супер-пупер демо :D
Супер-пупер демо "Программирование БД в действии" https://github.com/Cfon/MFCSQLite3Demo заходи смотри не тупи :D
1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
0 пользователей:


[ Script Execution time: 0,2034 ]   [ 22 queries used ]   [ Generated: 26.04.17, 15:50 GMT ]