Jump to content

Como compilar uma DLL corretamente?


Matheus Miguel

Recommended Posts

 

E ai Pessoal! Beleza?

Estou trabalhando com simulações no Ansys (AQWA) e estou tendo problemas para compilar uma DLL que exportará funções para a simulação. Estou usando o Visual Studio 2019, com  um tamplate Biblioteca de Vínculo Dinâmico (DLL). Sou bem iniciante com este tipo de programação, pelo desculpas caso o erro seja muito tolo

 

Esses são os meus algortimos:

 

 

//user_force64.cpp

#include "user_force.h"
#include "pch.h"
#include <stdio.h>

extern "C"
{

	__declspec(dllexport) void _stdcall USER_FORCE(int* Mode, int I_Control[100], float R_Control[100],
		int* Nstruc, float* Time, float* TimeStep, int* Stage,
		float Position[][6], float Velocity[][6], float Cog[][3],
		float Force[][6], float Addmass[][6][6], int* ErrorFlag)

	{

		//
		// *** Visual C++ Template
		// -----------------------
		//
		// 1. Uses stdcall calling convention
		// 2. Routine name MUST be in upper case
		// 3. All parameters are passed as pointers
		//
		// Input Parameter Description:
		//
		// Mode int*       - 0  = Initialisation. This routine is called once with mode 0
		//                        before the simulation. All parameters are as described
		//                        below except for STAGE, which is undefined. FORCES and
		//                        ADDMAS are assumed undefined on exit.
		//                        IERR if set to > 0 on exit will cause
		//                        the simulation to stop.
		//
		//                   1  = Called during the simulation. FORCE/ADDMAS output expected.
		//
		//                   99 = Termination. This routine is called once with mode 99
		//                        at the end of the simulation.
		//
		// I_Control[100]  - User-defined integer control parameters input in .DAT file.
		// (int*)
		//
		// R_Control[100]  - User-defined real control parameters input in .DAT file.
		// (float*)
		//
		// Nstruc int*     - Number of structures in the the simulation
		//
		// Time float*     - The current time (see Stage below)
		//
		// Timestep float* - The current timestep (DT, see Stage below)
		//
		// Stage int*      - The stage of the integration scheme. AQWA time integration is
		//                   based on a 2-stage predictor corrector method. This routine is
		//                   therefore called twice at each timestep, once with STAGE=1 and
		//                   once with STAGE=2. On stage 2 the position and velocity are
		//                   predictions of the position and velocity at TIME+DT.
		//                   e.g. if the initial time is 0.0 and the step 1.0 seconds then
		//                   calls are as follows for the 1st 3 integration steps:
		//
		//                   CALL USER_FORCE(.....,TIME=0.0,TIMESTEP=1.0,STAGE=1 ...)
		//                   CALL USER_FORCE(.....,TIME=0.0,TIMESTEP=1.0,STAGE=2 ...)
		//                   CALL USER_FORCE(.....,TIME=1.0,TIMESTEP=1.0,STAGE=1 ...)
		//                   CALL USER_FORCE(.....,TIME=1.0,TIMESTEP=1.0,STAGE=2 ...)
		//                   CALL USER_FORCE(.....,TIME=2.0,TIMESTEP=1.0,STAGE=1 ...)
		//                   CALL USER_FORCE(.....,TIME=2.0,TIMESTEP=1.0,STAGE=2 ...)
		//
		// Cog[Nstruc][3]  - Position of the Centre of Gravity in the Definition axes.
		//
		// Position[Nstruc][6] - Position of the structure in the FRA - angles in radians
		// (float*)
		//
		// Velocity[Nstruc][6] - Velocity of the structure in the FRA
		// (float*)              angular velocity in rad/s
		//
		//
		// Output Parameter Description:
		//
		// Force[Nstruc][6] - Force on the Centre of gravity of the structure. NB: these
		// (float)           forces are applied in the Fixed Reference axis e.g.
		//                   the surge(X) force is ALWAYS IN THE SAME DIRECTION i.e. in
		//                   the direction of the X fixed reference axis.
		//
		// Addmass[Nstruc][6][6]
		// (float)         - Added mass matrix for each structure. As the value of the
		//                   acceleration is dependent on FORCES, this matrix may be used
		//                   to apply inertia type forces to the structure. This mass
		//                   will be added to the total added mass of the structure at each
		//                   timestep at each stage.
		//
		// Errorflag int*  - Error flag. The program will abort at any time if this
		//                   error flag is non-zero. The values of the error flag will
		//                   be output in the abort message.


	

		int i, j;
		int struc = 1;

		//------------------------------------------------------------------------
		// MODE#0 - Initialise any summing variables/open/create files.
		//          This mode is executed once before the simulation begins.
		//------------------------------------------------------------------------

		if (*Mode == 0)
		{
		}

		//------------------------------------------------------------------------
		// MODE#1 - On-going - calculation of forces/mass
		//------------------------------------------------------------------------

		else if (*Mode == 1)
		{
			for (struc = 0; struc < *Nstruc; struc++)
			{
				for (i = 0; i < 6; i++)
				{
					Force[struc][i] = 2 * Velocity[struc][i];
					for (j = 0; j < 6; j++)
					{
						Addmass[struc][j][i] = 0.0;
					}
				}
			}
			*ErrorFlag = 0;
		}

		//------------------------------------------------------------------------
		// MODE#99 - Termination - Output/print any summaries required/Close Files
		//           This mode is executed once at the end of the simulation
		//------------------------------------------------------------------------

		else if (*Mode == 99)
		{
		}

		//------------------------------------------------------------------------
		// MODE# ERROR - OUTPUT ERROR MESSAGE
		//------------------------------------------------------------------------

		else
		{
		}

		return;
	}
}

