Bad dll calling convention error 49

Q. Excel keeps throwing the following error, whenever my addin is loaded (Runtime Error 49, Bad DLL calling convention) The dialog starts to pop up everytime with no indication of where the error ...

In my case this was «caused» by an excessive use of the continue character _ in a single if conditional

I had already recompiled, checked all return codes, moved modules around ,restarted excel , restarted my computer, copied the code to a brand new Excel spread-sheet, I read this article and the bit about return codes made me think about how many returns can be in an if statement

I had this

    If CompressIntoOneLineON(rg1, rgstart, rgend) or _
       CompressIntoOneLineOS(rg1, rgstart, rgend) or _
       CompressIntoOneLineOGN(rg1, rgstart, rgend) or _
       CompressIntoOneLineOGS(rg1, rgstart, rgend) or _
       CompressIntoOneLineGO(rg1, rgstart, rgend) Then
       <code>
    End If

I was getting the error when the subroutine containing this code exited
So I changed to this

matched = True
If CompressIntoOneLineON(rg1, rgstart, rgend) Then
ElseIf CompressIntoOneLineOS(rg1, rgstart, rgend) Then
ElseIf CompressIntoOneLineOGN(rg1, rgstart, rgend) Then
ElseIf CompressIntoOneLineOGS(rg1, rgstart, rgend) Then
ElseIf CompressIntoOneLineGO(rg1, rgstart, rgend) Then
Else
  matched = False
End If
if matched then
  <code>

and the error went away

Icon Ex Номер ошибки: Ошибка во время выполнения 49
Название ошибки: Bad DLL calling convention
Описание ошибки: Arguments passed to a dynamic-link library (DLL) must exactly match those expected by the routine. Calling conventions deal with number, type, and order of arguments.
Разработчик: Microsoft Corporation
Программное обеспечение: Windows Operating System
Относится к: Windows XP, Vista, 7, 8, 10, 11

«Bad DLL calling convention» Введение

Люди часто предпочитают ссылаться на «Bad DLL calling convention» как на «ошибку времени выполнения», также известную как программная ошибка. Разработчики программного обеспечения, такие как Microsoft Corporation, обычно принимают Windows Operating System через несколько уровней отладки, чтобы сорвать эти ошибки перед выпуском для общественности. Как и во всем в жизни, иногда такие проблемы, как ошибка 49, упускаются из виду.

Некоторые люди могут столкнуться с сообщением «Arguments passed to a dynamic-link library (DLL) must exactly match those expected by the routine. Calling conventions deal with number, type, and order of arguments.» во время работы программного обеспечения. Когда это происходит, конечные пользователи программного обеспечения могут сообщить Microsoft Corporation о существовании ошибки 49 ошибок. Microsoft Corporation вернется к коду и исправит его, а затем сделает обновление доступным для загрузки. Таким образом при выполнении обновления программного обеспечения Windows Operating System, он будет содержать исправление для устранения проблем, таких как ошибка 49.

Почему возникает ошибка времени выполнения 49?

Ошибки выполнения при запуске Windows Operating System — это когда вы, скорее всего, столкнетесь с «Bad DLL calling convention». Рассмотрим распространенные причины ошибок ошибки 49 во время выполнения:

Ошибка 49 Crash — Ошибка 49 остановит компьютер от выполнения обычной программной операции. Это происходит много, когда продукт (Windows Operating System) или компьютер не может обрабатывать уникальные входные данные.

Утечка памяти «Bad DLL calling convention» — если есть утечка памяти в Windows Operating System, это может привести к тому, что ОС будет выглядеть вялой. Критическими проблемами, связанными с этим, могут быть отсутствие девыделения памяти или подключение к плохому коду, такому как бесконечные циклы.

Ошибка 49 Logic Error — логическая ошибка Windows Operating System возникает, когда она производит неправильный вывод, несмотря на то, что пользователь предоставляет правильный ввод. Виновником в этом случае обычно является недостаток в исходном коде Microsoft Corporation, который неправильно обрабатывает ввод.

Как правило, ошибки Bad DLL calling convention вызваны повреждением или отсутствием файла связанного Windows Operating System, а иногда — заражением вредоносным ПО. Как правило, любую проблему, связанную с файлом Microsoft Corporation, можно решить посредством замены файла на новую копию. В качестве последней меры мы рекомендуем использовать очиститель реестра для исправления всех недопустимых Bad DLL calling convention, расширений файлов Microsoft Corporation и других ссылок на пути к файлам, по причине которых может возникать сообщение об ошибке.

Распространенные сообщения об ошибках в Bad DLL calling convention

Наиболее распространенные ошибки Bad DLL calling convention, которые могут возникнуть на компьютере под управлением Windows, перечислены ниже:

  • «Ошибка в приложении: Bad DLL calling convention»
  • «Недопустимая программа Win32: Bad DLL calling convention»
  • «Возникла ошибка в приложении Bad DLL calling convention. Приложение будет закрыто. Приносим извинения за неудобства.»
  • «Файл Bad DLL calling convention не найден.»
  • «Отсутствует файл Bad DLL calling convention.»
  • «Ошибка запуска программы: Bad DLL calling convention.»
  • «Bad DLL calling convention не работает. «
  • «Bad DLL calling convention остановлен. «
  • «Неверный путь к приложению: Bad DLL calling convention.»

Ошибки Bad DLL calling convention EXE возникают во время установки Windows Operating System, при запуске приложений, связанных с Bad DLL calling convention (Windows Operating System), во время запуска или завершения работы или во время установки ОС Windows. Документирование проблем Bad DLL calling convention в Windows Operating System является ключевым для определения причины проблем с электронной Windows и сообщения о них в Microsoft Corporation.

Источники проблем Bad DLL calling convention

Проблемы Windows Operating System и Bad DLL calling convention возникают из отсутствующих или поврежденных файлов, недействительных записей реестра Windows и вредоносных инфекций.

В частности, проблемы Bad DLL calling convention возникают через:

  • Поврежденная или недопустимая запись реестра Bad DLL calling convention.
  • Зазаражение вредоносными программами повредил файл Bad DLL calling convention.
  • Bad DLL calling convention ошибочно удален или злонамеренно программным обеспечением, не связанным с приложением Windows Operating System.
  • Другое программное обеспечение, конфликтующее с Windows Operating System, Bad DLL calling convention или общими ссылками.
  • Windows Operating System (Bad DLL calling convention) поврежден во время загрузки или установки.

Продукт Solvusoft

Загрузка
WinThruster 2022 — Проверьте свой компьютер на наличие ошибок.

Совместима с Windows 2000, XP, Vista, 7, 8, 10 и 11

Установить необязательные продукты — WinThruster (Solvusoft) | Лицензия | Политика защиты личных сведений | Условия | Удаление

Содержание

  1. Как исправить ошибку во время выполнения 49
  2. «Bad DLL calling convention» Введение
  3. Почему возникает ошибка времени выполнения 49?
  4. Распространенные сообщения об ошибках в Bad DLL calling convention
  5. Источники проблем Bad DLL calling convention
  6. Недопустимое соглашение о вызовах библиотеки DLL (ошибка 49)
  7. Поддержка и обратная связь
  8. Run time error 49 word bad dll calling convention
  9. How to fix the Runtime Code 49 Bad DLL calling convention
  10. Bad DLL calling convention (Error 49)
  11. Support and feedback

Как исправить ошибку во время выполнения 49

Номер ошибки: Ошибка во время выполнения 49
Название ошибки: Bad DLL calling convention
Описание ошибки: Arguments passed to a dynamic-link library (DLL) must exactly match those expected by the routine. Calling conventions deal with number, type, and order of arguments.
Разработчик: Microsoft Corporation
Программное обеспечение: Windows Operating System
Относится к: Windows XP, Vista, 7, 8, 10, 11

«Bad DLL calling convention» Введение

Люди часто предпочитают ссылаться на «Bad DLL calling convention» как на «ошибку времени выполнения», также известную как программная ошибка. Разработчики программного обеспечения, такие как Microsoft Corporation, обычно принимают Windows Operating System через несколько уровней отладки, чтобы сорвать эти ошибки перед выпуском для общественности. Как и во всем в жизни, иногда такие проблемы, как ошибка 49, упускаются из виду.

Некоторые люди могут столкнуться с сообщением «Arguments passed to a dynamic-link library (DLL) must exactly match those expected by the routine. Calling conventions deal with number, type, and order of arguments.» во время работы программного обеспечения. Когда это происходит, конечные пользователи программного обеспечения могут сообщить Microsoft Corporation о существовании ошибки 49 ошибок. Microsoft Corporation вернется к коду и исправит его, а затем сделает обновление доступным для загрузки. Таким образом при выполнении обновления программного обеспечения Windows Operating System, он будет содержать исправление для устранения проблем, таких как ошибка 49.

