很多时候我们用rundll32.exe作为宿主来运行dll的某个函数,每次都是潦草的搬一段代码完事。
这次有个dll需要导出给rundll32运行的函数,就先找了下资料,汇总了一下相关的知识点。
用法
rundll32.exe <dllname>,<entrypoint> <optional arguments>
<dllname>最好给完整路径,且注意路径中不能有空格、逗号和引号,所以最好把路径转成短文件名来避免出现非法字符
<dllname>和<entrypoint>之间用,隔开,不能有空格,<entrypoint>和<optional arguments>之间必须有空格
<optional arguments>这部分rundll32不会解析,而是作为<entrypoint>的第三个参数传递过去
导出函数
我们先来看下导出函数的原型
void CALLBACK EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow);
首先容易被忽略的一个知识点就是认为导出函数就是上面这样的MBCS编码的(第三个参数可见),但是现在大多数情况下,我们都是使用Unicode编码了,难道是因为这是历史原因吗?
当然不是,其实是可以导出Unicode版本的,我们先来看下rundll32是如何找到这个导出函数的:
- 给函数名加上W后缀,用GetProcAddress找(可见首先找的就是Unicode版本)
- 如果1没找到,那么加上A后缀找
- 如果2也没找到,那么就用原名字找
从上面的三个查找步骤,我们可以知道,如果我们要导出Unicode版本的,那么就得导出类似EntryPointW这样的函数名,且第三个参数为LPWSTR,然后使用的时候,要用rundll32 abc.dll,EntryPoint <传递的命令参数>
这样才能正确工作。
而如果导出函数是带A后缀,或者不带后缀的话,rundll32就会视为这个是MBCS编码的导出函数了。
总结
从上面的描述,可以知道,如果我们导出Unicode版本的函数,在使用的时候就要注意去掉W后缀
一旦有了这种潜规则,给别人使用的时候,就很容易出问题,所以一般情况下,还是建议导出不带后缀的MBCS版本