Praveen Kumar Katiyar Ответов: 3

Функция не работает в DLL


У меня есть такая структура

#define MAX_NAME_LENGTH 40
typedef struct _tagMYPERSON  
{
    WCHAR FName[MAX_NAME_LENGTH];
    WCHAR LName[MAX_NAME_LENGTH];
    int Age;
    double Salary;
}MYPERSON;


тогда у меня есть функция в DLL, как это
extern "C" MARSHALDLL_API void _stdcall ModifyPersonStructArray(int nCount, MYPERSON * pPersonArr)
{
    for ( int nI = 0; nI < nCount; nI++ )
    {
	wcscat_s(pPersonArr[nI].FName, MAX_NAME_LENGTH, L"-Modified");
	wcscat_s(pPersonArr[nI].LName, MAX_NAME_LENGTH, L"-Modified");
	pPersonArr[nI].Age = pPersonArr[nI].Age+ 5;
	pPersonArr[nI].Salary = pPersonArr[nI].Salary + 1000 ;
   }
}


и вот как я это называю.

int nCount = 4;
MYPERSON* prsnArr = new MYPERSON [nCount];
CString strTmp;
m_lstOutput.ResetContent ();

for (int nI=0; nI<nCount ; nI++)
{
        strTmp.Format(_T("First Name %d"), nI+1);
        StringCchCopyW(prsnArr[nI].FName, MAX_NAME_LENGTH, strTmp);
	strTmp.Format(_T("Last Name %d"), nI+1);
	StringCchCopyW(prsnArr[nI].LName, MAX_NAME_LENGTH, strTmp);
	prsnArr [nI].Age = 20 + (nI+ 1)*2 ;
	prsnArr [nI].Salary = 20000 + (nI+ 1) * 1000;
	strTmp.Format(_T("Person %d=[(%s %s, Age=[%d], Salary=[%.2lf])]"), nI, prsnArr [nI].FName, prsnArr [nI].LName, prsnArr [nI].Age, prsnArr [nI].Salary);

	m_lstOutput.AddString (strTmp);
}
	  
ModifyPersonStructArray(nCount, prsnArr );
    
m_lstOutput.AddString(_T("After Call ==>"));
for (int nI=0; nI<nCount ; nI++)
{
        strTmp.Format(_T("Person %d=[(%s %s, Age=[%d], Salary=[%.2lf])]"), nI, prsnArr [nI].FName, prsnArr [nI].LName, prsnArr [nI].Age, prsnArr [nI].Salary);
	m_lstOutput.AddString (strTmp);
}


Примечание : m_lstOutput-это управляющая переменная (ListBox) в диалоговом окне MFC.

Когда я запускаюсь в режиме отладки, я получаю такое сообщение об ошибке,

Windows запустила точку останова в MFCClient.exe.
Это может быть связано с повреждением кучи, что указывает на ошибку в работе системы. MFCClient.exe или любой из загруженных им библиотек DLL.
Это также может быть связано с тем, что пользователь нажимает клавишу F12 во время MFCClient.exe имеет фокус.
Окно вывода может содержать дополнительную диагностическую информацию.


Что я здесь делаю не так ?

Что я уже пробовал:

Я перенес функцию DLL в сам класс Dialog. любить.


void CMFCClientDlg::ModifyPersonStructArray(int nCount, MYPERSON * pPersonArr)
{
    for ( int nI = 0; nI < nCount; nI++ )
    {
		wcscat_s(pPersonArr[nI].FName, MAX_NAME_LENGTH, L"-Modified");
		wcscat_s(pPersonArr[nI].LName, MAX_NAME_LENGTH, L"-Modified");
		pPersonArr[nI].Age = pPersonArr[nI].Age+ 5;
		pPersonArr[nI].Salary = pPersonArr[nI].Salary + 1000 ;
   }
}


и у меня нет никаких проблем. это работает.

пожалуйста, предложите.

Shao Voon Wong

Пожалуйста, покажите, как вы получили указатель функции на эту функцию в dll.

Shao Voon Wong

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

Praveen Kumar Katiyar

Я сделал полную перестройку всех мишеней. и скопировал обновленную dll в папку exe, но безрезультатно.

3 Ответов

Рейтинг:
24

Rick York

Из кода, который вы опубликовали, кажется, что проблема заключается в объявлениях прототипа по сравнению с его реализацией, как указал Ричард. Я написал письмо. МНОГО конечно, и это действительно не очень сложно. То есть, чтобы получить правильную связь. Я часто использую заголовок, который помогает в этом. Это выглядит примерно так.

#define DLLEXPORT __declspec(dllexport)
#define DLLIMPORT __declspec(dllimport)

// applications linking with this DLL see the import definition only

#ifdef BUILD_MY_DLL // this is defined in the DLL's project ONLY!!!
#define DLLFUNC      DLLEXPORT
#else
#define DLLFUNC      DLLIMPORT
#endif

// in a header that declares the prototype :

extern "C"
{
DLLFUNC void ModifyPersonStructArray( int count, MYPERSON * pArray );
}
Затем скопируйте эту строку именно так как написано, так и вставьте в файл реализации DLL и используйте его в качестве объявления функции. Он должен соответствовать прототипу в заголовке Вот именно! Последний шаг-определить BUILD_MY_DLL в файле реализации DLL или в файле проекта в качестве определения всего проекта. Этот макрос не может быть определен в приложении, иначе связывание завершится неудачей.

До тех пор, пока код реализации также завернут в объявление "extern C", функция по умолчанию будет __cdecl, поэтому она не нужна. Если вы используете его, то убедитесь, что он находится как в заголовочном файле, так и в реализации. Лично я никогда не использую его или __stdcall, если это не требуется для функции, используемой в качестве обратного вызова или потоковой процедуры.

Вы также можете поместить целые классы в библиотеку DLL, если хотите. Это может быть тот случай, когда это будет удобно. У вас может быть функция (или статический метод класса) для построения массива структур MYPERSON, эта для изменения массива и, возможно, другие для выполнения таких действий, как сортировка массива и его удаление.


Dave Kreskowiak

Разве что "#определить BUILD_MY_DLL" быть "#если BUILD_MY_DLL"??

Я могу ошибаться. Я уже довольно давно не прикасался к C/C++.

Rick York

Да, так и должно быть. Спасибо!

Praveen Kumar Katiyar

#ifdef BUILD_MY_DLL // это определено только в проекте DLL!!!

первая строка недоступна в моем заголовочном файле (проект DLL). затем я проверил его, и он был определен (проект DLL) в настройках проекта

Свойства -&проект gt; Свойства -> конфигурация; с/с++ -&ГТ; Prepreprocessor -&ГТ;Prepreprocessor определений. (Я использую VS2010 Ultimate).

Рейтинг:
1

Richard MacCutchan

Ваше определение в инструкции экспорта dll неверно. Он должен использовать __cdecl связь, а не _stdcall. Вы можете обеспечить правильную связь с помощью __declspec(dllexport) как описано в Экспорт из библиотеки DLL с помощью __declspec(dllexport) | Microsoft Docs[^].


Praveen Kumar Katiyar

спасибо за быстрый ответ.

но даже изменение соглашения о вызове не имеет никакого эффекта.

это одно и то же.

Richard MacCutchan

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

Рейтинг:
0

KarstenK

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

Я бы использовал такую подпись

extern "C" __declspec(dllexport) ModifyPersonStructArray()
Некоторые дополнительные Общие сведения о библиотеках DLL.
совет: вы можете отладить его, когда соберете используемую библиотеку dll в режиме отладки.