Почему возникает ошибка времени выполнения 49?

Ошибки выполнения при запуске Windows Operating System — это когда вы, скорее всего, столкнетесь с «Bad DLL calling convention». Рассмотрим распространенные причины ошибок ошибки 49 во время выполнения:

Ошибка 49 Crash — Ошибка 49 остановит компьютер от выполнения обычной программной операции. Это происходит много, когда продукт (Windows Operating System) или компьютер не может обрабатывать уникальные входные данные.

Утечка памяти «Bad DLL calling convention» — если есть утечка памяти в Windows Operating System, это может привести к тому, что ОС будет выглядеть вялой. Критическими проблемами, связанными с этим, могут быть отсутствие девыделения памяти или подключение к плохому коду, такому как бесконечные циклы.

Ошибка 49 Logic Error — логическая ошибка Windows Operating System возникает, когда она производит неправильный вывод, несмотря на то, что пользователь предоставляет правильный ввод. Виновником в этом случае обычно является недостаток в исходном коде Microsoft Corporation, который неправильно обрабатывает ввод.

Как правило, ошибки Bad DLL calling convention вызваны повреждением или отсутствием файла связанного Windows Operating System, а иногда — заражением вредоносным ПО. Как правило, любую проблему, связанную с файлом Microsoft Corporation, можно решить посредством замены файла на новую копию. В качестве последней меры мы рекомендуем использовать очиститель реестра для исправления всех недопустимых Bad DLL calling convention, расширений файлов Microsoft Corporation и других ссылок на пути к файлам, по причине которых может возникать сообщение об ошибке.

Распространенные сообщения об ошибках в Bad DLL calling convention

Наиболее распространенные ошибки Bad DLL calling convention, которые могут возникнуть на компьютере под управлением Windows, перечислены ниже:

  • «Ошибка в приложении: Bad DLL calling convention»
  • «Недопустимая программа Win32: Bad DLL calling convention»
  • «Возникла ошибка в приложении Bad DLL calling convention. Приложение будет закрыто. Приносим извинения за неудобства.»
  • «Файл Bad DLL calling convention не найден.»
  • «Отсутствует файл Bad DLL calling convention.»
  • «Ошибка запуска программы: Bad DLL calling convention.»
  • «Bad DLL calling convention не работает. «
  • «Bad DLL calling convention остановлен. «
  • «Неверный путь к приложению: Bad DLL calling convention.»

Ошибки Bad DLL calling convention EXE возникают во время установки Windows Operating System, при запуске приложений, связанных с Bad DLL calling convention (Windows Operating System), во время запуска или завершения работы или во время установки ОС Windows. Документирование проблем Bad DLL calling convention в Windows Operating System является ключевым для определения причины проблем с электронной Windows и сообщения о них в Microsoft Corporation.

Источники проблем Bad DLL calling convention

Проблемы Windows Operating System и Bad DLL calling convention возникают из отсутствующих или поврежденных файлов, недействительных записей реестра Windows и вредоносных инфекций.

В частности, проблемы Bad DLL calling convention возникают через:

  • Поврежденная или недопустимая запись реестра Bad DLL calling convention.
  • Зазаражение вредоносными программами повредил файл Bad DLL calling convention.
  • Bad DLL calling convention ошибочно удален или злонамеренно программным обеспечением, не связанным с приложением Windows Operating System.
  • Другое программное обеспечение, конфликтующее с Windows Operating System, Bad DLL calling convention или общими ссылками.
  • Windows Operating System (Bad DLL calling convention) поврежден во время загрузки или установки.

Совместима с Windows 2000, XP, Vista, 7, 8, 10 и 11

Источник

Недопустимое соглашение о вызовах библиотеки DLL (ошибка 49)

Аргументы, передаваемые в библиотеку динамической компоновки (DLL) или процедуру ресурсов кода Macintosh, должны в точности соответствовать всем требованиям процедуры. Соглашения о вызове действуют в отношении числа, типа и порядка аргументов. Эта ошибка имеет следующие причины и решения:

Программа вызывает процедуру в DLL (Windows) или ресурсе кода (Macintosh) и передает им аргументы неверного типа. Убедитесь, что тип аргументов соответствует заданному в объявлении процедуры, которую вы вызываете.

Программа вызывает процедуру в DLL (Windows) или ресурсе кода (Macintosh) и передает им неверное число аргументов. Убедитесь, что число аргументов соответствует заданному в объявлении процедуры, которую вы вызываете.

Программа вызывает процедуру в DLL с нарушением соглашения о стандартном вызове. Если процедура DLL требует указывать аргументы по значению, убедитесь, что в объявлении процедуры для этих аргументов определен атрибут ByVal.

Оператор Declare для библиотеки DLL Windows включает ключевое слово CDecl. Ключевое слово CDecl применяется только на платформе Macintosh.

Для получения дополнительной информации выберите необходимый элемент и нажмите клавишу F1 (для Windows) или HELP (для Macintosh).

Поддержка и обратная связь

Есть вопросы или отзывы, касающиеся Office VBA или этой статьи? Руководство по другим способам получения поддержки и отправки отзывов см. в статье Поддержка Office VBA и обратная связь.

Источник

Run time error 49 word bad dll calling convention

Здесь обсуждаются вопросы по языку Visual Basic 1-6 (а так же по схожим языкам, как, например, PowerBASIC).
Вопросы по Visual Basic .NET (это который входит в состав Visual Studio 2002/2003/2005/2008+, для тех, кто не в курсе) обсуждаются в разделе .NET.

Обратите внимание:
1. Прежде чем начать новую тему или отправить сообщение, убедитесь, что Вы не нарушаете правил форума!
2. Обязательно воспользуйтесь поиском. Возможно, Ваш вопрос уже обсуждали. Полезные ссылки приведены ниже.
3. Темы с просьбой выполнить какую-либо работу за автора в этом разделе не обсуждаются. Студенты, вам сюда: ПОМОЩЬ СТУДЕНТАМ !
4. Используйте теги [ code=vba ] . текст программы. [ /code ] для выделения текста программы подсветкой.
5. Помните, здесь телепатов нет. Формулируйте свой вопрос максимально грамотно и чётко: Как правильно задавать вопросы
6. Запрещено отвечать в темы месячной (и более) давности, без веских на то причин.

Полезные ссылки:
FAQ Сайта FAQ Раздела Кладовка Наши Исходники API-Guide Поиск по Разделу MSDN Library Online Google
Ваше мнение о модераторах: SCINER, B.V.

Источник

How to fix the Runtime Code 49 Bad DLL calling convention

This article features error number Code 49, commonly known as Bad DLL calling convention described as Arguments passed to a dynamic-link library (DLL) must exactly match those expected by the routine. Calling conventions deal with number, type, and order of arguments.

Error Information

Error name: Bad DLL calling convention
Error number: Code 49
Description: Arguments passed to a dynamic-link library (DLL) must exactly match those expected by the routine. Calling conventions deal with number, type, and order of arguments.
Software: Windows
Developer: Microsoft

This repair tool can fix common computer errors like BSODs, system freezes and crashes. It can replace missing operating system files and DLLs, remove malware and fix the damage caused by it, as well as optimize your PC for maximum performance.

About Runtime Code 49

Runtime Code 49 happens when Windows fails or crashes whilst it’s running, hence its name. It doesn’t necessarily mean that the code was corrupt in some way, but just that it did not work during its run-time. This kind of error will appear as an annoying notification on your screen unless handled and corrected. Here are symptoms, causes and ways to troubleshoot the problem.

Definitions (Beta)

Here we list some definitions for the words contained in your error, in an attempt to help you understand your problem. This is a work in progress, so sometimes we might define the word incorrectly, so feel free to skip this section!

  • Calling convention — A calling convention refers to the way a function transmits parameters to a called function and receives a return value from it.
  • Convention — A convention is a set of agreed, stipulated, or generally accepted norms
  • Conventions — A generic tag covering any accepted method of doing things, which could include naming, spacing, coding, commenting, etc.
  • Dll — A dynamic-link library DLL is a module that contains functions and data that can be used by another module application or DLL
  • Dynamic — Dynamic is a widely used term that, in general, describes a decision made by the program at run-time rather than at compile time.
  • Match — A programming concept about finding results based on some kind of search
  • Order — THIS TAG IS VAGUE
  • Link — A hyperlink is a reference to a document or a section that can be followed for retrieval using a navigation system that allows selecting emphasized content within an originating document.
  • Type — Types, and type systems, are used to enforce levels of abstraction in programs.
  • .dll — A dynamic-link library DLL is a module that contains functions and data that can be used by another module application or DLL
  • Number — A number is a mathematical object used to count, measure and label
Symptoms of Code 49 — Bad DLL calling convention

Runtime errors happen without warning. The error message can come up the screen anytime Windows is run. In fact, the error message or some other dialogue box can come up again and again if not addressed early on.

