Ответ 1
Обновлено, если вы можете получить <object>
, созданный из HTML (MyObject.object != null
), конечная проблема с обработчиком событий JavaScript заключается в том, что вы удаляете исходный HTML-документ с помощью document.write
перед вызовом MyObject.SayHello("Javascript Load")
и замените его на <p>Loaded ActiveX Object: ...</p>
. К тому времени все оригинальные обработчики событий JavaScript исчезли.
Таким образом, следующее прекрасно работает, событие запускается и обрабатывается (с помощью alert
):
<!DOCTYPE html>
<html>
<head>
<title>DemoCSharpActiveX webpage</title>
</head>
<body>
<script type="text/javascript">
window.objectLoadFailure = false;
</script>
<object id="MyObject" onerror="window.objectLoadFailure = true" classid="clsid:7A5D58C7-1C27-4DFF-8C8F-F5876FF94C64"></object>
<script type="text/javascript" for="MyObject" event="OnUpdateString">
alert("Hello from event handler");
</script>
<script type="text/javascript" for="window" event="onload">
alert("Hello from window.onload!");
alert(MyObject.object);
MyObject.SayHello("Javascript Load");
</script>
</body>
</html>
Чтобы ваша оригинальная логика работала, вы можете напрямую манипулировать DOM вместо использования document.write
. Или, по крайней мере, назовите его после того, как OnUpdateString
был запущен и обработан.
Теперь, когда я увидел полный источник, я могу сказать, что здесь несколько ошибок.
-
Вы можете попасть в точку останова внутри
SayHello
, потому что вы создаетеMyObject
из С# [MyObject myObject = new MyObject()
] и вызываете его из С# [myObject.SayHello("C# Launch")
]. Удалите это, и вы увидите, что он никогда не вызывается, когда вы вызываете его из JavaScript [obj.SayHello("Javascript Load")
]. -
Это приводит к другой проблеме:
<object>
не удается создать, и тем более ни один из ваших сценариев JavaScript даже не запускается, потому что ваш тестовый HTML файл подается из локальной файловой системы (черезfile://
). Это ограничение безопасности. Попытайтесь изменить свой script, как показано ниже, чтобы увидеть, что ни одно из предупреждений не отображается:<script type="text/javascript" for="window" event="onload"> alert("Hello from window.onload!"); alert(MyObject.object) // null! object wasn't created... document.write("<p>Loaded ActiveX Object: " + !window.objectLoadFailure); document.writeln("</p>"); if (typeof window.external.ControlObject !== "undefined") { document.write(window.external.ControlObject()); } var obj = document.MyObject; if (typeof obj.SayHello !== "undefined") { document.writeln("<p>Can Call say hello</p>") } obj.SayHello("Javascript Load"); </script>
-
Есть несколько способов его исправления. Самый простой способ - использовать "Mark of Web" . Самое сложное - предоставить пользовательскую реализацию
IInternetSecurityManager
. Я сам буду использовать еще один метод - Управление функциями Интернета - и отключить клавишиFEATURE_LOCALMACHINE_LOCKDOWN
,FEATURE_BLOCK_LMZ_SCRIPT
,FEATURE_BLOCK_LMZ_OBJECT
. Вы можете использовать следующий код, который я адаптировал из моего другого связанного ответа:// static constructor, runs first static Form1() { SetWebBrowserFeatures(); } static void SetWebBrowserFeatures() { // don't change the registry if running in-proc inside Visual Studio if (LicenseManager.UsageMode != LicenseUsageMode.Runtime) return; var appName = System.IO.Path.GetFileName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName); var featureControlRegKey = @"HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\FeatureControl\"; Registry.SetValue(featureControlRegKey + "FEATURE_BROWSER_EMULATION", appName, GetBrowserEmulationMode(), RegistryValueKind.DWord); // enable the features which are "On" for the full Internet Explorer browser Registry.SetValue(featureControlRegKey + "FEATURE_ENABLE_CLIPCHILDREN_OPTIMIZATION", appName, 1, RegistryValueKind.DWord); Registry.SetValue(featureControlRegKey + "FEATURE_AJAX_CONNECTIONEVENTS", appName, 1, RegistryValueKind.DWord); Registry.SetValue(featureControlRegKey + "FEATURE_GPU_RENDERING", appName, 1, RegistryValueKind.DWord); Registry.SetValue(featureControlRegKey + "FEATURE_WEBOC_DOCUMENT_ZOOM", appName, 1, RegistryValueKind.DWord); Registry.SetValue(featureControlRegKey + "FEATURE_NINPUT_LEGACYMODE", appName, 0, RegistryValueKind.DWord); Registry.SetValue(featureControlRegKey + "FEATURE_LOCALMACHINE_LOCKDOWN", appName, 0, RegistryValueKind.DWord); Registry.SetValue(featureControlRegKey + "FEATURE_BLOCK_LMZ_SCRIPT", appName, 0, RegistryValueKind.DWord); Registry.SetValue(featureControlRegKey + "FEATURE_BLOCK_LMZ_OBJECT", appName, 0, RegistryValueKind.DWord); } static UInt32 GetBrowserEmulationMode() { int browserVersion = 0; using (var ieKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Internet Explorer", RegistryKeyPermissionCheck.ReadSubTree, System.Security.AccessControl.RegistryRights.QueryValues)) { var version = ieKey.GetValue("svcVersion"); if (null == version) { version = ieKey.GetValue("Version"); if (null == version) throw new ApplicationException("Microsoft Internet Explorer is required!"); } int.TryParse(version.ToString().Split('.')[0], out browserVersion); } if (browserVersion < 7) { throw new ApplicationException("Unsupported version of Microsoft Internet Explorer!"); } UInt32 mode = 11000; // Internet Explorer 11. Webpages containing standards-based !DOCTYPE directives are displayed in IE11 Standards mode. switch (browserVersion) { case 7: mode = 7000; // Webpages containing standards-based !DOCTYPE directives are displayed in IE7 Standards mode. break; case 8: mode = 8000; // Webpages containing standards-based !DOCTYPE directives are displayed in IE8 mode. break; case 9: mode = 9000; // Internet Explorer 9. Webpages containing standards-based !DOCTYPE directives are displayed in IE9 mode. break; case 10: mode = 10000; // Internet Explorer 10. break; } return mode; }
-
Теперь ваши сценарии выполняются, но
<object>
по-прежнему не создается (alert(MyObject.object)
показываетnull
). Наконец, вам нужно будет реализоватьIObjectSafety
интерфейс вашего объекта ActiveX и site-lock это только для ваших собственных HTML-страниц. Без надлежащегоIObjectSafety
объект не будет создан в соответствии с настройками безопасности IE по умолчанию. Без блокировки сайта это может стать огромной угрозой безопасности, поскольку любой вредоносный script возможно, может создать и использовать ваш объект вне контекста вашего приложения.
Обновлено, чтобы ответить на комментарий:
Я обновил проект с предоставленным примером, обратите внимание, что у меня было сделал такое изменение, что есть кнопка С# и кнопка Javascript для запуска события. Кнопка JS работает, но С# не срабатывает. я ищет предупреждение "Привет из: С#".
В вашем коде экземпляр MyObject
создается и доступен исключительно из С#:
MyObject myObject = new MyObject();
// ...
private void button1_Click(object sender, EventArgs e)
{
// Call ActiveX
myObject.SayHello("C# Button");
}
Этот экземпляр не имеет ничего общего с экземпляром <object id="MyObject" onerror="window.objectLoadFailure = true" classid="clsid:7A5D58C7-1C27-4DFF-8C8F-F5876FF94C64"></object>
, который вы создаете из HTML. Это два отдельных, не связанных объекта. Обработчики событий работают только для последнего экземпляра <object>
. Вы даже не подписываетесь на какие-либо события в экземпляре new MyObject()
.
Если я правильно понимаю вашу цель, вам нужно это:
private void button1_Click(object sender, EventArgs e)
{
// Call ActiveX
//myObject.SayHello("C# Button");
this.webBrowser1.Document.InvokeScript("eval",
new[] { "MyObject.SayHello('C# Button')" });
}
Теперь обработчик события JavaScript будет вызван, и вы увидите предупреждение "C# Button"
.