summaryrefslogtreecommitdiffstats
path: root/private/ole32/common/olescm.cxx
blob: ecfafb1cf8c1eda2a9032ea0ed4a4c7af778aeb7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
//+---------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1992 - 1993.
//
//  File:       olescm.cxx
//
//  Contents:   Functions shared between OLE32 and the SCM
//
//  Classes:
//
//  Functions:
//
//  History:    10-03-95   kevinro   Created
//
//----------------------------------------------------------------------------

#include <windows.h>
#include <ole2sp.h>
#include <ole2com.h>

static const TCHAR tszOle32Dll[] = TEXT("OLE32.DLL");

#define OLE32_DLL tszOle32Dll
#define OLE32_BYTE_LEN sizeof(OLE32_DLL)
#define OLE32_CHAR_LEN (sizeof(OLE32_DLL) / sizeof(TCHAR) - 1)

//
// Threading Model Registry Constants
//

const TCHAR tszDllThreadModel[] = TEXT("ThreadingModel");

const TCHAR tszAptModel[]       = TEXT("Apartment");
const TCHAR tszBothModel[]      = TEXT("Both");
const TCHAR wszFreeModel[]      = TEXT("Free");

// Thread model match table. The table's first index is the threading
// model of the process and can be either APT_THREADED or
// FREE_THREADED. The second index is any one of the types of threading
// model's for DLLs.
BOOL afThreadModelMatch[2][4] =
    {{TRUE, FALSE, TRUE, TRUE},
     {FALSE, TRUE, FALSE, TRUE}};
//+---------------------------------------------------------------------------
//
//  Function:   CompareDllName
//
//  Synopsis:   Give a DLL path, this sees if the path is equal to a given
//              DLL name or the last component of the is the same as the
//              DLL name.
//
//  Arguments:  [pwszPath] -- DLL path
//              [pwszDllName] -- name of DLL to compare with
//
//  Returns:    TRUE - The input path is equal or its last component is equal
//                     to the input Dll name.
//              FALSE - Not equal at all.
//
//  History:    6-15-95   ricksa    Created
//
//  Notes:      This is a helper function used by the routines that convert
//              ole2.dll to ole32.dll and to convert paths that end in ole32.dll
//              into ole32.dll.
//
//----------------------------------------------------------------------------
BOOL
wCompareDllName(LPCTSTR ptszPath, LPCTSTR ptszDllName, DWORD dwDllNameLen)
{
    BOOL fResult = TRUE;

    if (lstrcmpi(ptszDllName, ptszPath) != 0)
    {
        // Check if the last component is the same path
        DWORD dwPathLen = lstrlen(ptszPath);

        if (dwPathLen > dwDllNameLen)
        {
            // Point to the last where the slash would be if the substitute
            // path is the last component
            LPCTSTR ptszLastComponent = ptszPath + dwPathLen - (dwDllNameLen + 1);

            // Is there a slash in that position
            if ((*ptszLastComponent == '\\') || (*ptszLastComponent == '/'))
            {
                // Point to where the last component should be
                ptszLastComponent++;

                // Does the last component match?
                if (lstrcmpi(ptszLastComponent, ptszDllName) == 0)
                {
                    goto CompareDllName_Exit;
                }
            }
        }

        fResult = FALSE;
    }

CompareDllName_Exit:

    return fResult;
}