There may be instances of files deletion or new files appearing. Though this symptom is largely due to virus infection, it can be attributed as a symptom for runtime error, as virus infection is one of the causes for runtime error. User may also experience a sudden drop in internet connection speed, yet again, this is not always the case.

(Bad DLL calling convention) Repair Tool»/>
(For illustrative purposes only)

Causes of Bad DLL calling convention — Code 49

During software design, programmers code anticipating the occurrence of errors. However, there are no perfect designs, as errors can be expected even with the best program design. Glitches can happen during runtime if a certain error is not experienced and addressed during design and testing.

Runtime errors are generally caused by incompatible programs running at the same time. It may also occur because of memory problem, a bad graphics driver or virus infection. Whatever the case may be, the problem must be resolved immediately to avoid further problems. Here are ways to remedy the error.

Repair Methods

Runtime errors may be annoying and persistent, but it is not totally hopeless, repairs are available. Here are ways to do it.

If a repair method works for you, please click the upvote button to the left of the answer, this will let other users know which repair method is currently working the best.

Источник

Bad DLL calling convention (Error 49)

Arguments passed to a dynamic-link library (DLL) or Macintosh code resource routine must exactly match those expected by the routine. Calling conventions deal with number, type, and order of arguments. This error has the following causes and solutions:

Your program is calling a routine in a DLL (in Windows) or a code resource (on the Macintosh) that’s being passed the wrong type of arguments. Make sure all argument types agree with those specified in the declaration of the routine you are calling.

Your program is calling a routine in a DLL (in Windows) or a code resource (on the Macintosh) that’s being passed the wrong number of arguments. Make sure you are passing the same number of arguments indicated in the declaration of the routine you are calling.

Your program is calling a routine in a DLL, but isn’t using the StdCall calling convention. If the DLL routine expects arguments by value, then make sure ByVal is specified for those arguments in the declaration for the routine.

Your Declare statement for a Windows DLL includes CDecl. The CDecl keyword applies only to the Macintosh.

For additional information, select the item in question and press F1 (in Windows) or HELP (on the Macintosh).

Support and feedback

Have questions or feedback about Office VBA or this documentation? Please see Office VBA support and feedback for guidance about the ways you can receive support and provide feedback.

Источник

03.08.2013, 22:51. Показов 52535. Ответов 18


В данной статье описаны основные способы работы с DLL в языке программирования Visual Basic. Рассчитана прежде всего на начинающих программистов. Она поможет заинтересованному читателю ответить на ряд вопросов: что такое DLL, зачем его используют, как его правильно использовать и создавать.

Основы

Итак, что же такое DLL? Этой английской аббревиатурой словосочетания Dynamic-Link Library, что переводится как «динамически подключая библиотека», называют в операционных системах семейства Microsoft Windows динамические библиотеки, содержащие процедуры и функции, которые могут многократно использоваться различными программными приложениями.

Ранние версии Windows работали в условиях жёсткого ограничения памяти, а потому использование DLL должно было позволить более активно использовать её, ведь один экземпляр DLL, загруженный в память, может использоваться сразу несколькими программами. Однако существенных преимуществ полностью получить не удалось. Причиной является такое явление, как DLL Hell («DLL ад») — несколько программ работают с одинаковой библиотекой, однако с разными не полностью совместимыми версиями. Это приводило к большому количеству ошибок. Сейчас в Windows используется технология SxS, разрешающая параллельное использование разные версий библиотеки, что иногда сводит на нет её главное преимущество.

Тем не менее, DLL (к этому понятию также относят библиотеки ActiveX и драйверы) активно используются при разработке ПО.

Но в каких же случаях лучше использовать модули, а в каких DLL? Во-первых, модули, подключаемые к проекту, должны быть написаны на том языке, с которым работает среда разработки. DLL могут быть написаны на другом языке, хранятся они в уже откомпилированном виде. Во-вторых, использование DLL позволяет экономить память в том случае, если ею пользуются две или более программ одновременно (точнее, при использовании одной и той же версии). В-третьих, если функции не будут использоваться другими программами, то нет смысла создавать DLL. Тоже самое можно сказать про те случаи, когда нужно просто разбить для удобства большой код по модулям — удобнее работать с ними в одном проекте.

Соглашения вызова

Говоря о DLL как о библиотеках подпрограмм, следует рассказать о соглашения вызова — это часть интерфейса приложения, которая регламентирует технические особенности вызова подпрограммы, передачи параметров, возврата из неё, передача результата в основную программу. Говоря простым языком — разные стандарты использования подпрограмм (функций и процедур).

Например, это расположения параметров подпрограммы: они могут быть в стеке или в регистрах. Различие существенное, от того-то эти соглашения не совместимы и нужно знать, какие используются в той или иной библиотеке.

Существует немало разных соглашений, но из них обратим внимание на stdcall и cdecl. Первый используют библиотеки WinAPI функций. Второй же пригодиться нам для использования функций, написанных на языке Си (cdecl — C Declaration). В обоих соглашениях аргументы передаются через стек, справа налево. Но в stdcall очистку стека производит вызываемая подпрограмма, а в cdecl — вызывающая программа.

Если что-то не поняли — не спешите ломать голову этими соглашениями, ведь для полного понимания работы с ними вам нужно знание основ Ассемблера. Не знаете? Вернетесь ещё к ним потом.
Внимание мы уделим stdcall и cdecl. Большинство библиотек у вас будут работать и с этим.

Использование

Каким же образом использовать DLL? Как воспользоваться функциями из них? Для этого их нужно подключить к программе. Различают два способа подключения: статический и динамический.

Статический. При использовании DLL загружается в память сразу при запуске программы, а выгружаются лишь при завершении работы программы. Преимущества: возможность вызова любой функции из библиотеки в любое время. Недостатки: нерациональное использование памяти в том случае, если какие-либо функции и процедуры из неё используются лишь 1 раз за всё время работы. Ведь она будет всё время в памяти, хотя логичнее её от туда выгрузить за ненадобностью.

Динамический. Загрузить и выгрузить DLL можно в любое время при работе программы. Преимущества: экономное использование памяти в тех случаях, когда функция используется один раз за всё время работы программы, после чего они уже не нужны. Недостатки: большее, по сравнению со статическим подключением, количество кода.

Статическое подключение

При данном способе подключения нужные функции объявляют в разделе деклараций:

Visual Basic
1
2
Private Declare Function название_функции Lib "имя_библиотеки" Alias "название_функции_в_библиотеке"
(ByVal параметр_1 As тип_параметра, ..., ByVal параметр_n As тип_параметра) As тип_функции

Здесь:
Declare — ключевое слово, обозначающее, что дальше следует объявление функции из библиотеки
название_функции — название функции из библиотеки, которое будет использоваться у вас в программе. Может отличаться от названия функции в самой библиотеке (см. Alias)
Lib «имя_библиотеки» — название подключаемой библиотеки. Она должна находиться в папке System32, либо вместе с исполняемым файлом
Alias «название_функции_в_библиотеке» — необязательный параметр. Используется в том случае, если имя объявляемой функции в программе отличается от имени функции в библиотеке.

Пример подключения:

Visual Basic
1
Private Declare Function Symma Lib "test.dll" Alias "Summ" (ByVal a As Integer, ByVal b As Integer) As Integer

В библиотеке функция сложения двух чисел называется Summ, а у нас Symma.
Используются подключенные таким образом функции точно так же, как и обычные. Например:

Visual Basic
1
2
c = Symma(a,b)
d = Symma(1,3)

Ну, это всё описываются библиотеки с stdcall. А как же cdecl? Ну, в VB есть ключевое слово cDecl, причём использоваться оно должно так:

Visual Basic
1
Private Declare Function название_функции cDecl Lib "название_библиотеки"...

Однако вероятно вы получите Bad DLL Calling Convention (Error 49). Точнее, ваша программа будет работать лишь в Native (машинном) коде, т.е. уже полностью откомпилированная. А в режиме отладки (P-код), как и в самой IDE — нет. Дальнейшая разработка программы будет очень осложнена.
Мда, вот они какие — недокументированные возможности! Может есть шанс подключать cdecl библиотеки с динамическим подключением?

Динамическое подключение

Как уже было сказано выше, при данном способе подключения библиотек кода будет намного больше.
Ну во-первых сразу скажу, что в Visual Basic нет возможности стандартными средствами подключать библиотеки динамическим способом.

Для этого нам нужно 3 WinAPI функции: LoadLibrary, GetProcAddress, FreeLibrary. Объявим их в разделе деклараций, а также 3 переменные, куда будем сохранять результаты:

Visual Basic
1
2
3
4
5
6
7
8
Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" _
(ByVal lpLibFileName As String) As Long
Private Declare Function GetProcAddress Lib "kernel32" _
(ByVal hModule As Long, ByVal lpProcName As String) As Long
Private Declare Function FreeLibrary Lib "kernel32" _
(ByVal hLibModule As Long) As Long
 
