Tag: SO2 – 2021 – Ficha 3 v.2.6 – DLL.pdf
sessão 3 – DLL – Bibliotecas de ligação dinâmica
Bibliografia de apoio:
Material das aulas teóricas e incluindo documentos de apoio ao tópico de bibliotecas dinâmicas
Capítulo 5 do Livro Windows System Programming (da Bibliografia) (pags. 167 em diante)
MSDN:
Run-Time Dynamic Linking (Overview geral) https://docs.microsoft.com/en-us/windows/win32/dlls/run-time-dynamic-linking
Using Run-Time Dynamic Linking (Inclui exemplos) https://docs.microsoft.com/en-us/windows/win32/dlls/using-run-time-dynamic-linking
Referência do API para lidar com DLL (libloaderapi) https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/
Manipulação do registry: cria uma chave (se não existir), e abre a chave
#include <windows.h>
#include <tchar.h>
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
#define TAM 200
int _tmain(int argc, TCHAR* argv[]) {
HKEY chave;
TCHAR nome[TAM] = TEXT("SOFTWARE\\SO2");
TCHAR par_nome[TAM] = TEXT("1º autor");
TCHAR par_valor[TAM] = TEXT("João Sá");
DWORD o_que_aconteceu;
DWORD n_vezes = 1;
DWORD tam = sizeof(DWORD);
#ifdef UNICODE
_setmode(_fileno(stdin), _O_WTEXT);
_setmode(_fileno(stdout), _O_WTEXT);
_setmode(_fileno(stderr), _O_WTEXT);
#endif
if (RegCreateKeyEx(HKEY_CURRENT_USER, nome, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &chave, &o_que_aconteceu) == ERROR_SUCCESS)
{
if (o_que_aconteceu == REG_CREATED_NEW_KEY)
{
_tprintf(TEXT("chave %s criada com sucesso !"), nome);
RegSetValueEx(chave, par_nome, 0, REG_SZ, (LPBYTE)par_valor, (_tcslen(par_valor) + 1) * sizeof(DWORD));
RegSetValueEx(chave, TEXT("Número de execuções"), 0, REG_DWORD, (LPBYTE)&n_vezes, sizeof(DWORD));
}
else
{
_tprintf(TEXT("chave %s aberta com sucesso\n"), nome);
RegQueryValueEx(chave, TEXT("Número de execuções"), 0, NULL, (LPBYTE)&n_vezes, &tam);
n_vezes++;
_tprintf(TEXT("Esta é a %d vez que o programa é executado"), n_vezes);
RegSetValueEx(chave, TEXT("Número de execuções"), 0, REG_DWORD, (LPBYTE)&n_vezes, sizeof(DWORD));
}
return -1;
}
else
{
_tprintf(TEXT("Erro ao abrir/criar chave %s"), nome);
}
RegCloseKey(chave);
return 0;
}
Referência do API para lidar com DLL: LINK
Fazer a leitura pelo modo implícito na arquitetura x86
//base.c
#include "principal.h"
#include <windows.h>
#include <tchar.h>
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
int _tmain(int argc, TCHAR* argv[])
{
double local;
#ifdef UNICODE
_setmode(_fileno(stdin), _O_WTEXT);
_setmode(_fileno(stdout), _O_WTEXT);
_setmode(_fileno(stderr), _O_WTEXT);
#endif
//usar a variavel DLL
do
{
_tprintf(TEXT("Valor atual para a variavel global da DLL:%lf\nNovo valor:"), factor);
_tscanf_s(TEXT("%lf"), &factor);
_tprintf(TEXT("Valor atual para a variavel global da DLL:%lf\n"), factor);
_tprintf(TEXT("Valor a passar como argumento à função da DLL:"));
_tscanf_s(TEXT("%lf"), &local);
_tprintf(TEXT("Resultado da função da DLL:%lf\n"), applyFactor(local));
} while (factor != -1);
return 0;
}
//base.h #pragma once #include <windows.h> #ifdef SO2F3DLL_EXPORTS #define DLL_IMP_API __declspec(dllexport) #else #define DLL_IMP_API __declspec(dllimport) #endif DLL_IMP_API double factor; //variavel global, serve para cada processo //cada processo acede à sua DLL_IMP_API double applyFactor(double v); //funcao
carregar para o projeto o ficheiro .LIB, e colocar o ficheiro DLL na pasta do executável

