OSDN Git Service

An attempt to reduce build time
[winmerge-jp/winmerge-jp.git] / Src / dllpstub.cpp
1 /* dllpstub.cpp: Help implement DLL proxies
2  * Copyright (c) 2005 Jochen Tucht
3  *
4  * License:     This program is free software; you can redistribute it and/or modify
5  *                      it under the terms of the GNU General Public License as published by
6  *                      the Free Software Foundation; either version 2 of the License, or
7  *                      (at your option) any later version.
8  *
9  *                      This program is distributed in the hope that it will be useful,
10  *                      but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *                      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  *                      GNU General Public License for more details.
13  *
14  *                      You should have received a copy of the GNU General Public License
15  *                      along with this program; if not, write to the Free Software
16  *                      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 Please mind 2. a) of the GNU General Public License, and log your changes below.
19
20 DATE:           BY:                                     DESCRIPTION:
21 ==========      ==================      ================================================
22 2005/02/26      Jochen Tucht            Created
23 2006/09/10      Kimmo Varis                     Don't use 'export' as variable name
24                                                                 Visual Studio 2005 warns about it.
25 */
26
27 #include "stdafx.h"
28 #include "dllpstub.h"
29 #include <afxdisp.h>
30 #include <afxinet.h>
31
32 /**
33  * @brief Throw DLLPSTUB related exception.
34  */
35 void DLLPSTUB::Throw(LPCSTR name, HMODULE handle, DWORD dwError, bool bFreeLibrary)
36 {
37         CString strError = name;
38         if (handle != nullptr)
39         {
40                 TCHAR module[4096];
41                 module[0] = '@';
42                 if (::GetModuleFileName(handle, module + 1, 4095) == 0)
43                 {
44                         wsprintf(module + 1, _T("%p"), handle);
45                 }
46                 strError += strError.IsEmpty() ? module + 1 : module;
47         }
48         TCHAR szError[512];
49         if (CInternetException(dwError).GetErrorMessage(szError + 2, 510))
50         {
51                 szError[0] = ':';
52                 szError[1] = '\n';
53                 strError += szError;
54         }
55         if (bFreeLibrary && handle != nullptr)
56         {
57                 FreeLibrary(handle);
58         }
59         AfxThrowOleDispatchException(0, strError);
60 }
61
62 /**
63  * @brief Load a dll and import a number of functions.
64  */
65 HMODULE DLLPSTUB::Load()
66 {
67         // DLLPSTUB assumes that it is embedded in its owner
68         // followed by a char array of the DLL name to load
69         // so it access the char array via *(this + 1)
70         LPCSTR *proxy = (LPCSTR *) (this + 1);
71         HMODULE handle = nullptr;
72         if (LPCSTR name = *proxy)
73         {
74                 if (proxy[1] != nullptr && proxy[1] != name)
75                 {
76                         handle = LoadLibraryA(name);
77                         if (handle != nullptr)
78                         {
79                                 // If any of the version members are non-zero
80                                 // then we require that DLL export "DllGetVersion"
81                                 // and report a version as least as high as our
82                                 // version number members
83                                 if (dwMajorVersion || dwMinorVersion || dwBuildNumber)
84                                 {
85                                         // Is the DLL up to date?
86                                         DLLVERSIONINFO dvi{ sizeof dvi };
87                                         dvi.dwMajorVersion = 0;
88                                         dvi.dwMinorVersion = 0;
89                                         dvi.dwBuildNumber = 0;
90                                         DLLGETVERSIONPROC DllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(handle, "DllGetVersion");
91                                         if
92                                         (
93                                                 DllGetVersion == nullptr
94                                         ||      FAILED(DllGetVersion(&dvi))
95                                         ||      (
96                                                         dwMajorVersion && dvi.dwMajorVersion != dwMajorVersion
97                                                         ? dvi.dwMajorVersion < dwMajorVersion :
98                                                         dwMinorVersion && dvi.dwMinorVersion != dwMinorVersion
99                                                         ? dvi.dwMinorVersion < dwMinorVersion :
100                                                         dvi.dwBuildNumber < dwBuildNumber
101                                                 )
102                                         )
103                                         {
104                                                 // Well, that's the most appropriate canned system
105                                                 // message I came across: If DLL is outdated, it may
106                                                 // actually lack some interface we need...
107                                                 Throw(0, handle, CO_S_NOTALLINTERFACES, true);
108                                         }
109                                 }
110                                 LPCSTR *pszExport = proxy;
111                                 *proxy = nullptr;
112                                 while ((name = *++pszExport) != nullptr)
113                                 {
114                                         *pszExport = (LPCSTR)GetProcAddress(handle, name);
115                                         if (*pszExport == nullptr)
116                                         {
117                                                 *proxy = proxy[1] = name;
118                                                 pszExport = proxy + 2;
119                                                 break;
120                                         }
121                                 }
122                                 *pszExport = (LPCSTR)handle;
123                         }
124                 }
125                 if ((name = *proxy) != nullptr)
126                 {
127                         DWORD dwError = ERROR_MOD_NOT_FOUND;
128                         HMODULE handle1 = 0;
129                         if (proxy[1] == name)
130                         {
131                                 dwError = ERROR_PROC_NOT_FOUND;
132                                 handle1 = (HMODULE)proxy[2];
133                         }
134                         Throw(name, handle1, dwError, false);
135                 }
136         }
137         return handle;
138 }
139