Skip to content

Commit

Permalink
Fix #55847: DOTNET .NET 4.0 GAC new location
Browse files Browse the repository at this point in the history
If we do not specify the exact version of the .NET framework to use,
the default CLR is loaded, which is typically CLR 2, which is very old.
Therefore, we introduce a `PHP_INI_SYSTEM` setting, which allows users
to choose the desired .NET framework version.  The value of the setting
are the first three parts of the framework's version number, separated
by dots, and prefixed with "v", e.g. "v4.0.30319".  If the value of the
INI setting is `NULL` (the default) or an empty string, the default CLR
is used.

Internally, we switch from the most generic `CoCreateInstance()` to
`CorBindToRuntime()` which is implemented in mscoree.dll.  To avoid the
hard dependency to that library, we load dynamically.

So this fix is supposed to be fully backwards compatible.

Closes GH-5949
  • Loading branch information
cmb69 committed Aug 22, 2020
1 parent 969a432 commit e6044d4
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 4 deletions.
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ PHP NEWS
. Fixed bug #80007 (Potential type confusion in unixtojd() parameter parsing).
(Andy Postnikov)

- COM:
. Fixed bug #55847 (DOTNET .NET 4.0 GAC new location). (cmb)

- DOM:
. Fixed bug #79968 (DOMChildNode API crash on unattached nodes). (Benjamin)

Expand Down
4 changes: 4 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -1048,6 +1048,10 @@ PHP 8.0 UPGRADE NOTES
. New INI directive to set the maximum string length in an argument of a
stringified stack strace.

- com.dotnet_version
. New INI directive to choose the version of the .NET framework to use for
dotnet objects.

========================================
12. Windows Support
========================================
Expand Down
44 changes: 40 additions & 4 deletions ext/com_dotnet/com_dotnet.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,44 @@ struct dotnet_runtime_stuff {
DISPID create_instance;
};

/* We link dynamically to mscoree.dll to avoid the hard dependency on .NET
* framework, which is only required if a dotnet instance is to be created.
*/
static HRESULT dotnet_bind_runtime(LPVOID FAR *ppv)
{
HRESULT hr;
HMODULE mscoree;
typedef HRESULT (STDAPICALLTYPE *cbtr_t)(LPCWSTR pwszVersion, LPCWSTR pwszBuildFlavor, REFCLSID rclsid, REFIID riid, LPVOID FAR *ppv);
cbtr_t CorBindToRuntime;
OLECHAR *oleversion;
char *version;

mscoree = LoadLibraryA("mscoree.dll");
if (mscoree == NULL) {
return S_FALSE;
}

CorBindToRuntime = (cbtr_t) GetProcAddress(mscoree, "CorBindToRuntime");
if (CorBindToRuntime == NULL) {
FreeLibrary(mscoree);
return S_FALSE;
}

version = INI_STR("com.dotnet_version");
if (version == NULL || *version == '\0') {
oleversion = NULL;
} else {
oleversion = php_com_string_to_olestring(version, strlen(version), COMG(code_page));
}

hr = CorBindToRuntime(oleversion, NULL, &CLSID_CorRuntimeHost, &IID_ICorRuntimeHost, ppv);

efree(oleversion);
FreeLibrary(mscoree);

return hr;
}

static HRESULT dotnet_init(char **p_where)
{
HRESULT hr;
Expand All @@ -130,10 +168,8 @@ static HRESULT dotnet_init(char **p_where)
}
memset(stuff, 0, sizeof(*stuff));

where = "CoCreateInstance";
hr = CoCreateInstance(&CLSID_CorRuntimeHost, NULL, CLSCTX_ALL,
&IID_ICorRuntimeHost, (LPVOID*)&stuff->dotnet_host);

where = "dotnet_bind_runtime";
hr = dotnet_bind_runtime((LPVOID*)&stuff->dotnet_host);
if (FAILED(hr))
goto out;

Expand Down
1 change: 1 addition & 0 deletions ext/com_dotnet/com_extension.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("com.autoregister_casesensitive", "1", PHP_INI_ALL, OnAutoregisterCasesensitive, autoreg_case_sensitive, zend_com_dotnet_globals, com_dotnet_globals)
STD_PHP_INI_ENTRY("com.code_page", "", PHP_INI_ALL, OnUpdateLong, code_page, zend_com_dotnet_globals, com_dotnet_globals)
PHP_INI_ENTRY("com.typelib_file", "", PHP_INI_SYSTEM, OnTypeLibFileUpdate)
PHP_INI_ENTRY("com.dotnet_version", NULL, PHP_INI_SYSTEM, NULL)
PHP_INI_END()
/* }}} */

Expand Down
4 changes: 4 additions & 0 deletions php.ini-development
Original file line number Diff line number Diff line change
Expand Up @@ -1614,6 +1614,10 @@ zend.assertions = 1
; Default: system ANSI code page
;com.code_page=

; The version of the .NET framework to use. The value of the setting are the first three parts
; of the framework's version number, separated by dots, and prefixed with "v", e.g. "v4.0.30319".
;com.dotnet_version=

[mbstring]
; language for internal character representation.
; This affects mb_send_mail() and mbstring.detect_order.
Expand Down
4 changes: 4 additions & 0 deletions php.ini-production
Original file line number Diff line number Diff line change
Expand Up @@ -1618,6 +1618,10 @@ zend.assertions = -1
; Default: system ANSI code page
;com.code_page=

; The version of the .NET framework to use. The value of the setting are the first three parts
; of the framework's version number, separated by dots, and prefixed with "v", e.g. "v4.0.30319".
;com.dotnet_version=

[mbstring]
; language for internal character representation.
; This affects mb_send_mail() and mbstring.detect_order.
Expand Down

0 comments on commit e6044d4

Please sign in to comment.