我的公司最终将我们的开发团队从 Windows XP 升级到了 Windows 7 64 位计算机,我刚刚发现新环境中现有代码的一个奇怪错误。有问题的项目引用了一个 COM 库,该库用于与我们的文档图像管理系统进行交互。任何初始化此 API 的库类实例的尝试现在都会抛出 SEHException。返回的错误代码没有提供信息。这是我为测试此问题而编写的精简示例项目的完整异常:
System.Runtime.InteropServices.SEHException was caught
ErrorCode=-2147467259
HResult=-2147467259
Message=External component has thrown an exception.
Source=FileNetTestLib
StackTrace:
at FileNetTestLib.Library.Logon() in C:\Projects\Tests\SEHException\FileNetTestLib\Library.vb:line 4
at SEHException.Form1.btnLogIn_Click(Object sender, EventArgs e) in C:\Projects\Tests\SEHException\SEHException\Form1.vb:line 7
InnerException:
Run Code Online (Sandbox Code Playgroud)
在使用我的示例项目时,我能够确认以下内容:
总而言之,如果我们在面向 .NET4 或更高版本的 Windows 7 上进行调试,则会发生错误。如果我们改变这些因素中的任何一个,它就不会发生。
在研究这一点时,我发现 .NET4 改变了它的安全模型,以处理从非托管代码抛出的异常。乍一看,这可能与问题有关,但从我到目前为止所学到的知识来看,这些变化只影响 SEHExceptions 的一个子集,显然不是我得到的,因为 (1) 我能够抓住在 try...catch 块中的 SEHException,其中 .NET 中的更改导致受影响的异常(损坏的状态异常)根本不会被 .NET 捕获,除非您对代码或配置文件进行了某些更改(我没有做这些更改)并已确认我的项目中不存在)和 (2) 问题仅在 Windows 7 …
我写了一个 Angular 指令,它表现出一些奇怪的行为。该指令向 $parsers 添加了一个函数,以根据正则表达式模式限制用户键入的内容。如果当前文本与模式不匹配,解析器会将文本恢复为字段的先前值。
结果,当文本被还原时,Angular 会将此检测为字段值的更改并再次进入解析器。这通常很好,因为传递给解析器的值现在有效,但我遇到了一个非常奇怪的怪癖。
在我得到这个指令后,我决定改变它的名字。我这样做了,突然验证失败了。我的错误处理程序报告了太多的递归。当我调试代码时,我发现在输入无效字符后第二次调用解析器将字段值参数显示为“未定义”。结果,我的代码将该值视为无效并尝试再次恢复,这导致再次调用解析器并使用“未定义”值等,直到发生堆栈溢出。
我改回指令名称,再次调试,一切突然开始正常工作!对解析器的第二次调用具有正确的值而不是“未定义”。
我稍微玩了一下,发现我可以通过改变指令名称的第一个字符来重新创建这个错误。以字符 'a' 到 'm' 开头的指令名称工作正常,但以 'n' 到 'z' 开头的名称坏了(好吧,我承认,我没有尝试所有 26 个字符,但字符样本显示样本中指令名称的第一个字母在字母表的前半部分的所有名称都有效,而第一个字母在字母表的后半部分的所有运行都失败了)。
我把一个plunker和我的代码放在一起来演示它:
http://plnkr.co/edit/k8Hpk2jsMCS6xjOKiES5
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.someNumber;
});
app.directive('formattedWithPattern', function () {
// Formats an input field as a positive integer.
// Usage:
// <input type="text" data-integer-format>
// Creates:
// <input type="text" data-integer-format>
return {
require: 'ngModel',
link: function (scope, element, attr, ctrl) {
if (!ctrl) return;
var pattern = attr.ngPattern;
// get the pattern between …Run Code Online (Sandbox Code Playgroud)