none
Affichage des documents PDF ? RRS feed

  • Question

  • Bonjour,

    Quel type de contrôle peut-on utiliser pour afficher un fichier PDF ?

    J'ai une application qui gère des documents PDF et je voudrais proposer aux utilisateurs un aperçu d'un document sélectionné.

    Merci d'avance pour toute aide

    vendredi 11 août 2017 00:15

Réponses

  • Exemple minimal en C++/Win32 affichant le PDF directement à partir du fichier.

    Si l'on veut afficher le contrôle vide puis charger un fichier par les interfaces Acrobat, on le crée par exemple avec

    TEXT("AcroPDF.PDF.1") au lieu du nom du fichier.

    Ensuite, on génère puis ajoute les interfaces en les important.

    Par ex sur mon poste c'est :

    #import "C:\Program Files (x86)\Common Files\Adobe\Acrobat\ActiveX\AcroPDf.dll" named_guids

    puis je commente cette ligne et ajoute

    #include "acropdf.tlh"
    using namespace AcroPDFLib;

    après avoir copié acropdf.tlh et acropdf.tli dans le répertoire principal
    (et enlevé debug dans acropdf.tlh au chemin de l'include "acropdf.tli" puisque je l'ai copié dans le répertoire principal)

    On peut alors charger un fichier par :

    IUnknown* pUnknown = NULL;
    HRESULT hr = E_FAIL;
    IAcroAXDocShim* pAcroAXDocShim;
    if (pAAGC)
    {
    	hr = pAAGC(hWndActiveX, (IUnknown**)&pUnknown);
    	if (SUCCEEDED(hr))
    	{
    		hr = pUnknown->QueryInterface(IID_IAcroAXDocShim, (LPVOID *)&pAcroAXDocShim);
    		if (SUCCEEDED(hr))
    		{
    			BSTR bstrName = SysAllocString(L"E:\\Sources\\PDFReader\\cshTutorial.pdf");
    			hr = pAcroAXDocShim->LoadFile(bstrName);
    			pAcroAXDocShim->Release();
    		}
    		pUnknown->Release();
    	}
    }

    Exemple minimal =>

    #include <windows.h>
    #include <tchar.h>
    
    HINSTANCE hInst;
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    typedef BOOL(__stdcall *PAAWI)(void);
    PAAWI pAtlAxWinInit = NULL;
    typedef HRESULT(__stdcall *PAAGC) (HWND hWnd, IUnknown** pUnknown);
    PAAGC pAAGC = NULL;
    
    int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
    {
    	HINSTANCE hDLL = LoadLibrary(TEXT("atl.dll"));
    	pAtlAxWinInit = (PAAWI)GetProcAddress(hDLL, "AtlAxWinInit");
    	if (pAtlAxWinInit)
    		pAtlAxWinInit();
    	pAAGC = (PAAGC)GetProcAddress(hDLL, "AtlAxGetControl");
    
    	hInst = hInstance;
    	WNDCLASSEX wcex =
    	{
    		sizeof(WNDCLASSEX), 0, WndProc, 0, 0, hInst, LoadIcon(NULL, IDI_APPLICATION),
    		LoadCursor(NULL, IDC_ARROW), (HBRUSH)(COLOR_WINDOW + 1), NULL, TEXT("PDFReader"), NULL,
    	};
    	if (!RegisterClassEx(&wcex))
    		return MessageBox(NULL, TEXT("Cannot register class !"), TEXT("Error"), MB_ICONERROR | MB_OK);
    
    	int nX = (GetSystemMetrics(SM_CXSCREEN) - 860) / 2, nY = (GetSystemMetrics(SM_CYSCREEN) - 600) / 2;
    	HWND hWnd = CreateWindowEx(0, wcex.lpszClassName, TEXT("PDF Reader"), WS_OVERLAPPEDWINDOW, nX, nY, 860, 600, NULL, NULL, hInst, NULL);
    	if (!hWnd)
    		return MessageBox(NULL, TEXT("Cannot create window !"), TEXT("Error"), MB_ICONERROR | MB_OK);
    	
    	Sleep(100);
    	ShowWindow(hWnd, SW_SHOWNORMAL);
    	UpdateWindow(hWnd);
    
    	MSG msg;
    	while (GetMessage(&msg, NULL, 0, 0))
    	{
    		TranslateMessage(&msg);
    		DispatchMessage(&msg);
    	}
    	return (int)msg.wParam;
    }
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	static HWND hWndActiveX;
        switch (message)
        {
    	case WM_CREATE:
    	{
    		hWndActiveX = CreateWindow(TEXT("AtlAxWin"), TEXT("C:\\test.pdf"),
    		WS_CHILD | WS_VISIBLE | WS_BORDER, 0, 0, 0, 0, hWnd, 0, hInst, 0);				
    		return 0;
    	}
    	break;
    	case WM_SIZE:
    	{
    		MoveWindow(hWndActiveX, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
    		return 0;
    	}
    	break; 
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        return 0;
    }
    





    • Marqué comme réponse cheickna1966 mercredi 23 août 2017 20:56
    mardi 15 août 2017 12:02

Toutes les réponses

  • Il y a diverses méthodes.

    Une des plus simples est la classe de fenêtre "AtlAxWin" (après avoir appelé la fonction "AtlAxWinInit" pour l'initialiser)

    (on crée juste la fenêtre avec le nom du fichier PDF en paramètre lpWindowName de CreateWindow()

    et il s'affiche)

    vendredi 11 août 2017 04:23
  • Bonjour Cher Castorix31

    Je vous avoue que l'utilisation de la bibliothèque standard comme vous préconisez n'est pas des plus simples. Je ne trouve aucun exemple sur le net qui me convient et si j'en trouve ils datent de 2006 et l'ajout de ces codes exemples conduisent à beaucoup d'erreurs à cause des incompatibilités entre les fonctions qui ont évolué...Bref! 

    En plus dans ma solution l'affichage du PDF dans une nouvelle fenêtre ne convient pas. Ce que je souhaite c'est que lorsqu'un utilisateur sélectionne un fichier PDF dans une List Control qui est sur ma fenêtre principale que je puisse lui proposer un apercu de ce fichier PDF afin d'éviter qu'il double-click dessus pour l'ouvrir. La liste peut contenir des dizaines de fichiers, donc les ouvrir un à un est juste pas user friendly. L'idéal aurait été que je puisse afficher dans un picture Box mais malheureusement cela ne semble pas possible car je n'ai trouvé aucun exemple non plus.

    Ma contrainte est que mon appli doit être livré en standalone sans aucune Dll spécifique qui l'accompagne donc ce qui m'empêche d'utiliser des contrôles tiers.

    J'ai pensé au contrôle ActiveX Microsoft Browser Web que je pourrai inclure sur ma Dialog mais il me semble que je serai obligé de livrer aussi le fichier OCX qui va bien, donc...

    Si vous avez d'autres propositions à me faire je les prendrai vraiment avec plaisir.

    Merci d'avance

    mardi 15 août 2017 09:22
  • "AtlAxWin" n'ouvre pas de nouvelle fenêtre, c'est un contrôle similaire à une Picture Box (c'est juste un container)

    Et il ne nécessite aucune lib supplémentaire.

    Je l'utilise en C ou C++/Win32

    Je pourrais poster un exemple basique si vous n'y arrivez pas.

    mardi 15 août 2017 09:36
  • Bonjour et merci pour votre réactivité.

    Je vous serai mille fois reconnaissant si vous pouvez poster cet exemple basique qui me servira de point de depart pour l'adapter à mon cas. Car sincèrement, je n'y arrive pas.

    Merci d'avance

    mardi 15 août 2017 10:58
  • Exemple minimal en C++/Win32 affichant le PDF directement à partir du fichier.

    Si l'on veut afficher le contrôle vide puis charger un fichier par les interfaces Acrobat, on le crée par exemple avec

    TEXT("AcroPDF.PDF.1") au lieu du nom du fichier.

    Ensuite, on génère puis ajoute les interfaces en les important.

    Par ex sur mon poste c'est :

    #import "C:\Program Files (x86)\Common Files\Adobe\Acrobat\ActiveX\AcroPDf.dll" named_guids

    puis je commente cette ligne et ajoute

    #include "acropdf.tlh"
    using namespace AcroPDFLib;

    après avoir copié acropdf.tlh et acropdf.tli dans le répertoire principal
    (et enlevé debug dans acropdf.tlh au chemin de l'include "acropdf.tli" puisque je l'ai copié dans le répertoire principal)

    On peut alors charger un fichier par :

    IUnknown* pUnknown = NULL;
    HRESULT hr = E_FAIL;
    IAcroAXDocShim* pAcroAXDocShim;
    if (pAAGC)
    {
    	hr = pAAGC(hWndActiveX, (IUnknown**)&pUnknown);
    	if (SUCCEEDED(hr))
    	{
    		hr = pUnknown->QueryInterface(IID_IAcroAXDocShim, (LPVOID *)&pAcroAXDocShim);
    		if (SUCCEEDED(hr))
    		{
    			BSTR bstrName = SysAllocString(L"E:\\Sources\\PDFReader\\cshTutorial.pdf");
    			hr = pAcroAXDocShim->LoadFile(bstrName);
    			pAcroAXDocShim->Release();
    		}
    		pUnknown->Release();
    	}
    }

    Exemple minimal =>

    #include <windows.h>
    #include <tchar.h>
    
    HINSTANCE hInst;
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    typedef BOOL(__stdcall *PAAWI)(void);
    PAAWI pAtlAxWinInit = NULL;
    typedef HRESULT(__stdcall *PAAGC) (HWND hWnd, IUnknown** pUnknown);
    PAAGC pAAGC = NULL;
    
    int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
    {
    	HINSTANCE hDLL = LoadLibrary(TEXT("atl.dll"));
    	pAtlAxWinInit = (PAAWI)GetProcAddress(hDLL, "AtlAxWinInit");
    	if (pAtlAxWinInit)
    		pAtlAxWinInit();
    	pAAGC = (PAAGC)GetProcAddress(hDLL, "AtlAxGetControl");
    
    	hInst = hInstance;
    	WNDCLASSEX wcex =
    	{
    		sizeof(WNDCLASSEX), 0, WndProc, 0, 0, hInst, LoadIcon(NULL, IDI_APPLICATION),
    		LoadCursor(NULL, IDC_ARROW), (HBRUSH)(COLOR_WINDOW + 1), NULL, TEXT("PDFReader"), NULL,
    	};
    	if (!RegisterClassEx(&wcex))
    		return MessageBox(NULL, TEXT("Cannot register class !"), TEXT("Error"), MB_ICONERROR | MB_OK);
    
    	int nX = (GetSystemMetrics(SM_CXSCREEN) - 860) / 2, nY = (GetSystemMetrics(SM_CYSCREEN) - 600) / 2;
    	HWND hWnd = CreateWindowEx(0, wcex.lpszClassName, TEXT("PDF Reader"), WS_OVERLAPPEDWINDOW, nX, nY, 860, 600, NULL, NULL, hInst, NULL);
    	if (!hWnd)
    		return MessageBox(NULL, TEXT("Cannot create window !"), TEXT("Error"), MB_ICONERROR | MB_OK);
    	
    	Sleep(100);
    	ShowWindow(hWnd, SW_SHOWNORMAL);
    	UpdateWindow(hWnd);
    
    	MSG msg;
    	while (GetMessage(&msg, NULL, 0, 0))
    	{
    		TranslateMessage(&msg);
    		DispatchMessage(&msg);
    	}
    	return (int)msg.wParam;
    }
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	static HWND hWndActiveX;
        switch (message)
        {
    	case WM_CREATE:
    	{
    		hWndActiveX = CreateWindow(TEXT("AtlAxWin"), TEXT("C:\\test.pdf"),
    		WS_CHILD | WS_VISIBLE | WS_BORDER, 0, 0, 0, 0, hWnd, 0, hInst, 0);				
    		return 0;
    	}
    	break;
    	case WM_SIZE:
    	{
    		MoveWindow(hWndActiveX, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
    		return 0;
    	}
    	break; 
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        return 0;
    }
    





    • Marqué comme réponse cheickna1966 mercredi 23 août 2017 20:56
    mardi 15 août 2017 12:02
  • Bonjour,

    Merci infiniment pour ce post qui répond au delà de mes attentes. vraiment merci.

    mardi 15 août 2017 13:29
  • Bonjour Castorix31,

    La première option de votre proposition est celle qui correspond à mon appli. J'ai donc procédé comme suit dans mon projet Visual C++ 2017 en essayant d'adapter votre code. Je n'ai pas d'erreur de compil ni d'exécution mais ma zone d'affichage n'est pas créée sur l'écran principal. Peut-être avec le code, vous pourrez voir ce qui ne fonctionne pas. 

    J'ai d'abord dans mon fichier d'entête les éléments suivants après avoir copié les fichiers acropdf.tlh et acropdf.tli dans le répertoire principal de mon projet et après avoir enlever le sous repertoire "Debug" du fichier acropdf.tlh

    // ArchiveDocDlg.h : header file // #include <windows.h> #include <tchar.h> //#import "C:\Program Files (x86)\Common Files\Adobe\Acrobat\ActiveX\AcroPDf.dll" named_guids #include "acropdf.tlh" using namespace AcroPDFLib; // CArchiveDocDlg dialog class CArchiveDocDlg : public CDialogEx { // (.....) public: // Gestion dynamique de l'affichage des fichiers PDF HINSTANCE hInst; typedef BOOL(__stdcall *PAAWI)(void); PAAWI pAtlAxWinInit = NULL; typedef HRESULT(__stdcall *PAAGC) (HWND hWnd, IUnknown** pUnknown); PAAGC pAAGC = NULL;
    HWND hWndActiveX; // Ici j'ai dû enlever Static sinon problème de compiltaion

    int DisplayDocument(HWND hWndAX, LPSTR FileName); // Permet d'affichier le fichier PDF dont la fenêtre dont l'isntance est passée en paramètre }

    Ensuite j'ai initialisé la création de mon écran d'affichage dans la méthode OnInitDialog de ma fenêtre principale comme suit :

    // CArchiveDocDlg message handlers
    
    BOOL CArchiveDocDlg::OnInitDialog()
    {
    	CDialogEx::OnInitDialog();
    	SetIcon(m_hIcon, TRUE);			// Set big icon
    	SetIcon(m_hIcon, FALSE);		// Set small icon
    
        //Création de l'affichage du PDF
    	HINSTANCE hDLL = LoadLibrary(TEXT("atl.dll"));
    	if (hDLL == NULL)
    	{
    		AfxMessageBox("Chargement DLL KO"); // Ici tout est OK
    	}
    	pAtlAxWinInit = (PAAWI)GetProcAddress(hDLL, "AtlAxWinInit");
    	if (pAtlAxWinInit)
    		pAtlAxWinInit();
    	else
    	{
    		AfxMessageBox("KO - pAtlAxWinInit");  //Ici tout est OK
    	}
    	pAAGC = (PAAGC)GetProcAddress(hDLL, "AtlAxGetControl");
    
    	hWndActiveX = CreateWindow(TEXT("AtlAxWin"), TEXT("AcroPDF.PDF.1"),WS_CHILD | WS_VISIBLE | WS_BORDER, 342, 91, 390, 265, NULL, 0, NULL, 0);
    	if (hWndActiveX == NULL)
    	{
    		AfxMessageBox("KO");
    	}
    	
    	return TRUE;
    }

    Je pense que le problème vient de la dernière instruction car (hWndActiveX == NULL) et je pense que cela pourrait être dû au fait que j'ai mis le paramètre Hinstance de CreateWindow () à NULL car je n'ai pas pu récupérer l'instance de la fenêtre principale (m_hwnd n'est pas reconnu).

    Enfin pour afficher le PDF j'ai créé la fonction suivante que je peux appeler dans un bouton de commande:

    // Permet d'affichier le fichier PDF dont la fenêtre dont l'instance est passée en paramètre
    int CArchiveDocDlg::DisplayDocument(HWND hWndAX, LPSTR FileName)
    {
    	IUnknown* pUnknown = NULL;
    	HRESULT hr = E_FAIL;
    	IAcroAXDocShim* pAcroAXDocShim;
    	if (pAAGC)
    	{
    		hr = pAAGC(hWndAX, (IUnknown**)&pUnknown);
    		if (SUCCEEDED(hr))
    		{
    			hr = pUnknown->QueryInterface(IID_IAcroAXDocShim, (LPVOID *)&pAcroAXDocShim);
    			if (SUCCEEDED(hr))
    			{
    				//BSTR bstrName = SysAllocString((OLECHAR*)FileName);
    				BSTR bstrName = SysAllocString(L"C:\\CHEICKNA.pdf");
    				hr = pAcroAXDocShim->LoadFile(bstrName);
    				pAcroAXDocShim->Release();				
    			}
    			pUnknown->Release();
    		}
    	}
    	return 0;
    }

    il suffit que je passe en paramètre la variable hWndActiveX  et le nom chemin complet du PDF
    Cela ne marche donc pas certainement à cause de la création en échec du placeholder d'affichage.

    Voyez-vous où j'ai pu me louper ?

    Merci d'avance pour vos conseils avisés


    • Modifié cheickna1966 mardi 15 août 2017 19:42 Correction
    mardi 15 août 2017 19:35
  • Je pense que le problème vient de la dernière instruction car (hWndActiveX == NULL) et je pense que cela pourrait être dû au fait que j'ai mis le paramètre Hinstance de CreateWindow () à NULL car je n'ai pas pu récupérer l'instance de la fenêtre principale (m_hwnd n'est pas reconnu).

    Il faut absolument mettre un hWnd, car c'est le handle de la fenêtre parente du contrôle.

    Apparemment le handle de la Dialog Box dans ce cas.

    Je n'utilise pas les MFC, mais Google donne "The dialog's handle is the m_hWnd member variable of CDialog"...

    mardi 15 août 2017 20:08
  • Ok je vais regarder cela.

    Merci Castorix31

    mardi 15 août 2017 20:20
  • MFC + Controle d'Acrobat + MSVC lui-même.

    Chacun de ces trois éléments demandes des Dll installées qui ne le sont pas obligatoirement dans un OS Windows.

    C'est juste pour la remarque "Ma contrainte est que mon appli doit être livré en standalone sans aucune Dll spécifique". :-)

    Mais on s'en fout de ces contraintes à la noix.

    On crée un MSI d'installation comme pour toute solution logicielle digne de ce nom.


    Paul Bacelar, Ex - MVP VC++

    mercredi 16 août 2017 09:56
    Modérateur
  • Bonjour cher Paul,

    Content de voir que vous êtes toujours sur le forum. Il me semble que j'échangeais déjà beaucoup avec vous il ya plusieurs années quand j'étais développeur mais le temps est passé depuis... :-)

    En fait le contexte du développement spécial que je suis entrain de faire c'est effectivement d'avoir un seul exécutable unique car cette application sera installé (je devrais dire copié ) sur des support comme une clé USB ou des cartes mémoires SD afin que quelqu'un puisse avoir ce support sur lui n'importe où il sera et qu'on puisse au besoin le plugger sur n'importe quel machine Windows (> Xp au moins)  et exécuter l'application pour accéder à certains documents stockés sur le même support.

    c'est donc pour cela que j'ai choisi l'option de compilation "Static"  même si cela donne une exe plus volumineux mais qui me donne l'assurance que je n'aurai pas de problème de dll manquant que nous avions en longueur de journée avec VB.

    En revanche mon besoin a évolué car j'ai eu besoin d'un affichage PDF que je n'avais pas prévu d'où l'utilisation du contrôle Acrobat. Et encore je pensais qu'en mettant les fichiers AcroPDF.tlh et acropdf.tli directement dans mon projet, je n'avais plus à embarquer les dll physiques Acrobat avec moi. Je comprends dans votre message que ce n'est pas le cas. Est-ce bien cela ???

    Merci pour votre retour

    mercredi 16 août 2017 13:04
  • >Est-ce bien cela ???

    Et, Oui.

    Ok, ça complexifie pas mal la situation, l'histoire de la clé USB. ;-)

    Mais il y a quand même des Dll qui se baladent comme la atl.dll chargée via un LoadLibrary, en loosedé.

    Donc le truc, c'est pas qu'il n'y ait pas de Dll mais que le programme soit opérationnel depuis une clé USB.

    Bon, la solution de fainéant est toujours la meilleur : sauf erreur de ma part, Win10 (voir Win8) est directement hostable dans dès clé USB " : Windows To Go https://technet.microsoft.com/fr-fr/library/hh831833%28v=ws.11%29.aspx?f=255&MSPPError=-2147217396

    Donc, votre "globe-trotter" il se balade avec ça clé USB Windows To Go et il n'a plus qu'à chopper une machine qui boot sur un port USB.

    Une solution plus "développeur", c'est une exécution d'un programme depuis une clé USB (mais on fait un grand sourire à l'administrateur système du domaine, parce qu'il a été gentil de laisser d'aussi gros "trous" de sécurité, juste pour nos beaux yeux).

    Pour les histoires de Dll, il existe le mécanisme de manifeste dans un programme qui indique où aller chercher les Dll, y compris dans une clé USB. Il est donc totalement inutile d'essayer de fourrer l'exécutable comme une dinde de Noël avec des librairies statiques.

    Donc, ne vous emmerdez pas avec les librairies en statiques, mettez toutes les Dll nécessaires dans la clé USB et configurez le manifeste de l'application pour que le loader du système aille les chercher sur la clé.

    Mais cela ne règle pas les problèmes des composants Acrobat.

    Alors, j'ai pas trop compris vos bricolages à base de "#import + mise en commentaire + #include".

    A part vous compliquez la vie et perdre d'éventuelles améliorations liées aux mises à jours d'Acrobat, j'ai l'impression que ce bricolage ne sert à rien.

    Laissez le #import, qui fait tout le sale boulot pour vous.

    Ces composants utilisent les mécanismes COM, il faut donc que ces composants soit correctement et complètement installés dans le système hôte (salopage de la base de registre comprise).

    Vous pouvez faire l'assertion que ces composants soient déjà installés dans le système (on n'est pas sur MAC ;-) ). Vous n'aurez qu'à gérer l'erreur de création du composant en cas de non installation et demander à l'utilisateur de l'installer manuellement avant de continuer. (Voir coller un MSI d'installation d'Acrobat dans la clé USB et lancer l'installation depuis le programme).

    Soit utiliser une API qui n'utilise pas COM, en utilisant peut-être des visualiseurs de PDF "spéciale Portable APP".


    Paul Bacelar, Ex - MVP VC++

    mercredi 16 août 2017 14:48
    Modérateur
  • En revanche mon besoin a évolué car j'ai eu besoin d'un affichage PDF que je n'avais pas prévu d'où l'utilisation du contrôle Acrobat. Et encore je pensais qu'en mettant les fichiers AcroPDF.tlh et acropdf.tli directement dans mon projet, je n'avais plus à embarquer les dll physiques Acrobat avec moi. Je comprends dans votre message que ce n'est pas le cas. Est-ce bien cela ???
                Si on utilise le ProgId "AcroPDF.PDF.1", il faut qu'il ait été enregistré par AcroPDf.dll (ce qui est en principe le cas sur les derniers OS)
                Sinon Adobe Reader le fait  (j'ai aussi testé par regsvr32 en Admin mais ça me ramenait une erreur)
                
                Sinon on peut aussi l'afficher par IE (IWebBrowser2 interface) (je n'ai pas vérifié s'il utilise Adobe Reader en interne.)
                
              
    hWndActiveX = CreateWindow(TEXT("AtlAxWin"), TEXT("about:blank"), WS_CHILD | WS_VISIBLE | WS_BORDER, 342, 91, 390, 265, hWnd, 0, hInst, 0);
    Pour charger un fichier PDF :
               
    {
                HRESULT hr = E_FAIL;
                IUnknown* pUnknown = NULL;
                IWebBrowser2 *pWebBrowser = NULL;
                hr = pAAGC(hWndActiveX, &pUnknown);
                if (SUCCEEDED(hr))
                {
                    hr = pUnknown->QueryInterface(__uuidof(IWebBrowser2), (void**)&pWebBrowser);
                    if (SUCCEEDED(hr))
                    {
                        WCHAR wsLink[255] = "c:\\test.pdf";                    
                        BSTR bstrURL = SysAllocString(wsLink);
                        hr = pWebBrowser->Navigate(bstrURL, NULL, NULL, NULL, NULL);
                        SysFreeString(bstrURL);
                        pWebBrowser->Release();
                    }
                    pUnknown->Release();
                }
    }



    • Modifié Castorix31 mercredi 16 août 2017 15:20
    mercredi 16 août 2017 15:16
  • >Si on utilise le ProgId "AcroPDF.PDF.1"

    C'est un machin qui est dans la base de registre SI un composant Acrobat est installé. Pas installé, pas de chocolat.

    Connaissant Adobe et M$, je serais bien étonné que ces composants soient installés de base dans une distribution "Core" de Windows. ;-)

    >ce qui est en principe

    Le "principe", ça serait pas le constructeur du PC qui l'installerait pour afficher sa documentation sans avoir à fournir une version papier à basse d'arbres d'Amazonie ? ;-)

    >Sinon Adobe Reader le fait  (j'ai aussi testé par regsvr32 en Admin

    L'installateur d'Acrobat le fait automatiquement, et en "vrai" administrateur.

    > (je n'ai pas vérifié s'il utilise Adobe Reader en interne.)

    Vous, ça fait longtemps que vous n'utilisez plus vraiment IE, qui vous fait chier plusieurs fois par mois pour que le "plug-ins" d'Adobe se mette à jour.

    Via IE, c'est la même cochonnerie COM.

    Mais il y a peut-être des composants Web pour IE qui émule la lecture de PDF, mais Adobe est assez casse-bonbon avec son copyright sur son format.


    Paul Bacelar, Ex - MVP VC++

    mercredi 16 août 2017 15:59
    Modérateur
  • Bonsoir,
    Discussion très intéressante dont je résume ci-après les grandes lignes.

    Clé USB:
    Effectivement, Paul, je comprends qu'elle représente un véritable "trou de sécurité". Cette clé est plutôt destinée à
    des particuliers et une utilisations plutôt sur des machines non professionnelles. Par exemple quelqu'un a sur sa clé ses dossiers médicaux qu'il ne veux pas mettre
    sur le cloud. Même en dehors de chez lui il peut y avoir accès sur un autre ordinateur, l'imprimer, l'envoyer par e-mail via justement cette application sur cette clé.

    Question cruciale de DLL :
    Si je ne peux éviter les dll, la solution consistera donc à utiliser ce le mécanisme de manifeste dans un programme qui indique où aller chercher les Dll sur la clé.
    Il faudrait que je cherche sur MSDN comment utiliser ce mécanisme.
    "Soit utiliser une API qui n'utilise pas COM, en utilisant peut-être des visualiseurs de PDF "spéciale Portable APP".
    Ce serait la solution idéale et c'est parce que je n'ai rien trouvé de tel que j'ai posté une question sur l'affichage des PDF
    Paul si vous connaissez une telle API je suis preneur.
    Solution IE
    Une autre alternative proposée par Castorix31 (IWebBrowser2 interface) qui doit fonctionner aussi mais Paul rappelle les problèmes liés à IE notamment les mises à jour régulière des plug-ins Adobe.
    J'avais pensé aussi au contrôle ActiveX Microsoft Web Browser Control mais je m'étais dit que je devais alors livré un .OCX
    Paul évoque aussi un émulateur de lecture PDF mais avec des problèmes de copyright liés.

    Conclusion:

    Donc au final avec toutes ces idées, j'en reviens à me poser la question : "Qu'est ce que j'ai comme choix de solution ?"
    Pour moi au final je peux installer les dll sur la clé USB cela pourrait me convenir

    MAIS :
    Est-ce que mon problème n'est pas finalement le format PDF?
    ET si je stockais mes documents au format PNG ou JPEG et les afficher dans une PictureBox standard, n'est ce pas moins contraignant ?
    mercredi 16 août 2017 19:58
  • Solution IE
    Une autre alternative proposée par Castorix31 (IWebBrowser2 interface) qui doit fonctionner aussi mais Paul rappelle les problèmes liés à IE notamment les mises à jour régulière des plug-ins Adobe.
    J'avais pensé aussi au contrôle ActiveX Microsoft Web Browser Control mais je m'étais dit que je devais alors livré un .OCX

    Web Browser Control  = IWebBrowser2 (voir Reusing the WebBrowser Control)


    mercredi 16 août 2017 20:27
  • Problème d'affichage résolu. Il provenait du fait que le Handle de la fenêtre parent et l'instance du contrôle n'étaient pas précisés.

    J'ai d'abord défini dans le fichier d'entête une variable comme suit :

    HWND m_hwndDlg = NULL;

    Puis dans la fonction Oncreate j'ai stocké le handle de la Dialog principale dans cette variable :

    int CArchiveDocDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    	if (CDialogEx::OnCreate(lpCreateStruct) == -1)
    		return -1;
            // m_hwnd est disponible dès la création de la fenêtre
    	m_hwndDlg = m_hWnd;
    
    return 0;
    }

    et enfin j'ai modifié l'instruction CreateWindow comme suit :

    hWndActiveX = CreateWindowEx(WS_EX_LEFT, TEXT("AtlAxWin"), TEXT("AcroPDF.PDF.1"), WS_CHILD | WS_VISIBLE | WS_BORDER, 342, 91, 390, 265, m_hwndDlg, NULL, (HINSTANCE)GetWindowLong(m_hwndDlg, GWL_HINSTANCE), NULL);

    Le container est crée et le PDF est affiché à l'aide de l'appel de la fonction DisplayDocument(...)

    Maintenant réflexion en cours sur la pérennité du composant Acrobat après les échanges avec Paul et Castorix31


    • Modifié cheickna1966 mercredi 16 août 2017 21:51 correction
    mercredi 16 août 2017 21:25
  • Je sais qu'un utilisateur n'est pas rationnel mais qu'il ne veille pas mettre les informations sur le Cloud mais les mettre dans le port USB d'une machine d'un cybercafé, c'est quand même très étrange, non ?

    La solution "Windows To Go", c'est vraiment pour les professionnels, comme les médecins dans ce cas de figure de dossier médical. C'est vraiment confortable pour l'utilisateur qui n'a qu'une clé USB dans la poche et ne doit trouver qu'un hardware compatible x86/x64, même sans OS. A moins de sondes matérielles, c'est safe d'un point de vue sécurité.

    On peut toujours coller une version Linux-Live sur une clé USB si les outils proposés sont aussi disponibles sur l'OS au pingouin.

    Après lecture de Wikipédia, PDF est une norme ISO depuis 2008 (je croyais que c'était encore un format propriétaire :-° ), il est donc normalement possible d'avoir des implémentations complètes des outils ailleurs que chez Adobe qui ne propose, semble-t-il que des outils à installer. Il faut faire des recherches dans la jungle de ces outils.

    Mais une approche qui peut simplifier le machin, c'est de générer des fichiers vignettes/thumbtail dans un coin ( http://download.cnet.com/PDF-Thumbnail-Generator/3000-18497_4-10419619.html ) et d'utiliser les lecteurs type Foxit Reader ou Sumatra PDF sur la clé quand il faudra les afficher en full-sceen.

    Mais tous les outils casables dans une clé demandent des pré-requis plus ou moins lourd dans l'OS, qu'il faut vérifier, et peut-être qu'avoir Acrobat Reader d'installer n'est pas un pré-requis de la mort.

    Cela me fait penser à la fin d'Independence Day où ils contaminent le vaisseau mère avec un virus sur une clé USB, c'est de la Sci-Fi. ;-)


    Paul Bacelar, Ex - MVP VC++

    jeudi 17 août 2017 13:49
    Modérateur
  • Bonsoir Paul,

    Ok je conçois que le cloud est plus sécurisé qu'une clé USB mais seuls des professionnels comme nous savons cela bien que nous ayons aussi d'autres doutes sur l'utilisation des clouds qui sont situés à des endroits que nous ne connaissons même pas, ni l'honnêteté des administrateurs de ces systèmes. Mais ça c'est un autre débat. 

    Revenons à ce qui nous intéresse ici. Je n'ai pas choisi la solution Windows To Go pour 2 raisons :
    1. Pour utiliser sa clé USB sur un ordinateur encore faudra t-il avoir les compétences de dire à l'ordinateur de booter sur ta clé. Ce n'est pas une plaisanterie : si vous prenez 10 personnes non informaticiens, vous ne trouverez au mieux que 2 personnes qui saura le faire.

    2. Pire, L'utilisation de Windows To Go nécessite l'installation de certains composants sur la machine hôte. Va accepter que quelqu'un vient sur votre PC et installer quelques fichiers pour que sa clé USB soit reconnue. On va l'accepter pour une personne qu'on connaît mais jamais pour un inconnu. Microsoft même écrit noir sur blanc ceci : "Les lecteurs Windows To Go peuvent être démarrés sur plusieurs ordinateurs. Lors de son premier démarrage sur un ordinateur hôte, un espace de travail Windows To Go détectera tous les composants matériels de l’ordinateur et installera les pilotes nécessaires."

    Maintenant voyons concrètement ce que je veux faire : Sur ma fameuse clé "autonome" j'ai une structure de dossier avec des catégories, sous categories, etc. Je peux me contenter de visualiser cette arborescence dans l'explorateur Windows ou sous un mac et de choisir le document que je veux imprimer, envoyer, visualiser. C'est ce que je fais d'ailleurs actuellement.
    Au lieu de cela j'ai décidé de créer une interface utilisateur qui me permet de filtrer par catégorie, par année, par type de document, par sous type pour finir par choisir un document voulu. Donc une utilisation conviviale de mes documents. Je me suis donc dit qu'un simple exécutable que je placerai sur cette clé à la racine de cette arborescence et qui m'evite des installations de dll sera la solution idéale. Ainsi sur n'importe quel PC par exemple à partir de winxp ou win7 je pourrai utiliser la clé juste pour consulter mes documents et ne rien installer sur le PC hôte. Je compte bien sûr sur les propriétaires de PC hôtes d'avoir au moins un antivirus sur leurs PCs, sinon il ya aussi un risque pour ma clé également.
    Finalement c'est ce que je suis arrivé à faire car au lieu d'utiliser des langages plus simples comme VB j'ai utilisé VC++ qui me permettait d'avoir un exe compilé en static comme j'ai évoqué. MAIS MAIS MAIS je me suis rendu compte à l'utilisation que c'est contraignant d'ouvrir les documents un a un pour trouver le bon car a la numérisation de 150 documents je n'ai que des noms génériques avec un numéro séquentiel. Ne me demandez pas de donner un nom bien évocateur à des centaines de documents !!!! hi hi !!!. Je me suis alors dit que je vais créer une zone de prévisualisation (genre PictureBox) de mes documents PDF sur mon interface conviviale, ce qui me permet de parcourir sans les ouvrir à l'extérieur de l'interface. Tout le problème a commencé là : un visualiseur PDF risque de m'obliger à embarquer sur ma clé des dll adobe ou un ocx, etc. et surtout je risquais de ma lancer dans la création d'un MSI d'installation que je voulais vraiment éviter. J'ai pensé au PictureBox mais il ne peut afficher les PDF, j'ai pensé au browser Web de Microsoft mais je risque d'embarquer aussi des composants des manifestes, etc. 
    La solution Vignettes que vous préconisez ne convient pas car cela m'oblige à visualiser les documents à l'extérieur de mon interface. Contre mauvaise fortune, bon cœur je suis parvenu malgré tout à prévisualiser en utilisant la méthode Acrobat préconisée par Castorix31 (méthode que vous n'avez pas appréciez car avec #import à commenter et tlh et tli à ajouter au projet ). Cela fonctionne mais je ne suis pas sûr que ma clé soit encore autonome.... 
    j'ai été un peu long mais je pense que l'explication du contexte était nécessaire. Vos remarques sont toujours les bienvenus car je suis convaincu qu'une solution est au bout mais je ne sais où se trouve ce bout :_) !!!!


    • Modifié cheickna1966 jeudi 17 août 2017 20:53 correction
    jeudi 17 août 2017 20:51
  • Pour ce qui est de Windows To Go, Ok pour la première remarque.

    Mais la seconde est absolument fausse, il n'y à AUCUNE trace de l'exécution de Windows To Go sur les disques internes de la machine, AUCUNE. L'installation des pilotes, c'est dans le Windows "Live" qui est sur la clé.

    >Je me suis donc dit qu'un simple exécutable que je placerai sur cette clé

    Moi, comme on n'est plus dans une logique de spécialisation de l'affichage de l'explorateur, j'aurai plus regarder du coté des HTA ou des "Shell Extension" pour faire le taf. Mais c'est vieux, donc faut voir avec leurs successeurs.

    https://msdn.microsoft.com/en-us/library/ms536496%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396

    https://github.com/dwmkerr/sharpshell

    https://stackoverflow.com/questions/10619990/hta-equivalents-in-firefox-chrome-is-this-old-technology


    >et qui m'evite des installations de dll

    Les Dll, c'est vraiment pas le plus compliqué, surtout avec le mécanisme de manifeste. Un OCX qui doit être installé dans le système hôte, c'est bien plus chaud.

    > juste pour consulter mes documents et ne rien installer sur le PC hôte

    La solution actuelle fonctionne déjà, elle manque juste de convivialité. Ne serait-ce pas une exigence superfétatoire ? La solution ne doit pas ajouter des contraintes mais la solution actuelle en a déjà, et ça passe, non ?

    >sinon il ya aussi un risque pour ma clé également.

    Normalement, vous devrez la monté en lecture seule et cela devrait toujours fonctionner, non ?

    >utilisé VC++ qui me permettait d'avoir un exe compilé en static comme j'ai évoqué

    Si j'ai bien compris votre problème, je trouve que c'est un mauvais outil par rapport à votre problème.

    >PDF risque de m'obliger à embarquer sur ma clé des dll adobe ou un ocx, etc

    Et les installer sur le système hôte !!!

    >d'un MSI d'installation que je voulais vraiment éviter.

    OK, mais si vous êtes dans un environnement d'entreprise, le MSI peut être installé sur tout les machines du domaine "en cachette" par les administrateurs du domaine.

    > car cela m'oblige à visualiser les documents à l'extérieur de mon interface.

    Pas forcement, il est courant que des applicatifs est des paramètres de "hosting" dans d'autres applications, comme sous Office.

    Je ne critique pas la solution de Castorix31. Juste que le bidouillage de la mise en commentaire de #import et l'ajout des #include ne change absolument rien en terme de dépendance de l'exécutable généré. Donc pas la peine de se prendre la tête avec ce truc.

    >Cela fonctionne mais je ne suis pas sûr que ma clé soit encore autonome....

    Mais est-ce que l'autonomie est un "vrai" problème ? La solution actuelle fonctionne sur toutes les machines cibles, non ?


    Paul Bacelar, Ex - MVP VC++

    vendredi 18 août 2017 14:45
    Modérateur

  • Je ne critique pas la solution de Castorix31. Juste que le bidouillage de la mise en commentaire de #import et l'ajout des #include ne change absolument rien en terme de dépendance de l'exécutable généré.

    Non mais je fais juste ça par habitude pour pouvoir mettre directement #include "nom_du_fichier" et lancer #import une seule fois, vu que les .tlh et .tli sont générés dans \debug (ou \release)



    • Modifié Castorix31 vendredi 18 août 2017 15:07
    vendredi 18 août 2017 15:01
  • Bonsoir Paul,

    Encore merci pour vos dernières remarques mais comme disait Victor Hugo "De la discussion jaillit la lumière", je vais aussi répondre à quelques points.
    Concernant le point sur l'installation de windows To Go j'avais en fait mal interprété ce texte de Microsoft :
    "Lors de son premier démarrage sur un ordinateur hôte, un espace de travail Windows To Go détectera tous les composants matériels de l’ordinateur et installera les pilotes nécessaires. Pour des démarrages suivants sur cet ordinateur hôte, l’espace de travail Windows To Go sera en mesure d’identifier l’ordinateur hôte et de charger automatiquement le jeu de pilotes approprié.". Je pensais que l'expression "installera les pilotes nécessaires" signifiait que ces pilotes étaient installés sur l'ordinateur hôte. Qu'à cela ne tienne, je reste néanmoins accroché à la solution sans windows to go car l'application est vraiment destiné à des néophytes en informatique, c'est à dire à des utilisateurs lambda.
    Application HTA:
    Oui j'y avais pensé mais j'ai vite déchanté car j'avais eu de mauvaise surprise dans le passé avec les rendus complètement différents d'une application selon qu'on utilise IE, Firefox, Opera, Chrome, etc. J'avais ensuite commencé à développer avec ASP.NET mais lorsque j'ai vu tous les assembly et autres dll dans le repertoire de travail même du projet j'ai abandonné car le final ne pouvait jamais me produire un seul exe.
    Shell Extension :
    J'ai choisi pour ce cas d'utiliser dans mon projet actuel des composants comme MFC Shell ListCtrl qui m'a d'ailleurs épargné beaucoup de codage puisque je peux utiliser le bouton droit pour avoir le menu contextuel comme sur l'explorateur Windows: J'arrive donc à copier, supprimer, ouvrir, envoyer par e-mail un document sélectionné sans avoir eu à coder ces fonctions. 
    Vous dites ...
    "La solution actuelle fonctionne déjà, elle manque juste de convivialité.
    Ne serait-ce pas une exigence superfétatoire ? La solution ne doit pas ajouter
    des contraintes mais la solution actuelle en a déjà, et ça passe, non ?"
    Je réponds ...Si par superfétatoire vous vouliez faire référence au fait d'ajouter inutilement une contrainte supplémentaire ou quelque chose de superflu, je réponds que Non. J'ai voulu rajouter une fonction user friendly simplement et au final cette volonté fait que je ne peux plus respecter ma contrainte initiale d'un seul exécutable. MAIS après réflexion je dirais que je suis prêt aujourd'hui à renoncer à l'exécutable unique à condition que mon application puisse être installée entièrement sur une clé USB et aucune dll sur l'ordinateur hôte. Donc, m'orienter vers votre solution d'utiliser les manifestes pour dire que l'emplacement des dll est la clé USB et non l'ordinateur hôte. Pourquoi ? Parce que je trouve que la solution de prévisualisation des document sur ma page principale est devenu un MUST HAVE après mes premiers tests. Donc ce qui me restera à savoir faire maintenant dans le projet Visual C++ c'est comment indiquer l'emplacement de mes dll ? que je vais de toute façon être obligé d'embarquer.
    Vous dites ensuite...
    ">sinon il ya aussi un risque pour ma clé également.
    Normalement, vous devrez la monté en lecture seule et cela devrait toujours fonctionner, non ?"
    Je réponds..
    Oui tout à fait, la clé en lecture seule est une protection contre une éventuelle infection de virus et cela pourrait même être un argument pour convaincre une personne non disposé à me laisser son ordinateur pour y mettre ma clé.
    Enfin votre dernier point.
    ">utilisé VC++ qui me permettait d'avoir un exe compilé en static comme j'ai évoqué
    Si j'ai bien compris votre problème, je trouve que c'est un mauvais outil par rapport à votre problème."
    Je réponds...
    Vous avez certainement raison...ce point a été ma principale interrogation avant de démarrer ce projet et j'ai même posté une question la dessus pour avoir des conseils avisés avant de me lancer, mais hélas, les réponses que j'avais obtenues en fonction de mes exigences m'ont conduites au final vers VC++.
    J'ai développé pendant 10 ans puis ayant pris un peu de hauteur dans mes fonctions je ne code plus depuis 8 à 9 ans et donc en termes d'évolutions des langages de programmations même de visual studio, j'ai pensé que je n'étais plus à jour d'où mon premier post quant au choix du langage à utiliser. Finalement entre Visual Studio 2005 et 2017 (Oui ca fait longtemps) je n'ai pas eu bcp de mal. 
    Donc le choix mauvais ou pas a été fait et le produit final correspondait bien à mes attentes jusqu'à ce que....
    Voilà donc la situation que j'essaye maintenant de ne pas abandonné au risque d'y renoncer définitivement.

    La proposition de Castorix31:
    Je reconnais que j'ai pensé au départ qu'en rajoutant les .tlh et .tli je n'aurais plus à embarquer AcroPDF.dll. Mais personnellement je ne connaissais pas cette technique qu'il m'a apprise en utilisant #Import, en compilant une fois et en récupérant ces fichiers. Même si cela ne résolvait pas mon problème l'idée m'a semblé intéressante et d'ailleurs à ce jour c'est cette méthode qui me permet d'afficher le PDF car je n'ai pas trouvé une autre méthode. Je sais juste que si AcroPDF.dll évolue je serais obligé de rajouter les nouvelles versions de tlh et tli pour recompliler à nouveau... bref : contrainte+contrainte+contrainte....

    samedi 19 août 2017 18:33
  • >est vraiment destiné à des néophytes en informatique, c'est à dire à des utilisateurs lambda.

    Je n'ai pas de retour sur ce type de mise en place de Windows To Go, et effectivement, sans l'avoir déployé moi-même, je suis d'accord que le "coût" d'entré n'est pas nul.

    Pour les HTA, c'était IE Only, donc pas de "problèmes" de compatibilité entre navigateur, mais c'est toujours assez chiant de faire juste pour IE et il y a aussi des problèmes entre version d'IE.

    Ce n'est pas la pré-visualisation que je trouve peut-être superfétatoire mais les contraintes techniques comme la non utilisation de Dll.

    Pour les manifestes, regardez la partie "Préparation" de l'article suivant :

    https://msdn.microsoft.com/en-us/library/aa985617%28v=vs.90%29.aspx

    Attention, le manifeste fonctionne avec les Dll "directe", pas via l'infrastructure COM, qui utilise la base de registre.

    "#import" utilise l’infrastructure COM.

    Donc, le "#import" induit l'installation préalable des composants avant leur utilisation.

    Mais c'est peut-être gérable avec un message d'erreur demandant à l'utilisateur d'installer Acrobat Reader, quitte à fournir l'installation dans la clé USB.

    Pour l'usage du C++, ce n'est pas un choix facile et "ça passe comme une lettre à la poste", mais, pour votre cas de figure, je ne vois pas de meilleurs options non-plus (mais il y en a plein d'équivalentes).

    >je n'aurais plus à embarquer AcroPDF.dll.

    Vous avez à l'embarquer ET à l'enregistrer sur la machine hôte.

    Si on fait l'assertion que Acrobat Reader est installé sur toutes les machines, la solution de @Castorix31 est la plus simple (mais cela ne règle pas le problème des Dll mais le manifeste devrait faire le taf).


    Paul Bacelar, Ex - MVP VC++

    lundi 21 août 2017 14:18
    Modérateur
  • Bonjour Paul,

    Merci pour le lien sur la préparation du Manifeste à indiquer la location des dll à charger.

    Comme avons-nous souvent l'habitude d'entendre "il n'y a que les têtus qui ne changent pas d'avis"  (version soft :-))
    Je lève donc ma contrainte originelle d'un ex sans dll car à bien réfléchir ce n'est pas une vraie contrainte.
    Les deux seuls choix que j'avais pour l'affichage de mon PDF étaient l'utilisation AcroPDF.dll et le IWebBrowser2 interface de Microsoft. Les deux font appels à l'infrastructure COM, donc quoi qu'il en soit je devrais compter le fait qu'Acrobat Reader soit installé sur les machines et si ce n'est pas le cas de proposer à l'utilisateur de l'installer. Et s'il ne veut pas où si la machine hôte n'autorise aucune installation, je devrais faire en sorte que l'application puisse fonctionner sans la prévisualisation des documents comme dans la première version.

    En revanche une question me turlupine par rapport à l'utilisation d'AcroPDF. Selon la méthode @Castorix31 l'instruction #import n'existe plus puisque j'ai récupéré les fichiers générés AcroPDF.tlh et AcroPDF.tli que j'ai inclus directement dans mon projet puis fait #include "AcroPDF.tlh".
    Cette procédure ne contourne t-elle pas le nécessité d'enregistrer AcroPDF sur la machine hôte ? le fichier AcroPDF.dll à mon avis deviendrai dans cette façon d'utiliser une vraie Dll directe que je stockerai sur la clé et que j'indiquerai la location dans le manifeste ? Pour les futur mise à jour il me suffirai de régénérer les tlh et tli puis d'avoir la bonne version de la dll...
    Qu'en pensez-vous ???

    Bien sûr cette dernière question a  pour but d'avoir un peu plus de détail sur AcroPDF mais pas pour remettre encore tout en cause.

    Merci encore

    lundi 21 août 2017 16:05
  • Tout ce qui suit n'est que supposé, en fonction des mécanismes générales des outils COM et non spécifique aux composants AcroPDF que je n'ai jamais essayé de "#importés". Mais bon, c'est toujours pareil avec le reste, donc, sauf hack de sioux des personnes d'Adobe, ça devrait être "exacte".

    Je pense que vous faites un peu trop d'illusion sur le contenu de "AcroPDF.tlh". C'est du C/C++ standard qui a été généré par MIDL.EXE. Vous verrez que le code généré est un ensemble de code "copier-coller" qui ne sert qu'à simplifier l'appel de méthodes de composant COM depuis du code C ou C++.

    Le "#import" ne fait que demander au compilateur de "rendre la main" à MIDL.EXE pour qu'il lise toutes les informations sur les types d'objet COM que la Dll héberge : la Type Librairie (TypeLib ou TLB).

    Cette TypeLib, c'est juste des ressources "standard", avec "nom" de ressource spécial et un format spécial.

    Il est même possible de laisser cette TypeLib dans un fichier à part, ou de l'extraire de l'exécutable/dll, sous la forme d'un fichier tlb. (Utile pour faire de l'invocation de composant COM à distance sans avoir le code binaire sur la machine appelante : COM)

    MIDL.EXE lit ces ressources qui donnent l'identifiant de la TypeLib (TypeLibID), les identifiants de composant COM (ClassID), les interfaces qu'ils supportent (les composants), les identifiants des interfaces nouvelles (InterfaceID ou IID), les méthodes que chaque nouvelle interface déclare (avec leurs signatures).

    Avec toutes ces informations, MIDL.EXE ne fait que créer du code C et/ou C++ qui ne correspond qu'à des wrappers autour de ces composants COM. Le vrai code exécutable, il reste dans la Dll.

    Le code des wrappers utilise tous les identifiants que MIDL.EXE a glanés dans la TLB, mais à aucun moment il n'y a de transfert/copie de code exécutable. Avec ces identifiants et les fonctions de l’infrastructure COM, il est assez facile de faire ces wrappers automatiquement.

    Donc, avec votre code qui utilise ces wrappers, vous ne faites que simplifier les appels aux fonctions de l’infrastructure COM, qui elle, utilise tout plein d'information stockées dans la base de registre pour savoir comment bien utiliser les composants COM, qui peuvent être dans une Dll, mais aussi dans un exécutable, voir dans une Dll dans un autre exécutable, voir dans une Dll dans un autre exécutable dans une autre machine (DCOM).

    Donc, si vous utilisez ces wrappers, vous faites des appels COM et non des appels directement à des symboles exportés par la Dll. (une Dll pure COM n'exporte que ~4 méthodes, quelques soit le nombre de type de composant ou le nombre de méthodes des interfaces qu'ils implémentent.


    Paul Bacelar, Ex - MVP VC++

    lundi 21 août 2017 17:21
    Modérateur
  • Bonjour Paul,

    Je viens de comprendre dans l'architecture COM ce que je n'ai pas appris durant mes longues années de formation en informatique. Cela éclaire donc tous mes questionnements sur l'utilisation d'AcroPDF dans mon projet actuel et ce que cela entraine donc en termes de packaging, de distribution et d'installation du logiciel.
    Vraiment, vraiment mille mercis pour vos conseils avisés.

    CHEICKNA

    lundi 21 août 2017 22:54