--------------------------------------------------------------------

 

//user_force.h
#pragma once

extern "C"
{

	__declspec(dllexport) void _stdcall USER_FORCE(int* Mode, int I_Control[100], float R_Control[100],
		int* Nstruc, float* Time, float* TimeStep, int* Stage,
		float Position[][6], float Velocity[][6], float Cog[][3],
		float Force[][6], float Addmass[][6][6], int* ErrorFlag)
}

--------------------------------------------------------------------------

// dllmain.cpp : Define o ponto de entrada para o aplicativo DLL.
#include "pch.h"

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

Depois de usar o comando dumpbin /exports na DLL gerada, esta é a mensagem:

 Section contains the following exports for user_force64.dll

    00000000 characteristics
    FFFFFFFF time date stamp
        0.00 version
           1 ordinal base
           1 number of functions
           1 number of names

    ordinal hint RVA      name

          1    0 00011046 _USER_FORCE@52 = @ILT+65(_USER_FORCE@52)

  Summary

        1000 .00cfg
        1000 .data
        1000 .idata
        1000 .msvcjmc
        2000 .rdata
        1000 .reloc
        1000 .rsrc
        6000 .text
       10000 .textbss

E quando uso o mesmo comando em uma DLL funcional, este é o output

Dump of file user_force64.dll

File Type: DLL

  Section contains the following exports for user_force64.dll

    00000000 characteristics
    5D3F15AA time date stamp Mon Jul 29 12:50:02 2019
        0.00 version
           1 ordinal base
           1 number of functions
           1 number of names

    ordinal hint RVA      name

          1    0 00001000 USER_FORCE

  Summary

        1000 .data
        1000 .pdata
        1000 .rdata
        1000 .reloc
        1000 .rsrc
        1000 .text

 

Aparentemente errei alguma coisa na compilação, o que causou a diferença no nome da função exportada.

Link to comment
Share on other sites

  • Administrators
Citar

_USER_FORCE@52 = @ILT+65(_USER_FORCE@52)

Interessante... eu nunca tinha visto esse padrão de nome. Não me parece o name decoration / mangling normal de C++. E mesmo assim o extern "C" deveria impedir a decoração, claro, já que C não tem sobrecarga de funções. Será que não há uma função com o mesmo nome nessa pch.h?

Achei uma discussão longa de um usuário com um problema muito parecido, inclusive ele cita o mesmo padrão de nomes aqui.

Bem, eu iria com baby steps, saca? Compila a menor possível, checa os exports e, se tiver tudo certo, vai crescendo o código e checando os exports da DLL compilada, até encontrar o problema. Por exemplo, o código abaixo foi sem problemas aqui:

// user_force.h

int _stdcall USER_FORCE(int a, int b);

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
// user_force.cpp

extern "C"

__declspec(dllexport) int _stdcall USER_FORCE(int a, int b) {
    return a + b;
}

Compilação:

c:\Users\admin\Documents>cl /LD user_force.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 15.00.30729.01 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

user_force.cpp
Microsoft (R) Incremental Linker Version 9.00.30729.01
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:user_force.dll
/dll
/implib:user_force.lib
user_force.obj
   Creating library user_force.lib and object user_force.exp

Checagem dos exports:

c:\Users\admin\Documents>dumpbin /exports user_force.dll
Microsoft (R) COFF/PE Dumper Version 9.00.30729.01
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file user_force.dll

File Type: DLL

  Section contains the following exports for user_force.dll

    00000000 characteristics
    5ECD966F time date stamp Tue May 26 23:21:35 2020
        0.00 version
           1 ordinal base
           1 number of functions
           1 number of names

    ordinal hint RVA      name

          1    0 00001000 USER_FORCE

  Summary

        3000 .data
        1000 .pdata
        2000 .rdata
        1000 .reloc

Daí seria ir acrescentando o código e recompilando toda hora, até achar o problema... Mas pode ser que alguém saiba exatamente o que ocorre aqui e ajude também.

Abraço!

Link to comment
Share on other sites

Agradeço sua resposta, Fernando Mercês

 

Fiz exatamente como você fez. Porém a checagem dos exports foi a seguinte:

 

File Type: DLL

  Section contains the following exports for user_force.dll

    00000000 characteristics
    FFFFFFFF time date stamp
        0.00 version
           1 ordinal base
           1 number of functions
           1 number of names

    ordinal hint RVA      name

          1    0 00001000 _USER_FORCE@8

  Summary

        2000 .data
        6000 .rdata
        1000 .reloc
        B000 .text

C:\Users\l04392\source\repos\teste\teste>


Esqueci de comentar quando criei o post que o manual do ANSYS diz: On Windows, the name of the .DLL file must be user_force64.dll, and the file must be located in the same directory as the Aqwa executables (typically C:\Program Files\ANSYS Inc\v201\aqwa\bin\winx64)" 

Então creio que basta compilar e colocar nesta pasta, certo?  Mesmo assim, dá "Solver aborted". A simulação simplesmente não roda

 

 Fernando Mercês Você poderia me enviar seu projeto do VS?

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...