Dim handle As Long, address As Long, unload As Long

Как видите, используем мы эти функции из стандартной библиотеки kernel32.dll! Так что это статическое подключение, а значит как минимум эта библиотека у нас будет всегда в памяти.

Разберем подробнее эти функции, новые для нас. Как они работают, что делают и для чего нужны?

LoadLibrary

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

Единственный её параметр lpLibFileName (строковой тип) содержит путь либо имя подключаемой библиотеки.

Если функция завершается успешно, то она возвращает дескриптор модуля (библиотеки). Если происходит ошибка — 0.

GetProcAddress

Эта функция извлекает адрес нужной процедуры или функции из DLL.

Имеет два параметра: hModule («хэндл», обычно целочисленный тип) и lpProcName (строковой тип). Первый параметр — дескриптор модуля. Получить его нам позволяет вышеописанная функция LoadLibrary. Второй параметр — имя нужной функции.

Если функция завершается успешно, то она возвращает адрес экспортируемой функции из модуля (библиотеки). Если происходит ошибка — 0.

FreeLibrary

Эта функция уменьшает итоговое число ссылок на DLL (если она используется одновременно несколькими приложениями), а если число ссылок становится равно 0, то выгружает библиотеку из памяти.

Имеет один параметр: hModule, т.е. дескриптор библиотеки (который, напомню, возвращает функция LoadLibrary).

Если функция завершается успешно, возвращаемой значение не равно нулю. Если происходит ошибка, то оно равно нулю.

Но основе этих функций составим программу, которая будет подключать динамически DLL (stdcall):

Visual Basic
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
39
40
41
42
43
44
45
46
47
Option Explicit
' API-функции 
Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
Private Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long
 
Dim handle As Long, address As Long, unload As Long ' переменные с результатами функций
 
Private Sub Form_Load()
 
handle = LoadLibrary("test.dll") ' загружаем библиотеку
 
If handle <> 0 Then ' успешная загрузка
 
   MsgBox ("Библиотека успешно загружена.")
   address = GetProcAddress(handle, "Summ") ' получаем адрес функции
 
   If address <> 0 Then ' успешное получение адреса
 
      MsgBox ("Адрес функции успешно получен.") ' здесь можно использовать функцию
 
   ElseIf address = 0 Then ' ошибка при получении адреса
 
      MsgBox ("Ошибка при извлечении адреса функции из DLL!")
      Exit Sub 
 
   End If  
 
ElseIf handle = 0 Then ' ошибка при загрузке 
 
   MsgBox ("Ошибка при загрузке DLL!")
 
End If 
 
unload = FreeLibrary(handle) ' высвобождаем библиотеку из памяти 
 
If unload <> 0 Then ' успешно выгрузили 
 
   MsgBox ("Библиотека выгружена успешно.") 
 
ElseIf unload = 0 Then 'ошибка при выгрузке 
 
   MsgBox ("Ошибка при выгрузке библиотеки из памяти!") 
 
End If 
 
End Sub

Как вы сами видите, длина кода намного больше, чем при статической загрузке, поскольку мы включили сюда ещё и обработку ошибок при помощи конструкции if. Налицо — гибкость!

А теперь рассмотрим возможность динамического (впрочем, как я писал выше, работать со статическим очень сложно) подключения cdecl. Для этого, кроме упомянутых выше, нам понадобятся ещё функции CallWindowProc и CopyMemory. Сразу замечу, что необходимо знание Ассемблера для полного понимания работы такой программы.

GetProcWindow

Эта функция передает информацию сообщения процедуре заданного окна.

Имеет 5 параметров: lpFunc, который указывает на процедуру, и Param1-Param4, через которые передаются параметры функции. Все параметры имеют тип Long.

Возвращаемое значение определяет результат обработки и зависит от параметров.

RtlMoveMemory

Эта функция копирует содержимое одного блока памяти в другой.

Имеет 3 параметра: Dest — указатель в тот блок памяти, куда нужно произвести копирование, Src — указатель на тот блок памяти, который копируется, Length — количество байтов, которое должно передаваться.

Возвращаемое значение отсутствует.

В качестве примера использования мы будем вызывать функцию qsort из библиотеки ntdll.dll, написанной на Си (cdecl). Данная функция используется для быстрой сортировки массива.

Visual Basic
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
Option Explicit
 
Private Declare Sub qsort Lib "ntdll" (base As Any, ByVal num As Long, ByVal width As Long, ByVal compare As Long)
Private Declare Function VarCmp Lib "oleaut32" (ByVal pvarLeft As Variant, ByVal pvarRight As Variant, ByVal lcid As Long, ByVal dwFlags As Long) As Long
Public Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
Public Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
Public Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Dest As Any, Src As Any, ByVal Length As Long)
Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpFunc As Long, ByVal Param1 As Long, ByVal Param2 As Long, ByVal Param3 As Long, ByVal Param4 As Long) As Long
 
Dim hModule1 As Long, EntryPoint As Long
Dim hModule2 As Long, VarCmp As Long
Dim Thunk(0 To 32) As Byte
Dim Comparer(0 To 24) As Byte
 
Public Sub Initialize()
    hModule1 = LoadLibrary("ntdll")
    EntryPoint = GetProcAddress(hModule1, "qsort")
    hModule2 = LoadLibrary("oleaut32")
    VarCmp = GetProcAddress(hModule2, "VarCmp")
' cDecl - ложим в стек параметры справа налево
CopyMemory Thunk(0), &H102474FF, 4  'FF742410   push dword ptr [esp+10h] - помещаем адрес функции VarCmp
    CopyMemory Thunk(4), &H102474FF, 4  'FF742410   push dword ptr [esp+10h] - помещаем размер (в байтах) одной переменной
    CopyMemory Thunk(8), &H102474FF, 4  'FF742410   push dword ptr [esp+10h] - помещаем кол-во элементов массива
    CopyMemory Thunk(12), &H102474FF, 4 'FF742410   push dword ptr [esp+10h] - помещаем указатель на буфер
    CopyMemory Thunk(16), &H6E8, 2      'E806000000 call $+6 - помещаем в стек, адрес следующей инструкции,
                                        ' после вызова qSort, выполнение начнется с нее. А также вызываем
                                        ' инструкцию расположенную на шесть байт после текущей
    CopyMemory Thunk(21), &H10C483, 3   '83C410     add esp, 10h - вызов cDecl чистим стек здесь, потому что
                                        ' VB не будет этого за нами делать
    CopyMemory Thunk(24), &H10C2, 2     'C21000     ret 10h - Тоже для CallWindowProc
    Thunk(27) = &H68                    '68xxxxxxxx push xxxxxxxx - здесь пишем адрес функции qSort в стек
    CopyMemory Thunk(28), EntryPoint, 4
    Thunk(32) = &HC3                    'C3         ret - удаляем из стека адрес функции qSort, и вызываем ее
' Для косвенного вызова через qSort функции VarCmp (сравнение двух Variant переменных)
    ' qSort сама чистит стек после выполнения этой вставки.
    ' stdCall - ложим в стек параметры справа налево
Comparer(0) = &H6A                  '6A00       push 0 - dwFlags
    Comparer(2) = &H6A                  '6A00       push 0 - lcid
    CopyMemory Comparer(4), &H102474FF, 4 'FF742410 push dword ptr [esp+10h] - pvarRight
    CopyMemory Comparer(8), &H102474FF, 4 'FF742410 push dword ptr [esp+10h] - pvarLeft
    CopyMemory Comparer(12), &H2E8, 2   'E802000000 call $+2 - Начнем выполнение с Comparer(19) (push xxxxxxxx -
                                        ' где xxxxxxxx- адрес функции VarCmp)
                                        ' Возвращаемое значение в регистре eax
    Comparer(17) = &H48                 '48         dec eax  - Вычитаем единицу для соответствия константам qSort'a
    Comparer(18) = &HC3                 'C3         ret - stdcall функция VarCmp сама почистила стек, поэтому просто выходим
Comparer(19) = &H68                 '68xxxxxxxx push xxxxxxxx - здесь пишем адрес функции VarCmp в стек
    CopyMemory Comparer(20), VarCmp, 4
    Comparer(24) = &HC3                 'C3         ret - переходим к выполнению VarCmp
End Sub
 
Public Sub Terminate()
    FreeLibrary hModule1
    FreeLibrary hModule2
End Sub
 
Public Sub SystemSort(SortArray())
    Initialize
    CallWindowProc VarPtr(Thunk(0)), VarPtr(SortArray(LBound(SortArray))), UBound(SortArray) - LBound(SortArray) + 1, 16, VarPtr(Comparer(0))
    Terminate
End Sub
 
