Excel自定义函数
自定义函数
假定你想要为Excel编写自定义函数,但是这个自定义函数用vba写起来比较麻烦,还有一种做法就是编写一个dll。我们准备用熟悉的C/C++来编写dll,此时我们打开VS,写下了一个自定义函数Foo
,头文件定义如下
#ifndef TEST_H
#define TEST_H#pragma once#include <Windows.h>#ifdef TESTDLL_EXPORT
# define TESTDLL_API __declspec(dllexport)
#else
# define TESTDLL_API __declspec(dllimport)
#endif#ifdef __cplusplus
extern "C" {#endifTESTDLL_API int WINAPI Foo();#ifdef __cplusplus
}
#endif#endif // !TEST_H
这里大部分都是模板代码,需要注意的是Foo
的声明。Foo
的calling convetion是WINAPI
,也就是__stdcall
,vba中自定义c函数必须是WINAPI
。
我们在再来看vba中如何声明该函数
Declare Function Foo Lib "libpath" () As Long
这里有3点需要注意
Foo
有返回值,所以声明为Function
libpath
为dll的路径,可以是绝对路径,也可以是相对路径,这到后面再介绍- 返回值为
Long
不是Integer
C/C++导出函数名称
我们知道,c/c++编译器通常会对函数名进行修饰,其中两个原因是因为函数可以重载,还有为了区分不同的调用约定。这就导致dll中的导出函数名称和我们编写的函数名字不一样。为了能够让VBA找到导出函数,我们一般可以在声明VBA函数时指定Alias
。
假设c中有如下函数
void WINAPI Foo(int i);
对于32位和64位平台,导出函数名称不一样。[1]
32位
导出函数名字位_Foo@4
,所以函数声明为
Declare Sub Foo Lib "libpath" Alias "_Foo@4" (ByVal i As Long)
64位
Declare PtrSafe Foo Lib "libpath" (ByVal i As Long)
注意,这里我们使用了PtrSafe
关键字,因为在64位Office下面,函数声明需要PtrSafe
关键字。
数据类型
下表给出VBA
和C/C++
中常见的数据类型的对应关系
VBA | C/C++ | 说明 |
---|---|---|
Boolean | VARIANT_BOOL |
vba中的True=-1,False=0 VARIANT_BOOL实际为 short 的typedef
|
Integer | short | |
Long | int | |
Double | double | |
String | BSTR | BSTR是OLE的数据类型,是一个带长度前缀的字符串 |
Variant | VARIANT | |
Array | SAFEARRAY |
String
vba中的String
是Unicode string,对于常见的Win32 API,通常接受LPCWSTR
和LPCSTR
两种字符指针,分别是utf-16和ANSI的字符串。
String -> LPCWSTR、const wchar_t*或BSTR
这种比较简单,我们使用StrPtr
函数,直接获取String
的指针即可,因为String
本质上是一个BSTR
。
Declare Sub Foo Lib "libpath" (ByVal str As Long)
void WINAPI Foo(BSTR);
// void WINAPI Foo(LPCWSTR);
// void WINAPI Foo(const wchar_t*);
注意,vba的文档中找不到StrPtr
。
String -> LPCSTR 或 const char*
String
是utf-16编码的,如果我们声明vba中的函数接受String
,且c中的函数接受const char*
,那么vba就会根据系统当前的locale,将utf-16转换为ANSI字符串。显然这个过程可能是有损的,通常不建议这么做。还有中方法就是再vba中将字符串转换为utf-8数组后,再传递给c函数。
Declare Sub Foo Lib "libpath" (ByVal str As String)
void WINAPI Foo(const char*);
// void WINAPI Foo(LPCSTR);
ARRAY
要传递vba的数组到c/c++函数中,可以使用以下两种方法[2]
指向第一个元素的指针
Declare Sub Foo Lib "libpath" (ByRef anArray As Long, ByVal size As Long)Dim anArray() As Long
Foo anArray(0), UBound(anArray) + 1
void WINAPI Foo(const int* anArray, int size);
SAFEARRAY指针
Delcare Sub Foo Lib "libpath" (ByRef anArray() As Long)Dim anArray() Long
Foo anArray
void WINAPI Foo(SAFEARRAY** ppArray);
vba函数命名
vba函数的名字不能同Excel中已经存在的名字相冲突,比如单元格的名字。所以F2
这样的名字是非法,在调用时你会得到#REF!
错误。
Dll路径
Declare
时我们需要指定dll的路径,显然我们不想要硬编码路径。一种方法是我们修改PATH
变量,加入dll所在的目录。这个动作可以在打开插件的工作簿时完成,代码如下
Private Declare PtrSafe Function SetEnvironmentVariableW Lib "Kernel32" (ByVal name As LongPtr, ByVal value As LongPtr) As LongPrivate Sub Workbook_Open()Dim newPath As StringnewPath = "path to dll" & Environ("PATH")' TODO Warn if changing PATH failsDebug.Print SetEnvironmentVariableW(StrPtr("PATH"), StrPtr(newPath))
End Sub
References
[1] Decorated names
[2] How To Pass Arrays Between Visual Basic and C
Excel自定义函数相关推荐
- excel自定义函数添加和使用方法
第一,excel自定义函数简介 Excel自带很多函数供使用,但有些问题用内置函数解决起来很复杂,甚至是无能为力,这时就可以利用VBA开发自定义函数. 第二,excel如何添加自定义函数 excel自 ...
- excel自定义函数的注释_打印Excel注释的自定义列表
excel自定义函数的注释 If you've added comments to an Excel worksheet, you have a couple of built-in options ...
- VBA Excel 自定义函数不能调用成功的问题的解决方法
VBA Excel 自定义函数不能调用成功的问题的解决方法 问题以及解决方案的列举(持续更新中) 问题以及解决方案的列举(持续更新中) 自定义函数是自动化各种Excel重复操作的重要函数,我们可以用它 ...
- Excel 自定义函数按单元格背景颜色/字体颜色实现计数或求和
Excel 自定义函数按单元格背景颜色/字体颜色实现计数或求和 https://download.csdn.net/download/sea1_2/34881468
- EXCEL自定义函数无法运行的原因:可以在VBA里运行的函数,在EXCEL用自定义函数为什么报错?
目录 1目标问题: 为什么VBA里,function可以运行的代码,在EXCEL用自定义函数,会返回错误值? 2 先说结论 2.1 最容易发生的原因 2.2 其他原因梳理 3 自定义函数返回值的情况 ...
- 语言建立一个学生籍贯管理簿_编写一个Excel自定义函数,身份证信息提取如探囊取物...
观看视频更直观 我们建立信息表时不仅要输入性别.生日和年龄等信息,往往也需要输入身份证号码,而身份证号码中包含有籍贯.性别.生日和年龄等信息,从身份证号码中提取上述信息可以减少输入工作量,提高工作效率 ...
- 你所不知道的Excel自定义函数BUG
使用VBA开发自定义函数,可以弥补Excel内置函数的不足,简化函数公式,但是需要注意实现同样功能,自定义函数的效率远远不如内置函数,所以不要试图重新发明轮子. 最近发现了一个自定义函数的BUG(也可 ...
- python自定义函数求差_[VBA]发布一个计算桩号之差的Excel自定义函数(VBA)
这是一个可以计算桩号之差(也就是得到长度)的Excel(或WPS)扩展函数,可以减少工程师在统计工程量时的工作量. 该函数具有一定的通用性.可以在MS Office和金山WPS上使用. 文末会给出使用 ...
- Excel - 自定义函数
1. 问题: 假设我们在Excel中有以下需求: 你可以嵌套使用IF函数,判断每一个分数属于哪一个区间. 但是,4层IF会不会很容易出错:如果是5个区间,甚至是10个区间呢?嵌套使用10个IF不太现实 ...
- 如何使用Excel自定义函数并且全局使用
一.使用Excel自定义一个从末尾开始截取指定字符串后面的函数 1.选择文件->选项->自定义功能区:勾选开发工具. 2.选择开发工具->visual Basic 3.选择插入-&g ...
最新文章
- linux下安装libsvm_Linux下libsvm的安装及简单练习
- linux筛选之后备份到命令,linux find 命令使用备份
- github 档案馆(是不是那个把code放到北极的那个项目。。。)
- 树莓派debian配置lamp【解决apache不显示php】
- 机器学习 对模型进行惩罚_使用Streamlit对机器学习模型进行原型制作
- python 隐藏命令行窗口_python如何只执行cmd中的动作,但消除或隐藏cmd窗口 - 小众知识...
- mongodb副本集搭建
- 第五十三天:优化网站的常用方法
- TensorFlow精进之路(十一):反向传播BP
- java面试难吗_MBA提前面试考什么?MBA提前面试得到优秀的,复试还难吗?林晨陪你考研...
- Python中通过Image的open之后,去show结果打不开bmp图片,无法正常显示图片
- 电商数据分析的4大思维和8类指标
- Html Imput 的用法
- 浙江新曙光建设_中习集团大厦项目工地与姜太公签约,正在使用太公管工进行实名制考勤...
- 电脑录屏快捷键是什么?电脑录屏是什么键
- 苹果要求部分员工佩戴警用级随身摄像头
- android源代码目录详解
- C盘根目录下只能创建文件夹不能新建文件的解决办法
- 字节流与字符流(一)
- SD敢达服务器源码,《SD敢达OL》服务器账号数据合并规则