Fazer a leitura pelo modo explicito
_mais independente
_mais controlo ao programador (pode ser usada apenas na altura em que preciso: da variável, da função, .. que está na DLL)
_só preciso quando for executar o programa
_não vai ser necessário o ficheiro h com a “estrutura” que consta no DLL
#include <windows.h>
#include <tchar.h>
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
#define TAM 256
int obterValorUtilizador()
{
int valor = 0;
TCHAR buffer[TAM] = _TEXT("");
//obter o nome da chave
_tprintf(_TEXT("introduza um valor: "));
fflush(stdin);
_fgetts(buffer, TAM, stdin);
//retirar o \n
buffer[_tcsclen(buffer) - 1] = '\0';
valor = _tstoi(buffer);
return valor;
}
int _tmain(int argc, TCHAR* argv[])
{
int a, b;
int sair = 0;
#ifdef UNICODE
_setmode(_fileno(stdin), _O_WTEXT);
_setmode(_fileno(stdout), _O_WTEXT);
_setmode(_fileno(stderr), _O_WTEXT);
#endif
_tprintf(TEXT("Valor inicial da variavel da DLL \n \n"));
double (*ptrVar)(double) = NULL;
double (*ptrFunc)(double) = NULL;
HINSTANCE hLib = LoadLibrary(TEXT("so2x86.dll"));
if (hLib != NULL)
{
ptrFunc = (double(*)(double))GetProcAddress(hLib, "applyFactor");
ptrVar = (double(*)(double))GetProcAddress(hLib, "factor");
_tprintf(TEXT("parte2\n \n"));
if (ptrVar != NULL &amp;&amp; ptrFunc != NULL)
{
_tprintf(TEXT("parte3\n \n"));
_tprintf(_TEXT("Valor inicial da variavel da DLL: %f\n"), *((double*)ptrVar));
do
{
a = 0;
b = 0;
_tprintf(_TEXT("vairavel (a)\n"));
a = obterValorUtilizador();
if (a == 1)
{
sair = 1;
break;
}
*((double*)ptrVar) = (double)a;
_tprintf(_TEXT("Valor novo da variavel da DLL: %f\n"), *((double*)ptrVar));
b = obterValorUtilizador();
_tprintf(_TEXT("Valor novo da variavel da DLL: %f\n"), ptrFunc(b));
} while (sair != 1);
}
if (hLib != NULL)
{
FreeLibrary(hLib);
}
}
return 0;
}
Criar uma DLL
Mudar o projeto para concretizar uma DLL e não um ficheiro executavel (nas propriedades do projeto)

O visual studio sugere uma variável de nome _WINDLL

//source.c
#include <tchar.h>
#include <stdlib.h>
//#define SO2F3DLL_EXPORTS
//vou usar a constante sugerida pelo VS
#include <time.h>
#include "Header.h" //deve ser feito depois do define
double varGlobal = 4;
int varInternaDLL = 5;
double aplicarFactor(double argumento)
{
_tprintf(_TEXT("esta é a minha DLL"));
return varGlobal;
}
double geraAleatorio(int valor_min, int valor_max)
{
static int n_vezes = 1;
if(n_vezes == 1)
{
srand(time(NULL));
n_vezes++;
}
return rand() % (valor_max - valor_min) + valor_min;
}
#pragma once //header.h //diretivas para o importar e para o exportar //SO2F3DLL_EXPORTS é uma constante que fou ter que partilhar e vai para o .c //#ifdef SO2F3DLL_EXPORTS #ifdef _WINDLL #define DLL_IMP_API __declspec(dllexport) #else #define DLL_IMP_API __declspec(dllimport) #endif //porque quero que outros usem, e tem que ser exportado DLL_IMP_API double varGlobal; //não vai ser exportada int varInternaDLL; double geraAleatorio(int valor_min, int valor_max); DLL_IMP_API double aplicarFactor(double argumento);
