OSDN Git Service

Avoid an assertion failure when loading settings from winmerge.ini
[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;
87                                         dvi.cbSize = sizeof dvi;
88                                         dvi.dwMajorVersion = 0;
89                                         dvi.dwMinorVersion = 0;
90                                         dvi.dwBuildNumber = 0;
91                                         DLLGETVERSIONPROC DllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(handle, "DllGetVersion");
92                                         if
93                                         (
94                                                 DllGetVersion == nullptr
95                                         ||      FAILED(DllGetVersion(&dvi))
96                                         ||      (
97                                                         dwMajorVersion && dvi.dwMajorVersion != dwMajorVersion
98                                                         ? dvi.dwMajorVersion < dwMajorVersion :
99                                                         dwMinorVersion && dvi.dwMinorVersion != dwMinorVersion
100                                                         ? dvi.dwMinorVersion < dwMinorVersion :
101                                                         dvi.dwBuildNumber < dwBuildNumber
102                                                 )
103                                         )
104                                         {
105                                                 // Well, that's the most appropriate canned system
106                                                 // message I came across: If DLL is outdated, it may
107                                                 // actually lack some interface we need...
108                                                 Throw(0, handle, CO_S_NOTALLINTERFACES, true);
109                                         }
110                                 }
111                                 LPCSTR *pszExport = proxy;
112                                 *proxy = nullptr;
113                                 while ((name = *++pszExport) != nullptr)
114                                 {
115                                         *pszExport = (LPCSTR)GetProcAddress(handle, name);
116                                         if (*pszExport == nullptr)
117                                         {
118                                                 *proxy = proxy[1] = name;
119                                                 pszExport = proxy + 2;
120                                                 break;
121                                         }
122                                 }
123                                 *pszExport = (LPCSTR)handle;
124                         }
125                 }
126                 if ((name = *proxy) != nullptr)
127                 {
128                         DWORD dwError = ERROR_MOD_NOT_FOUND;
129                         HMODULE handle1 = 0;
130                         if (proxy[1] == name)
131                         {
132                                 dwError = ERROR_PROC_NOT_FOUND;
133                                 handle1 = (HMODULE)proxy[2];
134                         }
135                         Throw(name, handle1, dwError, false);
136                 }
137         }
138         return handle;
139 }
140