//+-------------------------------------------------------------------------
//
//  Function:   wThreadModelMatch
//
//  Synopsis:   Determines whether caller and DLL thread models match
//
//  Arguments:  [dwCallerThreadModel] - Caller thread model
//              [dwDllThreadModel] - DLL thread model
//
//  Returns:    TRUE - DLL can be loaded caller
//              FALSE - DLL cannot be loaded into caller.
//
//  Algorithm:  If the caller's thread model is apartment, then check
//              whether the DLL is one of apartment, single threaded or
//              both threaded. If it is, then return TRUE. Otherwise,
//              for free threading return TRUE if the DLL model is either
//              both or free threaded. If neither of the above is TRUE
//              then return FALSE.
//
//  History:    10-Nov-94 Ricksa    Created
//
//--------------------------------------------------------------------------
BOOL wThreadModelMatch(
    DWORD dwCallerThreadModel,
    DWORD dwDllThreadModel,
    DWORD dwContext)
{
    BOOL fResult = afThreadModelMatch[dwCallerThreadModel] [dwDllThreadModel];

    if (dwContext & CLSCTX_PS_DLL)
    {
        fResult = TRUE;
    }

    return fResult;
}

//+-------------------------------------------------------------------------
//
//  Function:   wQueryStripRegValue
//
//  Synopsis:   Get the DLL information for a 32 bit DLL and
//              strip off any leading and trailing "
//
//  Arguments:  [hkey] - class handle
//              [pwszSubKey] - key to open
//              [pwszValue] - where to return data
//              [pcbValue] - length of above buffer in bytes
//
//  Returns:    ERROR_SUCCESS - read DLL path information
//              Other - registry entries could not be found
//
//  Algorithm:  Read the value requested.
//		If first character is not ", exit
//		Otherwise, copy data after quote to beginning of buffer.
//		
//
//  History:    05-Jan-94 BillMo     Created
//              26-Sep-95 BruceMa    Support environment variable expansion
//                                    for shell viewers
//
//--------------------------------------------------------------------------

LONG
wQueryStripRegValue(HKEY    hKey,        // handle of key to query
		    LPCTSTR ptszSubKey, // address of name of subkey to query
		    LPTSTR  ptszValue,  // address of buffer for returned string
		    PLONG   pcbValue)    // address of buffer for size of returned string
{
    HKEY  hSubKey;
    DWORD dwType;
    LONG  lErr ;

    Win4Assert(ptszValue != NULL);
    Win4Assert(pcbValue != NULL);

    //
    // Open the subkey if there is a string
    //
    if (ptszSubKey != NULL)
    {
	lErr = RegOpenKeyExT(hKey, ptszSubKey, NULL, KEY_READ, &hSubKey);
    }
    else
    {
	hSubKey = hKey;
	lErr = ERROR_SUCCESS;
    }

    // Read the value into the user's buffer
    if (lErr == ERROR_SUCCESS)
    {
        lErr = RegQueryValueExT(hSubKey, NULL , NULL, &dwType,
                               (BYTE *) ptszValue, (ULONG *) pcbValue);
        if (lErr == ERROR_SUCCESS)
        {
            TCHAR *ptszScan = ptszValue;	// used to scan along string
            TCHAR *ptszDest = ptszValue; 	// used as destination when copying

            // if the name is quoted then ...
            if (*ptszScan == '\"')
            {
                ptszScan++;

                // copy all non-quote characters down to base of buffer
                // until end of quoted string
                while (*ptszScan != '\0' && *ptszScan != '\"')
                {
                    *ptszDest++ = *ptszScan++;
                }

                // terminate string and get length in bytes including nul
                *ptszDest++ = '\0';
                *pcbValue = (ptszDest - ptszValue) * sizeof(TCHAR);
            }

            // find first non-white space character
            ptszScan = ptszValue;
            while (_istspace(*ptszScan))
                ptszScan++;

            // if there are no non-white space characters this will be true
            if (*ptszScan == L'\0')
            {
                lErr = ERROR_FILE_NOT_FOUND;
                *pcbValue = 0;
            }

            // Chicago does not support ExpandEnvironmentStrings
#ifndef _CHICAGO_
            // If the value type is REG_EXPAND_SZ then do environment variable
            // expansion
            if (dwType == REG_EXPAND_SZ)
            {
                // Expand any embedded environemnt variable expressions
                TCHAR tszTemp[MAX_PATH];

                lstrcpy(tszTemp, ptszValue);
                *pcbValue = ExpandEnvironmentStrings(tszTemp, ptszValue,MAX_PATH);
            }
#endif // !_CHICAGO_
        }

	//
	// Only close the sub key if we actually opened it.
	//
	if (hSubKey != hKey)
	{
	    RegCloseKey(hSubKey);
	}

    }
    return lErr;
}