Sub Main()
Dim i As Long, MyArr(-800 To 4000), StartTime As Single
Randomize Timer
  For i = LBound(MyArr) To UBound(MyArr)
    MyArr(i) = Rnd * 800
  Next
StartTime = Timer
  SystemSort MyArr
  Debug.Print Round(Timer - StartTime, 4)
End Sub

Подробное описание работы — в комментариях к коду.

Альтернативный код — с CallBack функцией. В отличие от предыдущего варианта, он гибче, т.к. позволяет менять критерий сравнения, а во-вторых здесь используется CopyMemory. Вместо функции RtlMoveMemory здесь используем API-функции GetMem4, PutMem4, GetMem2.

Visual Basic
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
Option Explicit
 
Private Declare Function GetMem4 Lib "msvbvm60" (pSrc As Any, pDst As Any) As Long
Private Declare Function GetMem2 Lib "msvbvm60" (pSrc As Any, pDst As Any) As Long
Private Declare Function PutMem4 Lib "msvbvm60" (pDst As Any, NewValue As Any) As Long
 
Public Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
Public Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
Public Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long
Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpFunc As Long, ByVal Param1 As Long, ByVal Param2 As Long, ByVal Param3 As Long, ByVal Param4 As Long) As Long
 
Dim hModule1 As Long, EntryPoint As Long
 
Dim Thunk(0 To 43) As Byte
 
Public Sub Initialize()
 
    hModule1 = LoadLibrary("ntdll")
    EntryPoint = GetProcAddress(hModule1, "qsort")
 
    ' cDecl - ложим в стек параметры справа налево
    
    Thunk(0) = &HB8                     'B800000000 - помещаем в eax адрес функции qSort
    GetMem4 EntryPoint, Thunk(1)
    Thunk(5) = &H5B                     'pop ebx
    GetMem2 &H1D89, Thunk(6)            'mov xxxxxxxx,ebx
    PutMem4 Thunk(8), Thunk(24)
    GetMem2 &HD0FF, Thunk(12)           'FFD0 - Call eax вызываем qSort
    GetMem2 &H1D8B, Thunk(14)           'mov ebx,xxxxxxxx
    PutMem4 Thunk(16), Thunk(24)
    Thunk(20) = &H53                    'push ebx
    GetMem2 &H10C2, Thunk(21)           'C21000     ret 10h - Тоже для CallWindowProc
 
    ' т.к. qSort сама чистит стек, Compare вызывается через вставку
    
    GetMem4 &H82474FF, Thunk(28)          'push   DWORD PTR [esp+0x8]  ' Дубликат параметра
    GetMem4 &H82474FF, Thunk(32)          'push   DWORD PTR [esp+0x8]  ' Дубликат параметра
    Thunk(36) = &HB8                      'mov eax,xxxxxxxx
    GetMem4 AddressOf Compare, Thunk(37)  'xxxxxxxx - Compare
    GetMem2 &HD0FF, Thunk(41)             'call eax - вызываем Compare
    Thunk(43) = &HC3                      'ret - Возвращаемся, стек почистит qSort
End Sub
 
Public Function Compare(ByVal lpOp1 As Long, ByVal lpOp2 As Long) As Long      ' CallBack - функция сравнения
    Dim Op1 As Long, Op2 As Long
    
    GetMem4 ByVal lpOp1, Op1
    GetMem4 ByVal lpOp2, Op2
    
    ' По возрастанию
    If Op1 < Op2 Then Compare = -1: Exit Function
    If Op1 = Op2 Then Compare = 0: Exit Function
    Compare = 1
    
    ' По убыванию
'    If Op1 < Op2 Then Compare = 1: Exit Function
'    If Op1 = Op2 Then Compare = 0: Exit Function
'    Compare = -1
    
End Function
 
Public Sub Terminate()
    FreeLibrary hModule1
End Sub
 
Public Sub SystemSort(SortArray() As Long)
    Initialize
    CallWindowProc VarPtr(Thunk(0)), _
                   VarPtr(SortArray(LBound(SortArray))), _
                   UBound(SortArray) - LBound(SortArray) + 1, _
                   LenB(SortArray(LBound(SortArray))), VarPtr(Thunk(28))
    Terminate
End Sub
 
Sub Main()
    Dim i As Long, MyArr(0 To 4000) As Long
    
    For i = 0 To UBound(MyArr)
        MyArr(i) = Rnd * 800
    Next
    
    SystemSort MyArr
 
End Sub

Создание

По каким-то причинам в Microsoft решили, что возможность создавать обычные DLL в Visual Basic будет лишней, а потому создавать их так просто мы не сможем, во всяком случае, без бубна. Да, я говорю про обычные DLL, потому что можно создавать лишь ActiveX DLL. В чём же разница обычных DLL от ActiveX?

ActiveX

ActiveX была внедрена в Windows компанией Microsoft в 1996 году как продолжение развития её технологий OLE (Object Linking and Embedding) и COM (Component Object Model).

OLE — технология связи и внедрения объектов в другие документы и объекты. Она позволяет передавать данные от одной программы для редактирования другой. Так, например, изображение или рисунок в программе Microsoft Word можно редактировать в Paint, и при сохранении он автоматически измениться и в документе Word.

COM — технология создания программного обеспечения на основе взаимосвязанных компонентов. Воплощение идей объектно-ориентированного программирования (ООП): инкапсуляции и полиморфизма.

И вот мы имеем фреймворк ActiveX, совмещающий эти две технологии. Он активно используется при разработке форм приложений. Все кнопки, списки, диалоговые окна, «этикетки» (Label), поля ввода (Textbox), их которых мы собираем форму — всё это ActiveX. Вообще многие продукты Microsoft используют управляющий элементы ActiveX, что позволяет использовать их функционал в других приложениях. Подробнее об этом смотрите в моей статье об использовании компонента Windows Media Player для создания музыкального проигрывателя.

Итак, приступим к созданию ActiveX DLL! Запускаем Visual Basic, в окне New Project выбираем ActiveX DLL (либо в меню File-New Project). И вот уже перед нами и редактор кода! Процесс написания кода здесь ничем не отличается от написания обычной программы. Пишете код, сохраняете проект, компилируете библиотеку.
Но не забывайте тот факт, что ActiveX DLL, в отличие от обычной DLL, не библиотека процедур и функций, а библиотека классов! Так что здесь забудьте про процедурное программирование — только ООП! Пишем классы: поля, свойства, методы, инкапсуляция, наследование (кстати, в Visual Basic нет обычного наследования, так что это делать нужно через наследование интерфейсов), полиморфизм. В принципе это и есть главное отличие. Хотя написать процедуру как метод не составит проблем.

Коротко об использовании ActiveX DLL. Подключаются они точно так же, как и обычные, но с той разницей, что необходимо создать объект и вызывать его методы — это называют связыванием. Различают ранее и позднее связывание.

Ранее связывание осуществляется командой

Visual Basic
1
Set myObj = New имя_dll.myClass

где myObj — имя объекта, а myClass — название класса в DLL. При таком связывании вся информация о методах, свойствах и событиях класса известна во время компиляции, потому вызов методов происходит также быстро, как и обычных функций в
программе.
При позднем связывании нужно сначала создать объект:

Visual Basic
1
Set myObj=CreateObject("имя_dll.myClass")

после чего можно вызывать его метод:

Visual Basic
1
x=myObj.Summ(параметры)

Проверка методов/свойств происходит во время выполнения программы, так что мы проигрываем раннему связыванию во времени, но зато этот способ более гибкий.

Если вас заинтересовала технология ActiveX и её возможности, рекомендую вам ознакомится со статьей Б.Л. Файфеля «COM в действии»: «Создаем ActiveX DLL»: и «Вопросы» (часто задаваемые вопросы про ActiveX).

Обычные DLL

Вообще-то создавать обычные DLL в Visual Basic, как уже было сказано выше, нельзя без «танцев с бубном». Но энтузиастами был создан Add-In для среды разработки Visual Basic, который позволяет создавать почти полноценные DLL на Visual Basic. Единственный, и самый существенный минус — невозможность использования созданных таким образом библиотек в других языках программирования. Загрузить Add-In можно по этой ссылке К архиву прилагается файл ReadMe с подробным описанием установки дополнения и его использования, а также пара примеров создания DLL.

Каким же образом мы компилируем библиотеки, если такой возможности в VB нет? Весь секрет в недокументированных возможностях link.exe («линкеры», как известно, выполняют компиляцию в всё с этим связанное). Если запустить его в DOS командой link.exe > c:/link.txt, то мы увидим множество различных ключиков. Их них наибольший интерес представляют /DLL и /DRIVER. Понятно, что компилятор Visual Basic 6 способен ещё и компилировать библиотеки с драйверами! Ну вот именно на первом ключе и основан принцип работы этой надстройки: перехватываем командную строку линкера, изменяем, вызываем настоящий линкер.
Только одно но… это скорее не продуманная реализация линкера, а баг. Он нарушает компоновку библиотеки, из-за чего она будет работать не стабильно. А именно — лишь в Visual Basic!

