我有一个VB.net应用程序,它需要读写Excel工作簿,使用OLEDB和数据库驱动程序。随着时间的推移,我在StackOverflow上学到了大量的东西,这使我能够让一切都按应有的方式工作。这些主题涵盖了从连接字符串到“魔术”TypeGuessRows设置/255个字符限制(现在位于注册表中)的所有内容。随着时间的推移,由于多年来微软的发展,这个问题本身已经发生了变化,所以我不会引用这些(数百?数千人?)这里的帖子。只需说一句,我就能把它拼凑在一起,让它发挥作用。
供参考:我的连接字符串如下所示:
"Provider=Microsoft.ACE.OLEDB.12.0;Data Source='@DBQ';Extended Properties='Excel 12.0 Xml;HDR=YES';"
其中'@DBQ‘在运行时被所选Excel工作簿的适当路径名替换。注意,它不包含TypeGuessRows (因为它已经移到注册表了),而且IMEX=(不管什么)也不起作用,所以它不会出现。其结果是,只要TYPEGUESSROWS在注册表中设置为零,一切都运行得很好。
使用regedit在所有事件中手动搜索和设置TypeGuessRows=0 (我在StackOverflow上了解到的事情之一),这已经成功并完全避免了255-char截断。
问题是,每当有Windows更新时,它就会被设置为默认值8。没有警告或通知;只有当我开始看到“截断到255个字符”的症状再次出现时,我才知道这一点。因此,我必须返回并再次使用RegEdit。
显而易见的解决方案是,应用程序自己做这个设置,但这似乎需要操纵安全功能,这是我宁愿完全避免的事情,因为它似乎比我现在想要处理的更复杂。
因此,我想,“为什么不直接扫描适当的注册表项,如果它们不是零就报告”,然后向用户发出一条消息,以便使用regedit对其进行排序。
我编写了以下函数,它查看我找到的所有包含TypeGuessRows的各种注册表项:
Public Function CheckRegistry() As Integer
Dim Val1 As Integer = 0, Val2 As Integer = 0
Dim KeysToCheck As String() = New String() {
"HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Jet\4.0\Engines\Excel",
"HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Jet\4.0\Engines\Lotus",
"HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Office\14.0\Access Connectivity Engine\Engines\Excel",
"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\ClickToRun\REGISTRY\MACHINE\Software\Wow6432Node\Microsoft\Office\16.0\Access Connectivity Engine\Engines\Excel"
}
'
' try two methods for checking the registry values.
'
' method 1 uses the My.Computer class
'
For Each Key As String In KeysToCheck
Dim aVal As Object = My.Computer.Registry.GetValue(Key, "TypeGuessRows", CType("BOGUS", Object))
If IsNothing(aVal) Then ' did we hit Nothing?
Continue For ' have to skip it
ElseIf aVal.Equals(CType("BOGUS", Object)) Then ' did we hit one not exist?
Val1 = -9999 ' set a crazy value
End If
Val1 += CInt(aVal) ' otherwise, get its value and add to total
Next
'
' method 2 uses the RegistryKey class
'
Dim aKey As Microsoft.Win32.RegistryKey
For Each Key As String In KeysToCheck
Dim LM As Microsoft.Win32.RegistryKey = Microsoft.Win32.Registry.LocalMachine ' point to HKLM
Key = Key.TrimStart("HKEY_LOCAL_MACHINE\".ToCharArray) ' peel off the start (a convenience)
aKey = LM.OpenSubKey(Key, Microsoft.Win32.RegistryKeyPermissionCheck.ReadSubTree) ' try to read the subkey
If IsNothing(aKey) Then Continue For ' did we hit Nothing? have to skip it
'If CInt(aKey.GetValue("TypeGuessRows", 0)) <> 0 Then aKey.SetValue("TypeGuessRows", 0)
Val2 += CInt(aKey.GetValue("TypeGuessRows", 0)) ' otherwise, get its value and add to total
Next
Return Val1 + Val2 ' return the sum of both methods
End Function
这是很好的工作,除了最后一个,一个“...ClickToRun.”用钥匙的名字。无论如何,这总是以零形式返回,所以检查它的尝试失败了。即使在第一种方法中,我特别要求它返回一个“假”对象,但它总是作为空值返回。
问题是通过Windows更新的是这个键。到目前为止,我还从未见过其他三人中的任何一个被重置。
如果我“遍历此键的树”(即,尝试查看"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office"),,它可以正常工作,直到我到达ClickToRun分支,此时它将什么也不返回。
我想我有两个问题:
进一步信息:这台机器是Win 10 Pro,64位,安装了适当的驱动程序.该应用程序被设置为“启用ClickToRun安全设置”和“完全信任应用程序”。我已经在app.manifest中使用了这些设置和适当的条目,但是到目前为止,这只会在其他地方造成(很多)其他的悲伤和困难。所以我才不想搞砸。
任何帮助都会很感激的。
发布于 2021-05-18 03:25:14
睡了一觉,再想一想,特别是这里的一些暗示
Reading 64bit Registry from a 32bit application我至少能够读取注册表项。问题是,我试图从我的32位应用程序中“读取”64位注册表项。
现在,我可以做我真正想做的事情,即检测TypeGuessRows问题何时再次出现,并警告用户对此做些什么。
以下是修改后的代码:
Public Function CheckRegistry() As Integer
Dim CheckVal As Integer = 0
Dim KeysToCheck As String() = New String() {
"SOFTWARE\WOW6432Node\Microsoft\Jet\4.0\Engines\Excel",
"SOFTWARE\WOW6432Node\Microsoft\Jet\4.0\Engines\Lotus",
"SOFTWARE\WOW6432Node\Microsoft\Office\14.0\Access Connectivity Engine\Engines\Excel",
"SOFTWARE\Microsoft\Office\ClickToRun\REGISTRY\MACHINE\Software\Wow6432Node\Microsoft\Office\16.0\Access Connectivity Engine\Engines\Excel"
}
Dim LMachine As Microsoft.Win32.RegistryKey =
Microsoft.Win32.RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine,
Microsoft.Win32.RegistryView.Registry64)
Dim LKey As Microsoft.Win32.RegistryKey
For Each Key As String In KeysToCheck
Try
LKey = LMachine.OpenSubKey(Key, Microsoft.Win32.RegistryKeyPermissionCheck.ReadSubTree)
CheckVal += CInt(LKey.GetValue("TypeGuessRows", 0))
Catch ex As Exception
LMachine.Close()
Return -9999
End Try
Next
LMachine.Close()
Return CheckVal
End Function
在测试中,它可以成功地检查显示的所有四个键。试捕从来没有被发射过,但我还是为了安全而离开了那里。
我希望其他人可能会发现这是有用的。
https://stackoverflow.com/questions/67574449
复制相似问题