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);