//+-------------------------------------------------------------------------
//
//  Function:   GetDllInfo
//
//  Synopsis:   Get the DLL information for a 32 bit DLL
//
//  Arguments:  [hClsRegEntry] - class handle
//              [pwszKey] - key to open
//              [pwszDllName] - where to return DLL path
//              [pclDllName] - length of above buffer
//              [pulDllThreadType] - where to return DLL threading information
//
//  Returns:    ERROR_SUCCESS - read DLL path information
//              Other - registry entries could not be found
//
//  Algorithm:  Open the DLL key. Then read the DLL path name. Finally read
//              the threading model information if it is specified.
//
//  History:    09-Nov-94 Ricksa    Created
//
//--------------------------------------------------------------------------
LONG wGetDllInfo(
    HKEY hClsRegEntry,
    LPCTSTR ptszKey,
    LPTSTR ptszDllName,
    LONG *pclDllName,
    ULONG *pulDllThreadType)
{
    HKEY hDllEntry = NULL;

    // Open the registry key
    LONG lerr = RegOpenKeyT(hClsRegEntry, ptszKey, &hDllEntry);

    if (ERROR_SUCCESS == lerr)
    {
        // Read the DLL name
        lerr = wQueryStripRegValue(hDllEntry, NULL, ptszDllName, pclDllName);

        // Is there a DLL path?
        if (ERROR_SUCCESS == lerr)
        {
            if (wCompareDllName(ptszDllName,OLE32_DLL,OLE32_CHAR_LEN))
            {
		memcpy(ptszDllName,OLE32_DLL,OLE32_BYTE_LEN);
		*pclDllName = OLE32_CHAR_LEN;
                // Ole32 DLL will work anywhere
                *pulDllThreadType = BOTH_THREADED;
            }
            else
            {

                // Assume there is no registry entry
                *pulDllThreadType = SINGLE_THREADED;

                // Buffer to hold entry for the registry data.
                TCHAR tszModelBuf[MAX_PATH];
                DWORD cdwModelBuf = sizeof(tszModelBuf);
                DWORD dwRegEntType;

                // Read the DLL threading model from the registry

                lerr = RegQueryValueExT(hDllEntry, tszDllThreadModel, NULL,
                    &dwRegEntType, (LPBYTE) &tszModelBuf[0], &cdwModelBuf);
		
                // Is there an thread model descriptor
                if (ERROR_SUCCESS == lerr)
                {
		    if ( REG_SZ != dwRegEntType)
		    {
			// If it wasn't a string, bail
		    }
                    // Is it apartment model?

		    else if (lstrcmpi(tszAptModel, tszModelBuf) == 0)
                    {
                        *pulDllThreadType = APT_THREADED;
                    }
                    // Is is both threaded?
		    else if (lstrcmpi(tszBothModel, tszModelBuf) == 0)
                    {
                        *pulDllThreadType = BOTH_THREADED;
                    }
                    else if (lstrcmpi(wszFreeModel, tszModelBuf) == 0)
                    {
                        *pulDllThreadType = FREE_THREADED;
                    }
		    else
		    {
			// BUGBUG: Should print a warning here
		    }

                    // If neither then we fall back to single threaded
                    // since this is guaranteed to be safe for the DLL.
                }

                // When we get to this point, we got a DLL entry so we remap
                // any errors to success because they only mean that we could
                // not get a model from the registry.
                lerr = ERROR_SUCCESS;
            }
        }
        RegCloseKey(hDllEntry);
    }

    return lerr;
}