- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我搜索了文档 Office Excel API ,但根本找不到任何提及,如何实现。
问题:
幸运的 API 功能或某种错误可以通过 VBA 宏轻松解决。
但是,要做到这一点,我们只有两种可能性:
select
使用
Worksheet_SelectionChange
直接应用于单元格和捕获选择更改的方法在 VBA 中 - 它完美地工作。
Worksheet_change
ThisWorkbook
的任何操作之前,需要插入以下 VBA 宏。模块:Private Sub Workbook_NewSheet(ByVal Sh As Object)
On Error GoTo endline
Const SheetName As String = "_WorksheetSheetWorker"
CheckIfVBAAccessIsOn
If InStr(1, Sh.name, SheetName, vbBinaryCompare) >= 0 Then
If Sh.Range("$A$1") <> vbNullString Then
Const ModuleName As String = "m_TempMacroJS"
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets(SheetName)
'We will take MacroName from sheet which we added from JS
Dim MacroName As String
MacroName = ws.Range("A2").Value2
Dim rng As Range
Set rng = ws.Range("A1")
Dim pathToMacroBas As String
'Export the content of the cell to a .bas file
pathToMacroBas = ThisWorkbook.path & "\" & ModuleName & ".bas"
Open pathToMacroBas For Output As #1
Print #1, "Attribute VB_Name = """ & ModuleName & """ " & vbNewLine & ws.Range("A1").Value2
Close #1
'Declare VBProject Object
Dim vbaProject As VBProject
Set vbaProject = ThisWorkbook.VBProject
'Delete pre-existing module with the same name
On Error Resume Next
ThisWorkbook.VBProject.VBComponents.Remove ThisWorkbook.VBProject.VBComponents(ModuleName)
On Error GoTo 0
'Load the code as a new Module
vbaProject.VBComponents.Import ThisWorkbook.path & "\" & ModuleName & ".bas"
Dim vbaModule As VBIDE.VBComponent
Set vbaModule = vbaProject.VBComponents(ModuleName)
'Run the code and transfer working sheet to macro
'You can use this worksheet to transfer values to macro as JSON
Application.Run ModuleName & "." & MacroName, ws
'Cleanup
ThisWorkbook.VBProject.VBComponents.Remove vbaModule
'Optional
Kill pathToMacroBas
Application.DisplayAlerts = False
ws.Delete
Application.DisplayAlerts = True
End If
End If
Exit Sub
endline:
End Sub
Trust access to the VBA project object model
.请注意:您仍然需要启用
Microsoft Visual Basic for Applications Extensibility 5.3
Trust access to the VBA project object model
直接在注册。我还无法处理的问题是延迟。保存和关闭现有工作簿需要延迟时间。
Sub CheckIfVBAAccessIsOn()
'[HKEY_LOCAL_MACHINE/Software/Microsoft/Office/10.0/Excel/Security]
'"AccessVBOM"=dword:00000001
Dim strRegPath As String
strRegPath = "HKEY_CURRENT_USER\Software\Microsoft\Office\" & Application.Version & "\Excel\Security\AccessVBOM"
If TestIfKeyExists(strRegPath) = False Then
MsgBox "A change has been introduced into your registry configuration. All changes will be saved. Please reopen book."
WriteVBS
ThisWorkbook.Save
Application.Quit
End If
End Sub
Function TestIfKeyExists(ByVal path As String)
Dim WshShell As Object
Set WshShell = CreateObject("WScript.Shell")
On Error Resume Next
Dim RegValue As Boolean
RegValue = WshShell.RegRead(path)
If RegValue = True Then
TestIfKeyExists = True
Else
TestIfKeyExists = False
End If
On Error GoTo 0
End Function
Sub WriteVBS()
Dim objFile As Object
Dim objFSO As Object
Dim codePath As String
codePath = Me.path & "\reg_setting.vbs"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile(codePath, 2, True)
objFile.WriteLine (" On Error Resume Next")
objFile.WriteLine ("")
objFile.WriteLine ("Dim WshShell")
objFile.WriteLine ("Set WshShell = CreateObject(""WScript.Shell"")")
objFile.WriteLine ("")
objFile.WriteLine ("MsgBox ""Please wait until Excel will closes! Click OK to complete the setup process.""")
objFile.WriteLine ("")
objFile.WriteLine ("Dim strRegPath")
objFile.WriteLine ("Dim Application_Version")
objFile.WriteLine ("Application_Version = """ & Application.Version & """")
objFile.WriteLine ("strRegPath = ""HKEY_CURRENT_USER\Software\Microsoft\Office\"" & Application_Version & ""\Excel\Security\AccessVBOM""")
objFile.WriteLine ("WScript.echo strRegPath")
objFile.WriteLine ("WshShell.RegWrite strRegPath, 1, ""REG_DWORD""")
objFile.WriteLine ("")
objFile.WriteLine ("If Err.Code <> o Then")
objFile.WriteLine (" MsgBox ""Error"" & Chr(13) & Chr(10) & Err.Source & Chr(13) & Chr(10) & Err.Message")
objFile.WriteLine ("End If")
objFile.WriteLine ("")
objFile.WriteLine ("WScript.Quit")
objFile.Close
Set objFile = Nothing
Set objFSO = Nothing
'run the VBscript code
' > The macro will fail to execute the VB script if you use a
' [codepath] which contains blanks!
'
' > To fix this issue, we add a pair of double quotes (" ") around
' [codepath];
Shell "cscript " & Chr(34) & codePath & Chr(34), vbNormalFocus
End Sub
const VBAWorker = function(){
/* This is a name of tempurary sheet to execute macro */
this._executedMacroName = "JSSubRunner"
/* This is the name of sheet worker*/
this._WorksheetSheetWorkerName = "_WorksheetSheetWorker"
/* These options can be applied to already existed sheet*/
this._worksheetExistenceDecisionOptions = {
replaceSheet : "replaceSheet",
findNewAvailableName : "findNewAvailableName"
}
}
/**
* Function to run macro using sheet worker
* @param {String} VBAMacro is a code which will be executed
* @param {String} transferredValues (optional) are a values which we need
* to place into executable macro
* @param {String} worksheetDesicion (optional) is a desicion which we will if the worker worksheet exists
* default = "replaceSheet", possible = "findNewAvailableName"
*/
VBAWorker.prototype.run= async function(VBAMacro, transferredValues = "", worksheetDesicion = "replaceSheet"){
const defaultWorksheetName = this._WorksheetSheetWorkerName
let worksheetName = defaultWorksheetName
const preparedVBAMacro = this._changeMacroName(VBAMacro)
await Excel.run(async (context) => {
/* First we need to check out existence of sheet worker*/
let sheets = context.workbook.worksheets;
sheets.load("items/name");
await context.sync()
/**
* In this case we will deside what to do
* if we will find sheet with the same name
* */
const isSheetExists = this._checkWorksheetExistence(sheets)
const decisionOptions = this._worksheetExistenceDecisionOptions
if (isSheetExists){
switch (worksheetDesicion){
case decisionOptions.replaceSheet:
let sheetToReplace = sheets.getItem(worksheetName)
sheetToReplace.delete()
await context.sync()
break;
case decisionOptions.findNewAvailableName:
worksheetName = this._changeNameOfWorkerWorksheet(sheets)
break;
}
} else {
/* we will keep worksheetName as default */
}
let sheet = sheets.add(worksheetName);
let macroExeCell = sheet.getCell(0,0)
let macroNameCell = sheet.getCell(1,0)
let macroValuesCell = sheet.getCell(0,1)
macroExeCell.values = preparedVBAMacro
macroNameCell.values = this._executedMacroName
let preparedValues = []
const limit = 32700
const lengthOfString = transferredValues.length
// console.log(transferredValues.length)
// console.log(transferredValues.length / limit)
if (lengthOfString > limit) {
try {
let done = false
/* during cell lenght limit we will slice string to many*/
let lastStep = false
let current = limit
let oldcurrent = 0
do {
let end = current
let start = oldcurrent
/* Check that the next simbol not equals to "=" */
if(transferredValues.slice(end, end + 1) == "="){
current += 1
end = current
}
if (lengthOfString < start ){
start = lengthOfString
}
if (lengthOfString < end){
end = lengthOfString
lastStep = true
}
preparedValues.push(transferredValues.slice(start, end))
if (lastStep){
done = true
} else {
oldcurrent = current
current += limit
}
} while (done == false)
/* Write values to sheet*/
await preparedValues.forEach(async (el, i)=>{
macroValuesCell = sheet.getCell(0 + i,1)
macroValuesCell.values = [[el]]
})
} catch (error) {
console.log(error)
}
} else {
/* If string.length is less then limit we just put it directly to one cell*/
macroValuesCell.values = [[transferredValues]]
}
return await context.sync();
});
}
/**
* Function to search available name of sheet and return it
* @param {Array} sheets - worksheet items with
* returns suggestedName (string)
*/
VBAWorker.prototype._changeNameOfWorkerWorksheet = function(sheets){
try {
let suggestCounter = 0
let suggestedName;
let suggestedNameIsFree = false;
let worksheetName = this._WorksheetSheetWorkerName
do {
suggestedName = worksheetName + suggestCounter
suggestCounter = suggestCounter +1
suggestedNameIsFree = !this._checkWorksheetExistence(sheets)
} while (suggestedNameIsFree = false);
return suggestedName
} catch (error) {
console.log(error)
}
}
/**
* Function to check worksheet name existence
* @param {Array} sheets - worksheet items with names
* returns true or false
*/
VBAWorker.prototype._checkWorksheetExistence = function(sheets){
let isSheetExists = false
sheets.items.forEach(el=>{
if(el.name == this._WorksheetSheetWorkerName){
isSheetExists = true
return;
}
})
return isSheetExists
}
/**
* Function to change name of running macro
* @param {String} VBAMacro is a string that contains executed macro
* The name of running sub will be changed to "_JSSubRunner"
*/
VBAWorker.prototype._changeMacroName =function(VBAMacro){
const regex = /(Sub\s+)(.*)([(])/i
const renamedVBAMacro = VBAMacro.replace(regex, `Sub ${this._executedMacroName} (`)
return renamedVBAMacro
}
export default VBAWorker
const VBAWorkerInst = new VBAWorker()
await VBAWorkerInst.run(
"your VBA code goes here",
"your values in string (JSON for example) goes here",
"optional option:) - a name of decision what we need to do, if sheet already existed"
)
最佳答案
嗨,此功能目前不存在 Office.js API。我会在 Office 加载项用户语音网站上发布需求:https://officespdev.uservoice.com .谢谢你。
关于excel - 有没有办法从 Excel Addin 将宏插入到工作表中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57999868/
我正在开发一个基于我已经工作的现有网页的 Outlook 加载项(因此主要更改 UI 以适应我想要的外观)。 在我打开的任务 Pane 中,我有一个用于启动外部应用程序的“启动”按钮。 该应用程序已经
This question already has answers here: Closed 7 years ago. Possible Duplicate: Choosing between MEF
我可以从 outlook 加载项的侧面板访问漫游设置。但是当我尝试访问漫游设置时,如果 UI 对话框 (DialogAsync) 打开。它变得不确定。 var _settings = Office.c
我可以从 outlook 加载项的侧面板访问漫游设置。但是当我尝试访问漫游设置时,如果 UI 对话框 (DialogAsync) 打开。它变得不确定。 var _settings = Office.c
有没有办法在功能区下拉菜单中显示动态内容 Add-in Commands ?我认为在撰写本文时,这是无法实现的。此外,如果项目本身不能是动态的,是否可以至少为显示的标签提供动态字符串。 见 编辑: 我
我正在尝试安装 Rstudio 插件,但它们没有出现在“插件”按钮或“工具”→“插件”→“浏览插件...”菜单中。我首先更新了我的 Rstudio,然后再次重新安装,但无济于事。 我是这样处理的: d
在 appdomain 隔离功能开始工作之前,它至少需要 7 个程序集并将我的 AddIn 的数据模型限制为远程处理可以处理的数据类型。太复杂了! System.AddIn 团队博客向我暗示他们正在尝
我有一个我最近继承的Outlook 2007加载项,目前在生产中存在一个问题,有些用户正在周期性地,似乎是随机地禁用其加载项。外接程序中没有日志,并且在外接程序代码中的每个方法/事件调用周围都存在tr
在Outlook Web加载项中,我试图拦截发送电子邮件时触发的OnSend事件。 我在GitHub上使用了这个example,效果很好。 如果我在电子邮件正文中包含单词“attachment”,然后
当前进度: 我创建了一个 Excel 宏来保护/取消保护客户的工作簿。由于每次打开和关闭工作簿时都需要运行宏,因此 Excel 加载项似乎是最可行的。问题在于它们的文件结构的设计方式。此需要处理的 E
我创建了一个名为的 Excel 加载项 Project Count_Per Person.xlam 当我打开 Excel 并转到“开发”>“插件”并选择要安装的插件时,如果我在保存后关闭 Excel,
我用VBA编写了一个简单的Excel插件,它包含一个表单和相关代码。将其保存为加载项然后将其安装到 Excel 中后,什么也没有发生! 我需要在功能区中的某个位置放置一个按钮来触发我的加载项,就像“求
我有一个带有 WiX 安装程序的普通旧式 Windows 窗体应用程序,它已为所有用户安装到 Program Files文件夹如您所料。应用程序使用 System.AddIn framework 托管
我正在使用 Mono.Addins 框架、C# 和 visual studio 2010 编写一个可扩展的应用程序。 我的应用程序结构如下: 项目 1: namespace Plugins {
好的,所以我正在开发一个 Excel 插件,它可以分析单元格中的文本然后将其转换。 我希望它像在 excel 中做的事情一样工作,比如当你可以在单元格中输入 =abs(YOURNUMBER) 时绝对值
我有一个关于在 excel 加载项、应用程序级别中使用 windows 窗体的问题。 目标陈述:显示自定义窗体控件,类似于将图表插入到 excel 中的方式 自定义面板我尝试过自定义 Pane 加载项
我正在使用 Microsoft AddIn Framework 加载 AddIn 程序集。我在它们自己的进程中运行它们,以便将它们与服务分开。我不喜欢的是每个 AddIn 进程在任务管理器中都显示为
我们正在开发我们组织专有的 Outlook 插件。因此,我们宁愿不将其放在 AppSource 上,也不宁愿将插件源文件(所有 js、css 等)放在可公开访问的 url 上,即使我们可以将 list
是否可以将 OfficeJS 命令按钮放置到像 .xlam 文件一样构建的自定义 VBA 插件面板? * 我仍然希望混合使用 VBA 和 OfficeJS 最佳答案 这是未经测试的,但我相信沿着这些路
我正在开发一个 .NET 3.5 C# 桌面应用程序。它应该可以通过插件进行扩展。 是否有任何文章等讨论 MEF 和 Mono.AddIn 之间的差异,以帮助我做出明智的决定? 或者更好的是,你有这两
我是一名优秀的程序员,十分优秀!