Если вас заинтересовало это, то подробнее ознакомиться с работой надстройки вы можете здесь.

Автор: Павел Смирнов (Craw)
Источник: basic.ucoz.net
Отдельная благодарность за помощь в написании статьи:
Catstail, SoftIce, locm, Pro_grammer, TheTrick



15



    msm.ru

    Нравится ресурс?

    Помоги проекту!

    Здесь обсуждаются вопросы по языку Visual Basic 1-6 (а так же по схожим языкам, как, например, PowerBASIC).
    Вопросы по Visual Basic .NET (это который входит в состав Visual Studio 2002/2003/2005/2008+, для тех, кто не в курсе) обсуждаются в разделе .NET.

    Обратите внимание:
    1. Прежде чем начать новую тему или отправить сообщение, убедитесь, что Вы не нарушаете правил форума!
    2. Обязательно воспользуйтесь поиском. Возможно, Ваш вопрос уже обсуждали. Полезные ссылки приведены ниже.
    3. Темы с просьбой выполнить какую-либо работу за автора в этом разделе не обсуждаются. Студенты, вам сюда: ПОМОЩЬ СТУДЕНТАМ!
    4. Используйте теги [ code=vba ] …текст программы… [ /code ] для выделения текста программы подсветкой.
    5. Помните, здесь телепатов нет. Формулируйте свой вопрос максимально грамотно и чётко: Как правильно задавать вопросы
    6. Запрещено отвечать в темы месячной (и более) давности, без веских на то причин.

    Полезные ссылки:
    user posted image FAQ Сайта user posted image FAQ Раздела user posted image Кладовка user posted image Наши Исходники user posted image API-Guide user posted image Поиск по Разделу user posted image MSDN Library Online user posted image Google


    Ваше мнение о модераторах: user posted image SCINER, user posted image B.V.

    >
    Bad DLL calling convention
    , вызов функции из vba

    • Подписаться на тему
    • Сообщить другу
    • Скачать/распечатать тему

      


    Сообщ.
    #1

    ,
    14.05.05, 09:35

      Member

      **

      Господа, помогите, пожалуйста, избавиться от Run-time error 49 (Bad DLL calling convention). Ситуация такая.

      У меня есть MFC DLL, которую я сделал на MSVC++ v7. В ней функция

      ExpandedWrap disabled

        __declspec(dllexport) void mfcfun(int n) {…}

      Я её вызываю из MS Access следующим кодом

      ExpandedWrap disabled

        Private Declare Sub mfcfun _

          Lib «C:workaccessmfcdll.dll» _

          Alias «?mfcfun@@YAXH@Z» _

          (ByVal n As Integer)

        Private Sub testDLL()

            mfcfun 33

        End Sub

      Она нормально вызывается, но выдаёт после выхода эту самую ошибку 49.

      Конечно, можно поставить
      On Error Resume Next
      но только боюсь, это приведёт рано или поздно к каким-нибудь проблемам.

      Что посоветуете?

      PS на CodeNet.ru никто не знает, похоже…


      Mr. Greg



      Сообщ.
      #2

      ,
      14.05.05, 09:42

        Попробуй убрать

        ExpandedWrap disabled

          ByVal

        Добавлено 14.05.05, 09:55

        Цитата

        Bad DLL Calling Convention Error
        This error is often caused by incorrectly omitting or including the ByVal keyword from the Declare statement. This error can also be caused if the wrong parameters are passed.


        sq_deep



        Сообщ.
        #3

        ,
        14.05.05, 12:52

          Member

          **

          Цитата Mr. Greg @ 14.05.05, 09:42

          Попробуй убрать ByVal

          Нельзя. Тогда должно будет стать
          mfcfun(int* n), а мне надо без «*»…


          Mr. Greg



          Сообщ.
          #4

          ,
          14.05.05, 12:57

            Скинь длл


            sq_deep



            Сообщ.
            #5

            ,
            14.05.05, 14:25

              Member

              **

              Вот rar.

              В нём проект на VC++ v7.0.

              В папках Debug и Release соответственно отладочная и релизная DLL. Обе ведут себя одинаково. Функция вызывается, параметр передаётся правильно, но потом ошибка 49…

              Моя реальная DLL делает, конечно, гораздо больше всего интересного, но эта тестовая ведёт себя так же.

              Прикреплённый файлПрикреплённый файлmfcdll.rar (31.26 Кбайт, скачиваний: 104)


              Mr. Greg



              Сообщ.
              #6

              ,
              15.05.05, 03:27

                Цитата

                The C++ project must also be set to use the __stdcall calling convention. Otherwise you will get error 49 «Bad DLL Calling Convention». The issue there is that C++ and VB natively push arguments on the stack in different manner. But when you tell Visual C++ (presumable could do the same w/ Borland or another compiler) to use the __stdcall convention it makes it so your VB program can read it.

                ExpandedWrap disabled

                  __stdcall

                надо использовать, тем более если тип данных не определен

                ExpandedWrap disabled

                  void

                , с VB так нельзя.
                зы. проект перекомпиленный в vc 6 ведет себя также :(

                Добавлено 15.05.05, 03:28
                VC DLL in VB

                Сообщение отредактировано: Mr. Greg — 15.05.05, 03:34


                nikf



                Сообщ.
                #7

                ,
                15.05.05, 14:05

                  попробуй вместо void поюзать инт.. ноль возвратишь и ладно.. басике инт на лонг надо менять…


                  sq_deep

                    


                  Сообщ.
                  #8

                  ,
                  16.05.05, 06:00

                    Member

                    **

                    Спасибо, Mr. Greg. Надо действительно писать __stdcall (или PASCAL):

                    ExpandedWrap disabled

                      __declspec(dllexport) void __stdcall mfcfun(int n) {…}

                    Profi

                    Old Bat



                    Сообщ.
                    #9

                    ,
                    16.05.05, 07:06


                      sq_deep



                      Сообщ.
                      #10

                      ,
                      16.05.05, 08:42

                        Member

                        **

                        Цитата Old Bat @ 16.05.05, 07:06

                        Тема перемещена из раздела VB for Application

                        Вам, конечно, виднее, уважаемый Old Bat, но мне почему-то кажется, что вопрос «как вызвать функцию из DLL в программе, написанной на VBA?» всё-таки относится именно к VBA, у не к каким-то там «общим вопросам»…

                        Profi

                        Old Bat



                        Сообщ.
                        #11

                        ,
                        16.05.05, 09:26

                          IMHO :no: к VB, и, в том числе, к VBA. В теме не рассматриваются особенности именно VBA-кода (см. пост #6)


                          sq_deep



                          Сообщ.
                          #12

                          ,
                          16.05.05, 10:01

                            Member

                            **

                            Да, вы правы.


                            nash



                            Сообщ.
                            #13

                            ,
                            16.05.05, 11:58

                              Private Declare Sub mfcfun _
                              Lib «C:workaccessmfcdll.dll» _
                              Alias «?mfcfun@@YAXH@Z» _
                              (ByVal n As LONG)

                              и все ок будет


                              Алиса



                              Сообщ.
                              #14

                              ,
                              16.05.05, 12:07

                                Алиса Senior Member

                                ****

                                Рейтинг (т): 58

                                Используй def-файл, чтобы убрать декорирование имен.
                                Тогда будет не «?mfcfun@@YAXH@Z», а «mfcfun»
                                Достаточно в этом файле прописать
                                EXPORT:
                                mfcfun


                                Mr. Greg



                                Сообщ.
                                #15

                                ,
                                16.05.05, 13:29

                                  Цитата nash @ 16.05.05, 12:07

                                  и все ок будет

                                  утверждение ложное, не проверил, а советуешь :angry:

                                  Цитата Алиса @ 16.05.05, 12:07

                                  убрать декорирование имен

                                  однако, полезно предыдущие ответы посмотреть — в ссылке об этом есть.

                                  Сообщение отредактировано: Mr. Greg — 16.05.05, 13:30

                                  0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)

                                  0 пользователей:

                                  • Предыдущая тема
                                  • Visual Basic: Общие вопросы
                                  • Следующая тема

                                  Рейтинг@Mail.ru

                                  [ Script execution time: 0,0600 ]   [ 16 queries used ]   [ Generated: 9.02.23, 07:30 GMT ]  

                                  Модератор: Модераторы

                                  Обращение к DLL (fpc) из VBA(excel)

                                  При выполнении макроса при обращении к test
                                  выдается сообщение:
                                  run-time error «49»
                                  bad DLL calling convention

                                  Если параметры не массивы, все работает.
                                  Ниже привожу исходники.
                                  Спасибо

                                  <<—————— ЭТО FPC ——————————>>
                                  unit testU;
                                  interface
                                  procedure test(var tabl1: array of double); export; stdcall;
                                  implementation
                                  procedure test(var tabl1: array of double); stdcall;
                                  var
                                  i: integer;
                                  begin
                                  for i := 0 to 7 do tabl1[i] := i;
                                  end;
                                  exports test;
                                  end.

                                  <<—————— ЭТО VBA ——————————>>
                                  Private Declare Sub test Lib «test.dll» (ByRef tabl1() As Double)
                                  Sub TWS()
                                  Dim tabl1(0 To 7) As Double
                                  MsgBox (tabl1(6))
                                  Rem Call tab1(T, tabl1)
                                  Call test(tabl1)
                                  MsgBox (tabl1(6))
                                  End Sub

                                  azsht
                                  незнакомец
                                   
                                  Сообщения: 5
                                  Зарегистрирован: 15.04.2013 14:58:44


                                  Re: Обращение к DLL (fpc) из VBA(excel)

                                  Сообщение azsht » 15.04.2013 15:42:10

                                  А обойтись без SAFEARRAY никак нельзя?

                                  azsht
                                  незнакомец
                                   
                                  Сообщения: 5
                                  Зарегистрирован: 15.04.2013 14:58:44

                                  Re: Обращение к DLL (fpc) из VBA(excel)

                                  Сообщение NTFS » 15.04.2013 16:58:49

                                  Мой бог… ну не пишут на Паскале dll для использования в сторонних программах. Язык программирования Windows — это С и Assembler. Вот и пишите на них. Иначе не сейчас, так потом проблемы вылезут.

                                  Вот работающий код из моего приложения-расширения для Excel. Сможете перевести это в Паскаль — будет хорошо.

                                  Код: Выделить всё
                                  // GetTime.cpp: определяет экспортированные функции для приложения DLL.
                                  //

                                  #include "stdafx.h"

                                  #pragma comment(linker, "/export:CalcArray=_CalcArray@4")
                                  #pragma comment(linker, "/export:CalcSum=_CalcSum@40")
                                  #pragma comment(linker, "/export:CalcMax=_CalcMax@40")
                                  #pragma comment(linker, "/export:CalcMin=_CalcMin@40")
                                  #pragma comment(linker, "/export:CalcSred=_CalcSred@40")

                                  typedef struct
                                  {
                                  WORD rows;
                                  WORD columns;
                                  double array[1]; // Start of array[rows * columns]
                                  }
                                  xl_array;

                                  extern "C" __declspec(dllexport) double __stdcall CalcSum(double n1,double n2,double n3,double n4, double n5)
                                  {
                                    return(n1+n2+n3+n4+n5) ;
                                  }

                                  extern "C" __declspec(dllexport) double __stdcall CalcMax(double n1,double n2,double n3,double n4, double n5)
                                  {
                                    double r = n1 ;
                                    if (n2>r) r = n2 ;
                                    if (n3>r) r = n3 ;
                                    if (n4>r) r = n4 ;
                                    if (n5>r) r = n5 ;
                                    return(r) ;
                                  }

                                  extern "C" __declspec(dllexport) double __stdcall CalcMin(double n1,double n2,double n3,double n4, double n5)
                                  {
                                    double r = n1 ;
                                    if (n2<r) r = n2 ;
                                    if (n3<r) r = n3 ;
                                    if (n4<r) r = n4 ;
                                    if (n5<r) r = n5 ;
                                    return(r) ;
                                  }

                                  extern "C" __declspec(dllexport) double __stdcall CalcSred(double n1,double n2,double n3,double n4, double n5)
                                  {
                                    double cnt = 5 ;
                                    return((n1+n2+n3+n4+n5)/cnt) ;
                                  }

                                  extern "C" __declspec(dllexport) double __stdcall CalcArray(xl_array *p_array)
                                  {
                                  if(!p_array || !p_array->rows
                                  || !p_array->columns || p_array->columns > 0x100)
                                  return (123) ;
                                  int size = p_array->rows * p_array->columns;
                                  double sum ;
                                  for(int i = 0; i < size; i++)
                                    sum=sum+p_array->array[i] ; //= i / 10.0;
                                  return(sum) ;
                                  }

                                  NTFS
                                  постоялец
                                   
                                  Сообщения: 388
                                  Зарегистрирован: 05.11.2007 14:57:50
                                  Откуда: Краснодар
                                  • Профиль
                                  • Сайт
                                  • ICQ

                                  Re: Обращение к DLL (fpc) из VBA(excel)

                                  Сообщение alexey38 » 15.04.2013 20:05:57

                                  NTFS писал(а):Мой бог… ну не пишут на Паскале dll для использования в сторонних программах. Язык программирования Windows — это С и Assembler. Вот и пишите на них. Иначе не сейчас, так потом проблемы вылезут.

                                  Не нужно говорить ерунду. На паскале пишут все, что угодно. Просто не нужно программирование воспринимать как шаманство, особенно, когда идет взаимодействие между различными языками. Вначале разбираемся, что требует смежная система, и затем реализуем аналогичное в паскале.

                                  Добавлено спустя 3 минуты 5 секунд:

                                  Здесь рассмотрено несколько вариантов. В любом случае нужно понимать, что паскалевские динамические массивы, как и паскалевские строки — это специальные элементы со счетчиком элементов и счетчиком ссылок, и невозможно гарантировать одинаковость структуры заголовков.

                                  Добавлено спустя 1 минуту 42 секунды:

                                  azsht писал(а):А обойтись без SAFEARRAY никак нельзя?

                                  Можно, если не нужно создавать массив внутри DLL. SAFEARRAY нужен для того, чтобы выделить память под динамический массив в DLL, передать ее в головную программу и там освободить память. SAFEARRAY определяет общий алгоритм выделения/освобождения памяти, и одинаковую для всех структуру самого массива.

                                  Добавлено спустя 1 минуту 15 секунд:

                                  NTFS писал(а):Вот работающий код из моего приложения-расширения для Excel. Сможете перевести это в Паскаль — будет хорошо.

                                  Данный код без каких либо проблем переводится на паскаль.

                                  alexey38
                                  долгожитель
                                   
                                  Сообщения: 1627
                                  Зарегистрирован: 27.04.2011 19:42:31

                                  Re: Обращение к DLL (fpc) из VBA(excel)

                                  Сообщение NTFS » 15.04.2013 20:32:24

                                  alexey38

                                  На паскале пишут все, что угодно.

                                  Правильнее будет так: на паскале можно написать все, что угодно. Проблема в том, что это может и работать, как угодно.
                                  Есть четкие целевые назначения языков. Делать системные задачи на Паскале — так же неудобно, как и оболочку базы данных на C.

                                  NTFS
                                  постоялец
                                   
                                  Сообщения: 388
                                  Зарегистрирован: 05.11.2007 14:57:50
                                  Откуда: Краснодар
                                  • Профиль
                                  • Сайт
                                  • ICQ

                                  Re: Обращение к DLL (fpc) из VBA(excel)

                                  Сообщение alexey38 » 15.04.2013 20:46:37

                                  NTFS писал(а):Есть четкие целевые назначения языков. Делать системные задачи на Паскале — так же неудобно, как и оболочку базы данных на C.

                                  Это выдумка маркетологов и не более. Паскаль как язык полностью равнозначен (только лучше) тому же самому «С». И во времена турбопаскаля и доса мы прекрасно писали всякие там резидентные проги не только на ассемблере, но и на паскале. Все аналогично и сегодня. Единственное, что сам компилятор не позволяет компилировать в дрова, но вопрос не о дровах (драйверах).

                                  Поэтому не нужно выдумывать, что у языков есть «четкие целевые назначения». Есть SDK и библиотеки, которые существуют под конкретные языки, что делают не очень простым путь реализации аналога на другом языке (под который нет SDK).
                                  Занимаясь системным программированием нужно понимать, как работает система, какие функции можно использовать, а какие нельзя. При этом нужно хорошо знать и свой язык программирования, понимать, что можно использовать, а что нельзя. Все просто и однозначно, и ни как не связано с языком «С».

                                  Тем более, что интеграция с бейсиком никогда не называлась системной задачей. Тут просто вначале нужно изучить сам вопрос взаимодействия разных систем и разных приложений, а затем начинать реализовывать.
                                  А когда нужно наоборот управлять извне тем же самым Excel, Word или подобным, то паскаль (в его Дельфовской реализации) является идеальным инструментом по причине удачной реализации COM, OLE, Variant. На С-ях это самоубийство, хоть и родная среда для винды. Собственно Микрософт так долго тянул лямку с бейском, по причине корявости языка «С» и «С++» при работе с технологиями COM, OLE, Variant.

                                  alexey38
                                  долгожитель
                                   
                                  Сообщения: 1627
                                  Зарегистрирован: 27.04.2011 19:42:31

                                  Re: Обращение к DLL (fpc) из VBA(excel)

                                  Сообщение azsht » 16.04.2013 09:23:58

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

                                  azsht
                                  незнакомец
                                   
                                  Сообщения: 5
                                  Зарегистрирован: 15.04.2013 14:58:44

                                  Re: Обращение к DLL (fpc) из VBA(excel)

                                  Сообщение NTFS » 16.04.2013 10:02:35

                                  azsht

                                  Вам уже подсказали.
                                  Вариант 1: Выкинуть код на Паскале, поставить бесплатный Visual Studio Express, потом сделать по примерам из официальных руководств по автоматизации Excel.
                                  Вариант 2: Найти рабочий вариант кода на C++ и перевести все на Паскаль, разобравшись, какие типы в С++ соответствуют типам в Паскаль.

                                  alexey38

                                  Это выдумка маркетологов и не более. Паскаль как язык полностью равнозначен (только лучше) тому же самому «С»

                                  Паскаль как язык почти идентичен тому же С. Только вместо begin end идут скобки, да оператор if можно заменить на ?:.
                                  Только на языке программирования ничего не напишешь, да. Потому что уже операции ввода-вывода для языка — это нужны различные SDK. А бинарный код, в который переводится язык — это работа компилятора.
                                  Потому я и говорю: да, на Паскале можно сделать драйвер устройства, а на чистом C сделать морду к базе. Только зачем?

                                  NTFS
                                  постоялец
                                   
                                  Сообщения: 388
                                  Зарегистрирован: 05.11.2007 14:57:50
                                  Откуда: Краснодар
                                  • Профиль
                                  • Сайт
                                  • ICQ

                                  Re: Обращение к DLL (fpc) из VBA(excel)

                                  Сообщение alexey38 » 16.04.2013 10:55:47

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

                                  Ошибка в строке

                                  Код: Выделить всё
                                  procedure test(var tabl1: array of double); stdcall;

                                  Собственно Ваш вывод «Если параметры не массивы, все работает.» говорит о том, что внутренняя структура массивов в паскале не соответствует внутренней структуре массивов в байсике.

                                  Добавлено спустя 39 минут 45 секунд:
                                  Как реализовать, то смотрите либо MSDN, либо пример от NTFS, его структура xl_array прекрасно реализуется в паскале.

                                  Добавлено спустя 6 минут 26 секунд:

                                  NTFS писал(а):Потому я и говорю: да, на Паскале можно сделать драйвер устройства, а на чистом C сделать морду к базе. Только зачем?

                                  Драйвер на паскале не нужно писать, тут согласен. Но взаимодействие с бейсиком, Excel, Word и т.п. — это как раз ниша паскаля, а не С++. У паскаля код работает очень ожидаемо, нет ни какого шаманства. Поэтому в паскале очень легко реализуется взаимодействие между разными системами. Но взявшись за решению данной задачи нужно вначале изучить предметную область.
                                  Например, Ваш пример функции:

                                  Код: Выделить всё
                                  extern "C" __declspec(dllexport) double __stdcall CalcArray(xl_array *p_array)

                                  Если его переписать:

                                  Код: Выделить всё
                                  extern "C" __declspec(dllexport) double __stdcall CalcArray(std::string *p_array)

                                  , то он не будет работать, как и не работает код на паскале:

                                  Код: Выделить всё
                                  procedure test(var tabl1: array of double); stdcall;

                                  Языки программирования и наличие SDK тут не причем.

                                  alexey38
                                  долгожитель
                                   
                                  Сообщения: 1627
                                  Зарегистрирован: 27.04.2011 19:42:31

                                  Re: Обращение к DLL (fpc) из VBA(excel)

                                  Сообщение Widowmaker » 16.04.2013 20:22:57

                                  Код: Выделить всё
                                  type TRealVector = array of double;
                                  procedure test(const size_of_tabl1: longint; var tabl1: TRealVector); export; stdcall;

                                  ( cпособ «мешок с биркой»; остальные навороты вроде cdecl ни к чему )

                                  Аватара пользователя
                                  Widowmaker
                                  новенький
                                   
                                  Сообщения: 37
                                  Зарегистрирован: 27.04.2011 18:32:04

                                  Re: Обращение к DLL (fpc) из VBA(excel)

                                  Сообщение azsht » 17.04.2013 09:12:14

                                  Widowmaker писал(а):type TRealVector = array of double;
                                  procedure test(const size_of_tabl1: longint; var tabl1: TRealVector); export; stdcall;

                                  А как при этом выглядит обращение из VBA к test?

                                  azsht
                                  незнакомец
                                   
                                  Сообщения: 5
                                  Зарегистрирован: 15.04.2013 14:58:44

                                  Re: Обращение к DLL (fpc) из VBA(excel)

                                  Сообщение Widowmaker » 17.04.2013 14:35:31

                                  Я не большой знаток VBA, но, думаю, как-то так:

                                  Код: Выделить всё
                                  <<----------------- ЭТО FPC ----------------------------->>
                                  library testU;
                                  //
                                  {$mode objfpc} {$H+}
                                  //
                                  type TRealVector = array of double;
                                  //
                                  procedure test(const size_of_tabl1: longint; var tabl1: TRealVector); export; stdcall;
                                  var
                                  i: integer;
                                  //
                                  begin
                                  for i := 0 to size_of_tabl1 - 1 do tabl1[i] := i;
                                  end;
                                  //
                                  exports test;
                                  //
                                  begin
                                  end.

                                  <<----------------- ЭТО VBA ----------------------------->>
                                  Option Explicit
                                  Option Base 0
                                  '
                                  Private Declare Sub test Lib "test.dll" (ByRef size_of_tabl1 as Long, ByRef tabl1() As Double)
                                  '
                                  Sub TWS()
                                  '
                                  Dim size_of_tabl1 As Long
                                  Dim tabl1() As Double
                                  '
                                  size_of_tabl1 = 8
                                  ReDim tabl1(0 To size_of_tabl1)
                                  '
                                  MsgBox (tabl1(6))
                                  '
                                  Rem Call tab1(T, tabl1)
                                  '
                                  Call test(size_of_tabl1, tabl1)
                                  '
                                  MsgBox (tabl1(6))
                                  '
                                  End Sub

                                  Аватара пользователя
                                  Widowmaker
                                  новенький
                                   
                                  Сообщения: 37
                                  Зарегистрирован: 27.04.2011 18:32:04

                                  Re: Обращение к DLL (fpc) из VBA(excel)

                                  Сообщение azsht » 19.04.2013 12:30:16

                                  Собрал работающий код:

                                  VBA
                                  Private Declare Sub test Lib «test.dll» (ByRef tabl1() As Double)
                                  Sub TWS()
                                  Dim tabl1(0 To 7) As Double
                                  MsgBox (tabl1(6))
                                  Call test(tabl1)
                                  MsgBox (tabl1(7))
                                  End Sub

                                  Delphi
                                  unit testU;
                                  interface
                                  uses ActiveX,SysUtils;
                                  procedure test(var tabl1: PSafeArray); stdcall;
                                  implementation
                                  procedure test(var tabl1: PSafeArray); stdcall;
                                  var
                                  b: PDouble;
                                  i,i1,i2: integer;
                                  begin
                                  SafeArrayGetLBound(tabl1, 1, i1);
                                  SafeArrayGetUBound(tabl1, 1, i2);
                                  SafeArrayAccessData(tabl1, b);
                                  for i := i1 to i2 do b[i] := i+0.4;
                                  SafeArrayUnaccessData(tabl1)
                                  end;
                                  exports test;
                                  end.

                                  Всем спасибо!

                                  azsht
                                  незнакомец
                                   
                                  Сообщения: 5
                                  Зарегистрирован: 15.04.2013 14:58:44

                                  Re: Обращение к DLL (fpc) из VBA(excel)

                                  Сообщение Alex2013 » 25.04.2013 16:23:38

                                  Как вариант можно использовать не ДЛЛ а просто программу в простейшем варианте выдающую результат на консоль или в файл . Или чуть сложнее организовывать обмен через кипборд ДДЕ а можно вообще через сокеты по tcp/ip … Общем вариантов много и что особенно удобно почти нет нужды совмещать несовместимые форматы данных и программа работает как-бы самостоятельно что облегчает ее отладку .

                                  Alex2013
                                  долгожитель
                                   
                                  Сообщения: 2608
                                  Зарегистрирован: 03.04.2013 11:59:44


                                  Вернуться в Lazarus

                                  Кто сейчас на конференции

                                  Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 9

                                  Понравилась статья? Поделить с друзьями:
                                • Bad config system info windows 10 что делать ошибка
                                • Bad compressed data format minecraft как исправить
                                • Bad command error перевод
                                • Bad command argument error 12
                                • Bad apple error sans