| auteur : Farscape | Après avoir lancé AppWizard trois choix possibles sont disponibles à partir du choix MFC AppWizard DLL :
- Regular dll with MFC staticaly linked.
- Regular dll with using shared MFC DLL
- MFC extension DLL (using shared MFC DLL)
Les deux premiers sélectionnent le mode de travail avec les MFC :
une DLL normale liée de manière statique aux MFC et une DLL normale liée de manière dynamique aux MFC (shared MFC DLL)
La troisième solution correspond à la construction d'une DLL d'extension des MFC.
Regular dll with MFC staticaly linked :
La construction d'une DLL liée de manière statique aux MFC permettra l'utilisation de celle-ci quelque soit le programme : WIN32 ou autre qu'il fasse appel ou non aux MFC ,l'inconvénient :la taille de la DLL étant donné que le code des MFC est incorporé dedans .
Regular dll with using shared MFC DLL:
La construction d'une DLL liée de manière dynamique aux MFC peut aussi être utilisée par tout programme WIN32 ou autre par contre la présence des DLL liées aux MFC sera exigée dans l'environnement d'exécution.
L'option sélectionnée ici sera une DLL avec les MFC en DLL partagées.
Après génération du projet par AppWizard il ne reste plus qu'à écrire les fonctions dans la DLL.
Dans mon exemple la définition sera dans le fichier interface.h et le code dans interface.cpp.
# ifdef _WINDLL
# define DLLDEC __declspec ( dllexport )
# else
# define DLLDEC __declspec ( dllimport )
# endif
# ifdef __cplusplus
extern " C "
{
# endif
DLLDEC void TestDll ();
# ifdef __cplusplus
}
# endif
|
# include "stdafx.h"
# include "interface.h"
# define WM_TEST WM_USER + 100
void TestDll ()
{
CFrameWnd * pFrame= (CFrameWnd * )AfxGetMainWnd ();
CView * pView= pFrame- > GetActiveView ();
pView- > PostMessage (WM_TEST);
}
|
Pour exporter une fonction d'une DLL il faut employer le mot clef dllexport conjointement avec le mot clef __declspec.
L'exemple ci-dessus permet d'exporter la fonction TestDll , celle-ci sera disponible aussi bien dans un source C++ ou C grâce à l'utilisation de la commande extern « C ».
Il ne reste plus qu'à compiler, linker l'ensemble et à placer la DLL dans le répertoire d'exécution du programme appelant.
Insertion de la DLL dans un projet :
Il faudra rajouter dans le fichier testdll.lib dans l'onglet link du projet. :Project Settings onglet link.
Et ajouter le fichier interface.h pour utiliser les fonctions de la dll .
http://farscape.developpez.com/Samples/creationdll.pdf
|
| auteur : Farscape | Dans quels cas utiliser une DLL de ressources ?
A chaque fois que l'on voudra avoir un programme avec une interface multilingue, ou, par exemple s'adapter à une résolution d'écran :une dll de ressources pour la résolution 800*600 .
Procédure pour créer une DLL de ressources :
Après avoir lancé AppWizard choisir l'option :Win32 dynamic link Library .
Ensuite prendre l'option an empty DLL project.
Insérer le fichier ressource.h et le fichier .rc dans le projet.
Réglages des options de construction de la DLL :
Project setting onglet link :
Cocher les options :
- Doesn't produce.lib
- Ignore all default libraries
Et rajouter dans la partie project options : /noentry pour éviter
d'avoir une référence à la fonction _main au link.
Compiler et linker.
|
| auteur : matazz | 1ere étape, Dans la "ResourceView" :
Dans l'onglet "ResourceView" de VC, choisir par exemple une boîte de dialogue, faire bouton droit "insert copy".
Il apparaît alors une boîte de dialogue demandant le langage pour lequel la copie va être affectée.
Imaginons que l'on choisisse "English (UK)" dans le combo, il faut saisir dans l'EditBox dessous une valeur pour le compilateur (pour savoir quelle ressource il va linker dans l'exe) par exemple "_ENG".
Ensuite évidement il faut traduire la ressource.
Il faut faire de même avec toutes les ressources.
Remarque :
Pour la string table il faut faire aussi "insert copy", on choisit la langue mais on ne saisit pas de condition.
On traduit les textes mais là (va savoir pourquoi), le compilo link toutes les stringtable et Windows ira chercher la StringTable de l'exe correspondant à son langage .
Bref, La stringTable est très interessante pour les messagebox :
Dans le Code on fait:
CString Message;
Message.LoadString (IDS_TASTRING_POUR_CE_MESSAGE);
|
2eme étape la configuration du Workspace :
Ensuite c'est là que ça devient intéressant il faut configurer le Workspace:
Dans le menu BUILD->Configurations
S'ouvre une boîte de dialogue :
Cliquer sur Add et la rajouter une debug par exemple Debug_ENG et une release : Release_ENG
Enfin taper Alt+F7 ou Menu Projects->Settings
Choisir par exemple le projet Release_ENG
Dans l'onglet "Ressource"
Dans le combo "Language" choisir la langue ici English (UK) et dans l'EditBox "Preprocessor Definition" rajoute ",_ENG"
Ainsi seront linké dans l'exe que les ressources avec la condition _ENG
2eme remarque :
du coup il faut faire pareil avec la version Française (Condition _FRA par exemple)
Si l'on teste l'exe anglais sur un windows français on verra que les menus, les messagebox sont française, car les deux versions de la stringtable sont dans l'exe et windows choisit la plus apropriée à la version de Windows .
Bilan :
Il n'y as pas vraiment d'avantages ou d'inconvéniant par rapports aux DLL de resources, si ce n'est que l'Executable peut être plus lourd car si vous faites beaucoup de version il aura toutes les StringTables (pas les boites de dialogues).
C'est une question de goût on va dire...
|
| auteur : Farscape | On utilisera le stockage des ressources dans une DLL pour chaque langue.
Exemple :
Dans un projet existant dont les ressources sont en Anglais on veut implémenter les mêmes ressources mais en Français.
Procédure :
Dans le projet principal on appelle AppWizard pour la création d'un nouveau projet en utilisant l'option add to curent workspace.
Choisir l'option Win32 dynamic link Library .
Donner un nom à la DLL qui correspondra à la langue implémentée Exemple :ResDllFr
Ensuite prendre l'option an empty DLL project.
Réglages des options de construction de la DLL :
Project setting onglet link :
Cocher les options :
- Doesn't produce.lib
- Ignore all default libraries
Et rajouter dans la partie project options : /noentry pour éviter d'avoir une référence à la fonction _main au link.
Copier à partir du projet principal dans le répertoire de la DLL:
Le fichier ressource.h et le fichier .rc .
Copier aussi le répertoire res.
Procédure sous .NET:
Dans l'explorateur de projet (solution) faire click droit :
Ajouter / nouveau projet
Sélectionner le type de projet win32
Sélectionner le répertoire du projet principal
Donner un nom à la DLL qui correspondra à la langue implémentée Exemple :ResDllFr
Faire ok
Sélectionner paramètres de l'application
Cocher DLL et projet vide.
Valider avec le bouton terminer
Réglages des options de construction de la DLL :
Sur le nouveau projet faire click droit propriétés :
Sélectionner le chapitre éditeur de liens :
Option avancée :
Dans la rubrique DLL de ressource uniquement mettre oui
Option Entrée :
Dans la rubrique Toutes les bibliothèques par défaut ignorées mettre oui
Copier à partir du projet principal dans le répertoire de la DLL:
Le fichier ressource.h et le fichier .rc .
Copier aussi le répertoire res.
Ajouter par l'option ajouter un élément existant le .rc et le fichier ressource.h au projet .
Traduire les ressources dans la langue appropriée.
Compiler linker la DLL.
Sélection de la DLL dans le programme principal :
Dans la fonction InitInstance de la classe d'application on lira la DLL concernée :
m_bFrenchRes= (GetProfileInt (" Language " ," SetInFr " ,0 )= = 1 );
if (m_bFrenchRes)
{
HINSTANCE dll= LoadLibrary (" ResDllFr.dll " );
if (dll) AfxSetResourceHandle (dll);
}
|
Dans la fonction ExitInstance on libèrera les ressources:
int CTestResDllApp:: ExitInstance ()
{
HMODULE hDLL = AfxGetResourceHandle ();
if (hDLL ! = AfxGetInstanceHandle ())
{
AfxSetResourceHandle (AfxGetInstanceHandle ());
FreeLibrary (hDLL);
}
return CWinApp:: ExitInstance ();
}
|
|
| auteur : Farscape | Une DLL d'extensions permet l'export de classes complètes que le client peut instancier et même dériver.
Note : L'utilisation d'une DLL d'extensions impose l'utilisation des MFC en DLL partagées.
Comment procéder :
Au lancement de AppWizard par le menu file new Project.
Sélectionner l'option MFC AppWizard(dll)
Puis l'option MFC extension DLL (using shared MFC DLL).
Le squelette de la DLL est généré il ne reste plus qu'à implémenter les différentes classes en rajoutant la macro AFX_EXT_CLASS devant chaque nom de classe à exporter, comme dans l'exemple ci-dessous :
class AFX_EXT_CLASS CMyListBox : public CListBox
{
public :
CMyListBox ();
public :
public :
public :
virtual ~ CMyListBox ();
protected :
DECLARE_MESSAGE_MAP ()
} ;
|
Une fois la DLL compilée et linkée :
On utilisera le même include pour la définition des classes exportées dans la DLL et l'application MFC .
Le .lib de la DLL devra être rajouté au link de l'application MFC.
|
| auteur : Farscape | Pour sortir proprement du programme il ne faut surtout pas faire exit(0) à partir de la DLL mais faire la demande de fermeture sur le thread principal du programme .
Il suffira d'envoyer la commande suivante à partir de la DLL :
AfxGetMainWnd ()- > PostMessage (WM_SYSCOMMAND,SC_CLOSE,0 );
|
|
| auteur : Farscape | La distribution des DLL partagées pour une application Visual VC6.0 est nécessaire pour les systèmes antérieurs à Windows 2000 .
Les principales DLL sont à jour sur les systèmes récents.
Pour infos voici la liste des principales DLL concernées :
et éventuellement :
- MSVCP60.DLL
- NTDLL.DLL
- MSVCIRT.DLL
il est à noter que la mise à jour de IE 5 ou 6.0 mets à jour un grand de composant sur ces systèmes....
Néanmoins pour distribuer une application en DLL partagées on dispose d'un utilitaire VCREDIST.EXE
consulter la note d'informations MSDN à ce sujet :
Redistributing Microsoft Visual C++ 6.0 Applications
Note :VCREDIST.EXE est mis à jour avec la distribution du service pack de Visual 6.0 ,on le trouve généralement dans le répertoire :
FRENCH\VS60SP5\VC98\REDIST\VCREDIST.EXE pour le SP5 .
|
| auteur : matazz | En théorie, seuls les types de base sont passables d'une DLL C++ à VB:
Un petit résumé provenant de l'aide de VC++ et VB sur les types de Base :
EN VB :
Byte 1 byte 0 to 255
Boolean 2 bytes True or False
Integer 2 bytes -32,768 to 32,767
Long (long integer) 4 bytes -2,147,483,648 to 2,147,483,647
Single(single-precision floating-point) 4 bytes
Double (double-precision floating-point) 8 bytes
EN C++ :
Type Size
char, unsigned char, signed char 1 byte
short, unsigned short 2 bytes
int, unsigned int 4 bytes
long, unsigned long 4 bytes
float 4 bytes
double 8 bytes
long double1 8 bytes
Conclusion :
C++ | VB
char == byte
bool == Boolean
short== Integer
int == Long
long == Long ou rien
float == Single
double ==Double
Résumé :
Une fonction déclarée en C++ comme suit :
bool TestVB_Cpp (int Entier, double Reel, char Caractere, char * Chaine)
|
peut être récupérée en VB par la methode suivante :
Public Declare Function TestVB_Cpp Lib " MaDLL.dll "
(ByVal Entier As Long, ByVal Reel As Double, ByVal Caractere As Byte, ByVal Chaine As String) As Boolean
|
En pratique il existe un moyen détourné de manipuler des objets d'une classe C++ d'une DLL depuis VB :
En effet une adresse mémoire étant stockée sur 4 BYTES, on peut déclarer en C++ un pointeur de ce que l'on veut et le récupérer en VB grace à une variable déclarée en ByRef Long.
Par exemple, on peut manipuler les fonctions BMP du GDI
J'avais trouvé ça sur internet sachant que "&H" en VB correspond à "0x" de C++.
La structure BITMAP C++ correspond en VB à :
' **********BITMAP****************
Public Const SRCCOPY = & HCC0020
Public Const DIB_RGB_COLORS = 0
Public Type BITMAP
biSize As Long
biWidth As Long
biHeight As Long
biPlanes As Integer
biBitCount As Integer
biCompression As Long
biSizeImage As Long
biXPelsPerMeter As Long
biYPelsPerMeter As Long
biClrUsed As Long
biClrImportant As Long
End Type
' **********WAPI****************
Public Declare Function DeleteObject Lib " gdi32 " (ByVal hObject As Long) As Long
Public Declare Function GetObject Lib " gdi32 " Alias
" GetObjectA " (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
Public Declare Function GetBitmapBits Lib " gdi32 "
(ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
Public Declare Function SetBitmapBits Lib " gdi32 "
(ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
|
Sachant que la structure VB BITMAP correspond à ceci en C++
typedef struct tagBITMAPINFOHEADER{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER;
|
Conclusion : Avec une DLL C++ contenant une Classe, VB peut manipuler un pointeur sur un objet de cette classe et le passer à des fonctions globales de la DLL.
Par contre il n'existe pas à ma connaissance de moyen d'exporter un Objet C++ avec ces méthodes afin que VB puisse les appeler depuis une DLL. La seule solution est un ActiveX.
|
| auteur : Farscape | Pour définir l'accès procéder comme suit :
Dans le menu view option ressources includes.
Rajouter l'include des ressources contenant les définitions des identifiants de la DLL à la suite de la ligne
# include "afxres.h"
# include "MyLibres.h" // ressources DLL
|
Dans la seconde partie de la boîte de dialogue rajouter la référence au fichier .rc de la DLL à la suite des définitions existantes :
# define _AFX_NO_SPLITTER_RESOURCES
# define _AFX_NO_OLE_RESOURCES
# define _AFX_NO_TRACKER_RESOURCES
# define _AFX_NO_PROPERTY_RESOURCES
# if ! defined ( AFX_RESOURCE_DLL ) | | defined ( AFX_TARG_FRA )
# ifdef _WIN32
LANGUAGE 12 , 1
# pragma code_page ( 1252 )
# endif / / _WIN32
# include "res\TestMdi.rc2" // non-Microsoft Visual C++ edited resources
# include "l.fra\afxres.rc" // Standard components
# include "l.fra\afxprint.rc" // printing/print preview resources
# endif
# include « MyLib.rc » // fichier ressources DLL
|
Sauvegarder et recompiler les ressources.
|
| auteur : Gabrielly |
Voici un petit rappel pour ce qui est d'une dll normale ou régulière liée de manière dynamique aux MFC
Citation MSDN:
Une DLL normale liée de manière dynamique aux MFC est une DLL qui utilise les MFC en interne,
et les fonctions exportées de la DLL peuvent être appelées par des exécutables MFC ou non-MFC.
Comme son nom l'indique, ce type de DLL est généré à l'aide de la version bibliothèque de
liaisons dynamiques des MFC (appelée également version partagée des MFC).
Les fonctions sont généralement exportées à partir d'une DLL normale à l'aide de l'interface C standard.
Vous devez ajouter la macro AFX_MANAGE_STATE au début de toutes les fonctions exportées des
DLL normales qui sont liées de manière dynamique aux MFC pour définir l'état du module en cours
comme étant celui de la DLL.
Pour cela, ajoutez la ligne de code suivante au début des fonctions exportées à partir de la DLL :
AFX_MANAGE_STATE (AfxGetStaticModuleState ( ))
|
Une dll normale ou régulière possède un objet CWinApp comme n'importe quel module exe MFC.
Si nous voulons obtenir l'objet application dans le module exe nous faisons
CDuplicataApp* pTheApp = static_cast < CDuplicataApp* > (AfxGetApp ());
ATLASSERT (pTheApp);
|
où Duplicata est le module exe.
Comment obtenir ce même pointeur dans une dll régulière tout en sachant qu'un appel à AfxGetApp()
retourne le CWinApp de la dll.
Voici comment nous pouvons procéder:
Duplicata est un module exe et
Duplicata.Data est une dll régulière liée dynamiquement aux MFC.
Dans ce genre de dll, toute fonction exportée doit inclure la macro
AFX_MANAGE_STATE (AfxGetStaticModuleState ( ))
|
au début de la définition de la fonction afin que les MFC puissent définir l'état du module en cours.
Voici du code.
INT_PTR WINAPI ShowQuerySheet (UINT iSelectedPage, bool & bMultiSelectedQueryPage)
{
CDuplicataApp* pTheApp = static_cast < CDuplicataApp* > (AfxGetApp ());
ATLASSERT (pTheApp);
AFX_MANAGE_STATE (AfxGetStaticModuleState ());
CDuplicataDataApp* pTheDll = static_cast < CDuplicataDataApp* > (AfxGetApp ());
ATLASSERT (pTheDll);
}
|
En demeurant dans le contexte du module exe, avant que MFC rétablisse l'état du module en cours, nous pouvons récupérer
le CWinApp du module exe mais nous ne pouvons utiliser aucun objet de la dll.
Mais une fois que l'état du module en cours est rétabli, alors les objets de la dll sont maintenant disponibles et
à l'aide du même AfxGetApp() nous obtenons le CWinApp de la dll.
Les pointeurs obtenus sont valides et vous pouvez le vérifier avec le débogueur.
Dans le cas d'une dll MFC d'extension nous n'avons pas ce problème de changement de contexte de module d'état
avec AFX_MANAGE_STATE car le CWinApp est unique et est celui du module exe.
|
| auteur : Farscape | Avec Visual 2005 les dll concernant la bibliothèque CRT et MFC ont changé.
De ce fait la plupart des PC récents ne disposent pas des fichiers requis pour exécuter les programmes construits avec Visual 2005.
Vous trouverez sur ce lien l'accès à un setup permettant de distribuer les DLL sur un PC cible vcredist_x86.exe
Ce package installe les composants du runtime des bibliothèques C Runtime (CRT), Standard C++, ATL, MFC, OpenMP et MSDIA.
Note : ce fichier est aussi disponible dans l'environnement de développement à l'emplacement suivant :
C:\Program Files\Microsoft Visual Studio8\SDK\v2.0\BootStrapper\Packages\vcredist_x86\vcredist_x86.exe
Si on ne veut pas distribuer de DLL ,il faudra lier statiquement les MFC et sélectionner dans l'onglet C++ / option génération de code / bibliothèque runtime : Multithread (/MT)
Néanmoins il faudra veiller à ne pas mélanger les modes de fonctionnement avec la CRT en Multithread DLL et statique, pour éviter les problèmes sur les libérations d'objets entre modules ou partage de ressources fichiers.
|
| auteur : Farscape | Il y a deux manières de construire une application MFC :
-La plus utilisée c'est d'utiliser les MFC en dll partagée, ce qui implique que la bibliothèque de runtime C (CRT) soit aussi dans ce mode partagé ( Multithread DLL :/MD ).
Avantage : l'exécutable produit est plus léger puisqu'il ne comporte pas les MFC et la dll de la CRT.
Inconvénient : il faut distribuer un ensemble de DLL sur le poste cible.
Il existe plusieurs manières de procéder :
-Utiliser l'utilitaire vcredist_x86.exe évoqué dans cet autre poste de la faq Comment distribuer une application C++ avec Visual 2005 ?
.
-Créer un projet de déploiement pour le projet.
-Enfin copier manuellement le programme et ses dépendances dans un répertoire.
Comment procéder :
Créer un répertoire de distribution en dehors de program file (pour éviter les problèmes sous vista).
Copier son exécutable dedans.
Ensuite copier les fichiers contenus dans les répertoires :
C:\Program Files\Microsoft Visual Studio 9.0\VC\redist\x86\Microsoft.VC90.CRT
Et
C:\Program Files\Microsoft Visual Studio 9.0\VC\redist\x86\Microsoft.VC90.MFC
-La deuxième option de construction du programme consiste à utiliser les MFC dans une bibliothèque statique, la bibliothèque de runtime C (CRT) doit suivre le même mode statique ( Multithread static : /MT ).
Avantage : un exécutable autonome
Inconvénients : taille de l'exécutable non négligeable, surtout si on utilise les nouvelles MFC ?
Autre point : difficulté de construction du programme si on dispose d'un ensemble de bibliothèques tierces : il faudra en effet veiller à ce que celles-ci travaillent dans le même mode surtout au niveau de la bibliothèque de runtime C .
|
lien : Comment distribuer une application C++ avec Visual 2005 ?
|
| auteur : nico-pyright(c) | En utilisant les méthodes LoadLibrary, GetProcAddress et FreeLibrary.
Exemple pour charger dynamiquement l'API MessageBox :
typedef INT (WINAPI* PFNMESSAGEBOX)(HWND, LPCTSTR , LPCTSTR, UINT);
static PFNMESSAGEBOX g_pfnMessageBox = NULL ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
HMODULE hmodUser32 = LoadLibrary (TEXT (" USER32 " ));
if (hmodUser32 ! = NULL )
{
# ifdef UNICODE
g_pfnMessageBox = (PFNMESSAGEBOX) GetProcAddress (hmodUser32, " MessageBoxW " );
# else
g_pfnMessageBox = (PFNMESSAGEBOX) GetProcAddress (hmodUser32, " MessageBoxA " );
# endif
}
g_pfnMessageBox (NULL , TEXT (" Test " ), TEXT (" Titre " ), 0 );
if (hmodUser32 ! = NULL )
FreeLibrary (hmodUser32);
return 0 ;
}
|
|
Consultez les autres F.A.Q.
|
|