Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.142.197.212] |
|
Страницы: (2) [1] 2 все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
Уважаемые форумчане , помогите с вопросом по использованию функций DLL(написана на Си) ,
проект очень простенький все на одной кнопочке и пару текстЕдитов весь код линейный в одной кнопке MainWindow.xaml.cs Скрытый текст 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);// Чтение результатов помогите пожалуйста разобраться с вопросом ошибку выдает такую Помощник отладки управляемого кода "PInvokeStackImbalance" обнаружил неполадку в " \bin\x86\Debug\ComHyTech.vshost.exe". Дополнительные сведения: Вызов функции PInvoke "ComHyTech!ComHyTech.MainWindow::hcSqlReadResults" разбалансировал стек. Вероятно, это вызвано тем, что управляемая сигнатура PInvoke не совпадает с неуправляемой целевой сигнатурой. Убедитесь, что соглашение о вызовах и параметры сигнатуры PInvoke совпадают с неуправляемой целевой сигнатурой. Добавлено проект https://yadi.sk/d/Y5YtmjjK3GrG6f |
Сообщ.
#2
,
|
|
|
Помогите вопрос очень актуален
|
Сообщ.
#3
,
|
|
|
Начать имеет смысл с явного задания в C#-сигнатуре того calling convention, который использует функция hcSqlReadResults в DLL
https://msdn.microsoft.com/en-us/library/sy...(v=vs.110).aspx |
Сообщ.
#4
,
|
|
|
Всем спасибо вопрос решен
|
Сообщ.
#5
,
|
|
|
Цитата Mr.Delphist @ Начать имеет смысл с явного задания в C#-сигнатуре того calling convention, который использует функция hcSqlReadResults в DLL извините как то получилось что не прочитал Ваше сообщение, теперь начал разбиратся и немного не понял вот эти слова Цитата Mr.Delphist @ C#-сигнатуре того calling convention, который использует функция hcSqlReadResults в DLL извините не очень силен поетому и переспрашиваю, что это значит и как это моно реализовать применительно к моему случаю на данный момент дошел вот до этого если будет интересно , https://github.com/vovakms/dbms-HyTech_edition_CSharp код закончен , только надо теперь оптимизировать и дорабатывать нюансы |
Сообщ.
#6
,
|
|
|
У каждой функции есть, кроме параметров и результата, так называемое "соглашение о вызовах". Оно определяет, в числе прочего, как используется стэк, кто ответственен за его менеджмент, в каком формате передаются параметры и результат. Поэтому попытка использовать функцию с иным calling convention, нежели с которым она скомпилирована, приведёт к ошибке (функция будет искать не там свои параметры, класть результат не туда, память будет либо утекать, либо дербаниться чужая).
Например, сишные функции по умолчанию предполагают cdecl, однако WinAPI ставит в качестве стандарта stdcall. Подробнее: https://msdn.microsoft.com/en-us/library/984x0h58.aspx |
Сообщ.
#7
,
|
|
|
Цитата kms @ Уважаемые форумчане , помогите с вопросом по использованию функций DLL(написана на Си) , проект очень простенький все на одной кнопочке и пару текстЕдитов весь код линейный в одной кнопке Я же тебе еще в соседней теме, в этом разделе дал ссылки на нужную литературу. Если ты будешь вот так эспортировать каждую функцию - то выйдет громоздко, не красиво и не в ООП стиле. Я тебе предлагал написать класс обертку над этими функциями, потом его экспортировать в DLL class DLL_EXPORT MyClass {...} Где DLL_EXPORT - это макрос, который в зависимости от режима будет равен либо __declspec(dllexport), либо __declspec(dllimport) Потом на С++/CLI набросать точно такой же класс, но который будет оберткой над этим классом: class MyWrapper { private: MyClass m_myClass; }; Методы у него будут называться точно так же, по сути это внешне копия С++ класса, но в качестве реализации ты будешь просто вызывать методы своего С++ сного класса. А дальше, уже то, что у тебя получится на С++/CLI ты без всяких заморочек уже можешь использовать в C# |
Сообщ.
#8
,
|
|
|
Цитата KILLER @ Я же тебе еще в соседней теме, в этом разделе дал ссылки на нужную литературу. Если ты будешь вот так эспортировать каждую функцию - то выйдет громоздко, не красиво и не в ООП стиле. Я тебе предлагал написать класс обертку над этими функциями, потом его экспортировать в DLL Не-не-не, батенька, чтобы начать бегать и прыгать, надо научиться ходить. Давайте автор сперва твёрдо разберётся с экспортированием отдельных функций, а затем уже можно и классы попробовать экспортировать (не забывая про манглинг имён, ABI и прочие радости). |
Сообщ.
#9
,
|
|
|
Цитата 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, а так как гость если вы в курсе как подскажите , или там только зарегиным надо быть чтобы редактировать ???? |
Сообщ.
#10
,
|
|
|
Ну у тебя Сшный подход к задаче на C#, я этот код уже видел на С++ в разделе С++. Просто у тебя вообще концептуально не верный подход конкретно на C#, поэтому и говорю, проще все вот эти потроха от базы спрятать в С++ класс. Ну а так, ты по сути не пользуешься плюшками C#, я бы наверное не делал всех этих циклов с добавлением рядков/колонок, обошолся каким нибудь BindingList'ом ну или что то подобное бы использовал, это ближе к C#, чем цикл. Да вот и саму гриду ты не так готовишь, опять же на биндингах было бы проще, создав класс/структуру с необходимыми полями. Пусть лучше шарписты что подскажут. Они лучше тут шарят.
|
Сообщ.
#11
,
|
|
|
Цитата KILLER @ Ну у тебя Сшный подход к задаче на C#, я этот код уже видел на С++ в разделе С++. да эт точно , я и не отрицаю у меня линейное мышление , я же чукча , что вижу то и пою (на полном серьезе без сарказма) Цитата KILLER @ Ну а так, ты по сути не пользуешься плюшками C#, я бы наверное не делал всех этих циклов с добавлением рядков/колонок, обошолся каким нибудь BindingList'ом ну или что то подобное бы использовал, это ближе к C#, чем цикл хоть маленький намек , или направление куда двигатся , дело в том что я начинал уже смотреть в сторону " Тип BindingList<T> предоставляет следующие члены." только как обойти Т ему же надо задать тип , а в моем случае надо динамически разобрать динамический массив байтов и все это не зная заранее какие будут типы и размеры у полей вот такие пироги , я уже не на первом форуме по десятому кругу объясняю , но наверное с меня плохой объяснялщик , или не кто наверное не разбирал байтовые массивы (без обид это я так к слову ) Цитата KILLER @ Пусть лучше шарписты что подскажут. Они лучше тут шарят. их тут очень мало наверно , человек когда дорастает до определенного уровня , то уже не лазит по форумам, и тем более не отвечает на глупые вопросы, потому что думает "вот я же выучился познал таинство и мастерство кодера , и теперь эту тайну ни кому не скажу" вот такие пироги (прошу прощения за свой Гарвардский ) Добавлено Цитата KILLER @ Да вот и саму гриду ты не так готовишь, опять же на биндингах было бы проще, создав класс/структуру с необходимыми полями. вот это я сейчас как раз и делаю , вот только что такое "биндингах " |
Сообщ.
#12
,
|
|
|
Цитата kms @ только как обойти Т ему же надо задать тип , а в моем случае надо динамически разобрать динамический массив байтов и все это не зная заранее какие будут типы и размеры у полей Создай структуру с типами колонок. У тебя есть БД, в ней есть таблицы - ты работаешь с этой БД - ты не знаешь типов данных и какие у нее колонки? Если так, значит БД не твоя, и ты пишешь всего лишь юзер интерфейс для работы с ее таблицами. Как ты узнал какие таблицы там есть ? Вообще странный подход. В любом случае типы в таблице можно узнать. Далее создаешь свою структуру с нужными типами данных, передаешь ее в BindingList, связываешь его с таблицей, все. Примеры использования BindingList со всякими BindingSource и т.д. в интере есть полно. |
Сообщ.
#13
,
|
|
|
Цитата kms @ вот это я сейчас как раз и делаю , вот только что такое "биндингах " Ок, вот я накидал простенький пример, как примерно оно должно выглядеть у тебя, или по крайней мере как бы делал я: Прикреплённый файлBindings.zip (15,96 Кбайт, скачиваний: 111) _data - это массив твоих структур, куда ты будешь вычитывать из БД инфу. Добавлено Так же, если внимательно посмотришь, то не увидишь где я гриде добавляю колонки. Они через DataSource автоматически берутся из типа ManGridData |
Сообщ.
#14
,
|
|
|
Цитата KILLER @ Создай структуру с типами колонок. не возможно , я не знаю типы колонок до момента выполнения запроса, Цитата KILLER @ У тебя есть БД, в ней есть таблицы - ты работаешь с этой БД - ты не знаешь типов данных и какие у нее колонки? я делаю клиентскую часть к СУБД HyTech как например "MySQL Workbench" или вообще универсальное средство "EMS SQL Management Studio" т.е. я делаю менеджер управления не одной базы данных а клиентскую часть СУБД HyTech для того чтобы иметь доступ к самому ядру сервера СУБД чтобы создавать БазыДанных, таблицы и др.объекты СУБД, чтобы управлять не только БД а и самой СУБД, чтобы делать разные запросы на выборку не только с одной таблицы а настоящие запросы , HyTech поддерживает SQL-89 , вообщем все по настоящему все по взрослому Добавлено Цитата KILLER @ Ок, вот я накидал простенький пример, как примерно оно должно выглядеть у тебя, или по крайней мере как бы делал я: Прикреплённый файлBindings.zip (15,96 Кбайт, скачиваний: 2) ОК спасибо , посмотрел пример , но к сожалению это статика , как создавать типы динамически , во время выполнения программы , после получения ответа на SQL-запрос ? Добавлено если бы как то не так 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; } } а как бы в цикле если бы можно было задать вот абстрактный такой код , 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 эт я понял 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); } |
Сообщ.
#15
,
|
|
|
Цитата kms @ их тут очень мало наверно , человек когда дорастает до определенного уровня , то уже не лазит по форумам, и тем более не отвечает на глупые вопросы, потому что думает "вот я же выучился познал таинство и мастерство кодера , и теперь эту тайну ни кому не скажу" не шарписты как правило это молодняк, который сразу начал с C#, так что они просто не знают как быть в твоём случае |