Подтвердить что ты не робот

Declspec и stdcall vs declspec только

Я новый человек для темы импорта dll в С++, и, возможно, мой вопрос очень прост, но я не могу найти его в google.

У меня очень простая С++ win32 dll:

#include <iostream>

using namespace std;

extern "C"
{
    __declspec(dllexport) void __stdcall DisplayHellowFromDLL()
    {
        cout<<"Hi"<<endl;
    }
}

Когда я вызываю этот метод из С#, у меня нет никаких проблем, вот код С#

namespace UnmanagedTester
{
    class Program
    {
        [DllImport(@"C:\CGlobalDll")]
        public static extern void DisplayHellowFromDLL();

        static void Main(string[] args)
            {
                Console.WriteLine("This is C# program");
                DisplayHellowFromDLL();
            }
        }
    }

Как я и ожидал, выход: "Это программа С#" "Привет".

Теперь, если я изменяю объявление функции C как:

__declspec(dllexport) void DisplayHellowFromDLL()

без __stdcall, у меня тоже нет проблем, и возникает вопрос:

Когда мне действительно нужен __declspec (dllexport) TYPE __stdcall и когда я могу использовать только тэг __declspec (dllexport)?

Большое спасибо.

4b9b3361

Ответ 1

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

Ответ 2

Вы можете думать об этом так:

  • __declspec(dllexport) объявляет вашу функцию как публичную функцию, которую экспортирует ваша DLL;

  • __stdcall - это довольно низкоуровневая деталь, которая относится к "вызывающей конвенции", принятой этой функцией; в частности, __stdcall означает, что вызываемый человек очищает стек;

  • альтернативой __stdcall является __cdecl, что означает: вызывающий объект очищает стек.

__cdecl является "естественным" вызовом C-вызова; он поддерживает определение функций vararg (например, printf).

__stdcall - это стандартное соглашение о вызове для DLL-функций, поэтому вам не нужно указывать его, если вы собираетесь использовать эти функции только через свой DLL-API.

Это должно объяснить, что вы наблюдаете.

Ответ 3

Это работает случайно, потому что функция не принимает никаких аргументов. Как только вы сделаете это над функцией, которая принимает аргументы, вы начнете бежать. Вызов оставит стек несбалансированным, очень нездоровым. При отладке вы получите предупреждение pInvokeStackImbalance MDA. Некорректный стек в противном случае может остаться незамеченным на некоторое время, он, как правило, разбивает вашу программу в сборке Release.

Ответ 4

Илья, вы также можете установить соглашение по умолчанию в свойствах проекта → Свойства конфигурации → C/С++ → Дополнительно → Вызов конвенции. Если стандартное соглашение о вызове в вашем проекте уже установлено на __stdcall (/Gz), то добавление __std