VBScript/VBA设置Word文档的页眉或页脚

由于工作需要我们常常需要批量设置Word文档的页眉或者页脚,除了递归遍历Word文件外,我们还需要借助Word.Application组件来实现页眉或页脚的增加或修改。

Option Explicit
 
Const MSWORD_FILENAME = "Word文件路径"

Const wdSeekCurrentPageFooter = 10
Const wdAlignParagraphCenter = 1
Const wdAlignParagraphRight = 2
Const wdSeekMainDocument = 0

Dim wdApp
Set wdApp = WSH.CreateObject( "Word.Application")
wdApp.visible = False

Set doc = wdApp.Documents.Open(MSWORD_FILENAME)
doc.Activate ' 激活打开的文档
doc.PageSetup.FooterDistance = 30 ' 设置页脚到页面底边的距离

' 定位到页脚
wdApp.ActiveWindow.ActivePane.View.SeekView _
 = wdSeekCurrentPageFooter
' 下面是针对字体的设置
wdApp.Selection.Font.Name = "Times New Roman"
wdApp.Selection.Font.Size = 14 ' 字号
wdApp.Selection.Font.Bold = True ' 加粗
wdApp.Selection.Text = "页脚0001"  ' 页脚文本
' 页脚文本的位置wdAlignParagraphRight为居右
wdApp.Selection.ParagraphFormat.Alignment _
 = wdAlignParagraphRight
' 返回定位到主文档
wdApp.ActiveWindow.ActivePane.View.SeekView _
 = wdSeekMainDocument

doc.Save ' 保存刚才的修改
doc.Close ' 关闭文档
Set doc = Nothing

wdApp.visible = True
wdApp.Quit
Set wdApp = Nothing

这里要注意的是设置页脚到底边距离的时候需要用到页面设置的功能,即PageSetup.FooterDistance。

Posted in:
  • VBScript/JavaScript/Python
  • 系统应用程序开发
Tagged
  • word
  • vbscript
  • 页眉页脚

利用Prism或IE9将网页变为桌面应用程序(Application)

一般情况下我们打开一个网站是通过浏览器的方式,这样打开的网站将会有地址栏前进后退按钮等一系列的浏览器特性,随着B/S应用和追求最大可视浏览面积的兴起,大家可能不再满足于一般的浏览器特性,因为我们已经让我们的网站看上去更加应用程序化,特别是Ajax应用的推广,大家可能感觉以网页的形式去构造交互式程序将变得比直接通过类似于C/C++编程得到的桌面应用来得方便,但是如何让我们的网页看上去更加像桌面应用程序呢,这里就需要借助于浏览器。

其实Mozilla实验室很早就推出了一款实验型产品,那就是Prism( 官方主页 ),这个就是借助于火狐(FireFox)浏览器的内核将网页变得更像应用程序,其可定制的东西有不少,包括建立图标什么的一应俱全。

Posted in:
  • 前端开发与用户体验
  • Web开发及相关
Tagged
  • ie浏览器
  • prism
  • 桌面应用

VC++中忽略所有默认库纯Win32 API编译及链接

原文发表于2008年10月15日 已略作修改

我们在用VC++编写Windows程序的时候可能会发现一般可执行体(.EXE)的文件体积都比较大,于是非常羡慕那些使用Win32汇编编写程序的人,因为他们编写的可执行文件非常小。其实应用程序的体积是一方面,另外应用程序的部署环境则是需要注意的另一方面,这方面我深有体会,曾经使用Visual Studio 2008编译过一个C++的Win32程序,本地测试正常,但是部署到客户机时,出现缺少什么动态库,于是还要 安装Visual C++ 2008可再发行组件包(Visual C++ 2005 Redistributable Package) ,这给软件部署带来了一定的麻烦,另外对于一个功能比较简单的程序,安装如此的组件包,可能心里会不好受,我们希望对于一些比较简单的应用程序可以直接调用系统提供的API,从而降低部署程序的复杂度。

其实对于VC++我们可以采用忽略所有默认库的方式避免编译器引入不必要的动态链接库,当然你可以使用如下的预编译宏。

#pragma comment(linker, "/nodefaultlib")

实际上,我们还需要在属性的 连接器->清单文件 将 生成清单 改为 否;然后选择 清单工具->输入和输出 将嵌入清单改为否;在C/C++中选择代码生成将缓冲区安全检查改为否(/GS-),否则编译会出现一个错误,设定程序的主入口点。注意上述配置一般在Release下,生成文件也在Release下编译链接,Debug可能无法使用,如果需要防止Debug模式编译,可以使用如下宏命令:

#ifdef _DEBUG   
#error Debug is disabled   
#endif    //    _DEBUG

另外对于函数入口的重新定义可以使用如下宏以代替属性配置。

#pragma comment(linker,"/ENTRY:wWinMainCRTStartup")

由于这里指定使用的宽字符(Unicode)API调用,所以我们将入口点定义为wWinMainCRTStartup,ANSI版建议定义为WinMainCRTStartup,另外Windows API有两个版本的API接口,ANSI版和Unicode版,ANSI版主要是为了兼容Windows 98等旧系统,一般ANSI API编译的程序体积比较小,但由于现在的基于NT的新的操作系统基本使用的Unicode API,相对而言,对于这些系统,Unicode API接口的速度要快于ANSI 接口的速度。

入口点做如下定义:

#include <windows.h>
HINSTANCE g_hInst    = NULL;
int WINAPI SimpleMain(VOID)
{
  return 0; 
}
VOID WINAPI wWinMainCRTStartup(VOID)
{
  g_hInst = GetModuleHandle(NULL);
  ExitProcess(SimpleMain());
}

理论上这样可以编译链接了,实际上还有很多错误,主要是链接方面的。由于我们使用了纯Windows API,所以不能使用memset,这时可以调用FillMemory(RtlFillMemory)、ZeroMemory(RtlZeroMemory)等等,这时编译会出现链接错误 是关于_memset符号链接的,实际上我们并没有使用memset,那这个错误是怎么产生的呢?其实微软重新定义了RtlFillMemory等API并使它们挂接到memset这个函数下,为了我们能够顺利编译,我们需要在自己的头文件里做如下处理。

#undef RtlFillMemory 
#undef RtlZeroMemory
extern "C" NTSYSAPI BOOL NTAPI 
RtlFillMemory ( VOID *Source1,DWORD Source2,BYTE Fill );
extern "C" NTSYSAPI BOOL NTAPI 
RtlZeroMemory( PVOID Destination, SIZE_T Length);
#define memset(Destination,Fill,Length) \
    RtlFillMemory((Destination),(Length),(Fill))

下面我们继续我们的编译,在链接这里又出现错误。

error LNK2001: 无法解析的外部符号 __imp__InitCommonControls@0 error LNK2001: 无法解析的外部符号 __imp__InitCommonControlsEx@4

跟踪后发现这两个函数InitCommonControls和InitCommonControlsEx由COMCTL32.dll导出,参考网上的解决方案,加入lib库。

#include <commctrl.h>
#pragma comment(lib, "comctl32.lib")

错误依旧!经过仔细寻找发现在属性配置里 链接器->输入 在附加依赖项里填入 comctl32.lib,编译,通过!

另外对于空间分配建议参考HeapAlloc、HeapFree等等API函数。

如果大家在操作过程中遇到什么问题欢迎讨论!

2011年4月5日更新

这篇文章在网上转载还是比较多的,部分童鞋在转载时没有署名,希望他们在看到这篇文章时及时更新出处,另外文章我略作修改,去掉了一个问题比较大的函数,就是处理命令行的那段,以免误导大家。

最后要说的是,除非你是做病毒木马,否则再小体积的程序势必带来运行的不稳定,请三思,如果对编译小体积的程序感兴趣的话,可以参考 TCC : Tiny C Compiler

Posted in:
  • Windows编程技术
  • 系统应用程序开发
Tagged
  • 编译链接
  • vc
  • win32api

对于转载的相关说明

网站发表于2011年之前的文章均遵循创作共同性,署名、非商业转载,但是实际考察后发现部分朋友转载无法做到署名这点,这对原创作者是极大的伤害,甚至有人连链接图标都原封不动的复制粘贴,给本服务器造成一定的流量负担,所以经研究决定对于2011年2月及以后发表的日志,在非本人授权的情况下禁止转载,如需要转载请先征得本人同意,否则则视为侵权,本人将保留相关权利。

最后,谢谢大家的支持!

Posted in:
  • 我的生活点滴
Tagged
  • 版权

学好编程的几点个人总结(C/C++)

原文发表于2009年2月9日

这几天睡觉前翻了翻几本图书馆借的计算机书籍,原作是外国人写的,看的是翻译的,有时翻译的确实可以了,害得我看书就像复读机一样,一句话有时看了几遍才理解,到后来有个东东直接就看不懂了,说翻译尊重原著也好,但也至少在看不懂的地方加点译者的说明啊,难怪有老师建议直接看英文原著呢,不过我看到字母就想睡觉。其实每次放假前都在图书馆借好几本书,每次都看不了几页,但不借回来又觉得心痒,哎,没得说了。

上次那本计算机书非要和那个离散数学挂个勾,其实问题很好理解,非要弄个数学的解释再挂个记不住的名词,汗,不知道俺离散没学好啊。不过说实在的数学对于计算机还是比较重要的。

我觉得比较通俗些的还是老吴送的那本《高质量C/C++编程》林锐主编的,这本书不错,有利于代码编码水平的提高。

常常还有人问我怎样才能学好一门编程语言,我总结了些供参考(C/C++风格):

注重课堂效率,上课时尽量不要做无关的事情,经常思考老师提出的代码,重点理解这个代码解决的什么问题,解决这个问题的目的是什么,该如何解决这个问题(几步走?),你自己是否有另外的办法也能解决这个问题。当然不要把老师的代码和书上的代码看得很神圣,这些代码也会出现问题,要敢于提出自己的见解而不是思维被束缚,另外代码也是个很灵活的东西,书上和老师提出的代码的某些语句是可以进行相关语句的等价替换的,比如像if else if等等阶梯型if判断 你就该考虑是否可以用switch代替了,常常思考这些问题有助于你的代码书写的灵活性,并且在以后深入学习中也有很大帮助,比如像代码效率及代码风格等等。另外在代码风格上还要提点意见,变量风格的问题,不要像以前一样定义int a, b, c, d这样看似毫无意义的变量,为什么会觉得程序枯燥和天书呢,其实这些不太好的变量名对这个造成一定的影响。比如像动物园有老虎,斑马,熊猫,统计一下数量,很多同学拿到手定义个int a, b, c分别代表老虎、斑马和熊猫的数量,然后就开始组织代码,到最后会发现代码越来越枯燥,于是就没有兴趣再写下去,或者隔段时间后看自己的代码又看不懂了,其实变量可以这样定义,int tiger, zebra, panda,这样就很形象了,比如像老虎生了只小老虎,老虎数量增加tiger++,熊猫不幸挂了一只于是panda--。这样就很容易理解了吧^_^(很有意思吧,代码就像做游戏一样的),当然,为了使代码更清晰你也可以这样定义int tiger_count, zebra_count, panda_count,千万不要怕多敲字哦。对于一些语句要求适当缩进,这个为了别人阅读你的程序更是为了方便你自己阅读自己的程序,如果怕缩进狂敲空格的话可以尝试着TAB键,很神奇哦。

Posted in:
  • 我的生活点滴
Tagged
  • 学习笔记

印象

原文发表于2010年1月15日

深冬的傍晚,漫步在校园里,这里没了城市的喧嚣,最多的时候,只有落叶伴随着轻风从树上缓缓的落到地面,发出沙沙声,仿佛是恋人耳边轻声的絮语,虽然不知道再说些什么,但是想必也是甜蜜的事情吧。习习的冷风像是双温柔的大手轻轻的拂过的面庞,这充满爱意的抚摸让我在寒冷中感到一丝丝温暖。傍晚是个神奇的时刻,光线黯淡了下来,柔和的向你展示着她的美丽,世界仿佛笼罩在这柔和之中,而校园在这特别的时候仿佛穿上了一层薄纱,透出了几份朦胧,让人幻想着美好,仿佛是善男信女之间的纯真的浪漫。在这层薄纱的遮掩下,远处古韵的阁楼仿佛是害羞的少女般,让人琢磨不透,丝丝的古韵也透露出校园独有的历史文化,也许正是这阁楼见证着校园的一切,白驹过隙般的时光让其变成了阅历丰富的老人,纵使没有仙风道骨般的气质,但也有慈眉善目的和蔼,让人不由得想去向他倾述,而他只是默默的听着,也许生活的真谛就在这寂静中。我闭上眼,贪婪的呼吸着这新鲜的空气,这浸满了历史韵味的气息。酒是陈的香,也许只有经历过百年的文化沉淀才能有那份独特的香味。

虽然我只是个过客,但是我在这校园里一点都不感觉到陌生,校园仿佛是慈爱的母亲,而我只是个不懂事的孩子,依偎在母亲的怀抱里,就这样被她宠爱着。

公元2010年1月12日 随记于南京大学鼓楼校区

后记

笔试结束后,正好有很短的空闲,于是就在南大的校园随便走了走,有些不知所云的感想,作此拙作记之。

Posted in:
  • 我的生活点滴
Tagged
  • 大学
  • 感想

C/C++函数传递参数需要指定缓冲区大小

原文发表于2009年2月5日 标题是《一个自己犯的C/C++错误》

以前自己写程序时经常犯的错误,后来才开始重视起来,为了更好的说明这个错误,我将演示代码贴出来:

#include <stdio.h> 
#include <string.h> 
#include <memory.h> 

// 写出缓冲区的16进制值
void print_byte(void *ptr, size_t size)
{
  unsigned i;
  unsigned char *bptr = (unsigned char *)ptr;

  for(i = 0; i < size; i++) {
    printf("%x ", *(bptr + i));
  }
  putchar('\n');
}

// 测试函数1 
void func_test(char *pbuf, size_t size)
{
  printf("SIZE=%d ? \n", sizeof(pbuf));
  memset(pbuf, 0, sizeof(pbuf));  // 我以前经常犯的错误 
  print_byte(pbuf, size);
}

// 测试函数2 
void func_test1(char *pbuf, size_t size)
{
  memset(pbuf, 0, size);
  print_byte(pbuf, size);
}

int main(void)
{
  char buffer[] = "0123456789";  // 字符缓冲区 

  printf("SIZE=%d\n", sizeof(buffer));
  print_byte(buffer, sizeof(buffer));
  memset(buffer, 0, sizeof(buffer));
  print_byte(buffer, sizeof(buffer));

  strcpy(buffer, "0123456789");
  func_test(buffer, sizeof(buffer));
  func_test1(buffer, sizeof(buffer));

  return 0;
}

可以看出,表面上这个错误是关于在函数内部将传参指向的缓冲区清零的,调试上述程序后发现主函数里定义的缓冲区被全部成功设置为0,而将这个缓冲区地址传入函数func_test后只有前4个字节被置0,那么问题出在哪里呢?问题就在sizeof上,在主函数上sizeof算得缓冲区为11(包含字符串结尾\0),而函数func_test里算得是4,很明显只是计算的指针的大小。

疑惑就在这里,buffer是数组名不就是地址吗,为什么传参后sizeof值就不算整个数组的大小而只算指针的大小呢?

其实这个问题很容易buffer是数组名,sizeof(数组名)算得的是整个数组占用的字节数,一旦赋值给任何指针(函数传参也相当于一种赋值),也就算的是这个指针的占用空间,和数组就没任何关系了。若还是算的事数组占用空间,那这个指针的占用就没办法计算了。

理解了这些就不难理解一些SDK提供的接口为什么要你传入缓冲区地址后还要你给出大小了,就像上面的修正函数func_test1。

通过这件事我知道什么事都不能想当然。不过对我过去的代码影响不是很大的因为在Windows API下经常使用固定大小MAX_PATH。于是大小就这样算了sizeof(TCHAR) * MAX_PATH。

Posted in:
  • 数据结构及算法理论
  • 计算机学习与研究
Tagged
  • 缓冲区
  • bug

编程中通过二进制状态位存储信息

原文发表于2009年3月7日

今天解皞同学询问了一道编程题,要求是用表驱动法也就是查表的办法解决,题目(部分)如下:

映射关系如下:
A, B, 和C 映射到 2
D, E, 和F 映射到 3
G, H, 和I 映射到 4
J, K, 和L 映射到 5
M, N, 和O 映射到 6
P, R, 和S 映射到 7
T, U, 和V 映射到 8
W, X, 和Y 映射到 9
Q和Z没有映射到任何数字。

可能最近一个链表的项目做晕头了,我的第一反应竟然是链表,后来想了下,这个应该使用普通数组的表结构会比较合理,我给出的建表方案如下:

映射关系是连续的,假设没有映射是1,那么映射关系应该是1-9这九个数字,化为数组下标应该是0-8。然后知道这是个一对多的关系,首先0对Q和Z、1对A、B和C……假设数组就是0~8的。

如何才能将一个数组下标对应的空间包含相应的多个联系呢?

我们可以通过状态位来判断,这里需要用到点位运算的知识。

设二元序列如下:
<0000 0001, A>
<0000 0010, B>
<0000 0100, C>
<0000 1000, D>
<0001 0000, E>
<0010 0000, F>
<0100 0000, G>
(省略若干)

大家应该能看出什么规律了,二进制的一位代表一个状态位,那么我们可以通过这些状态位索引字母A-Z。

那么一个无符号长整型( unsigned long )即可包含全部大写字母表的信息,比如包含A、B和C的信息,只要将A、B和C的二进制状态位按位或即可。

因此可以得到一张编码表: <0x2010000> <Q, Z>
<0x0000007> <A, B, C>
<0x0000038> <D, E, F>
<0x00001c0> <G, H, I>
<0x0000e00> <J, K, L>
<0x0007000> <M, N, O>
<0x0068000> <P, R, S>
<0x0380000> <T, U, V>
<0x1c00000> <W, X, Y>

然后可以通过查这张表,然后用检测某位的方式判断映射关系,检测某位只需要按位与判断结果是否为0即可。

下面给出源代码:

#include <stdio.h> 

int main(void) {

  unsigned long letter_table[9] = 
    {0x2010000, 0x0000007, 0x0000038, 0x00001c0,
     0x0000e00, 0x0007000, 0x0068000, 0x0380000,  0x1c00000};

  int get_letter, i;

  puts("Enter letter [A-Z] ?");
  get_letter = getchar();

  if(get_letter < 0x41 || get_letter > 0x5a) {
    fprintf(stderr, "Error letter must A-Z");
    return 1;              
  }
    
  for(i = 0; i < 9; i++) {
    if((((unsigned long)(0x1 << (get_letter - 0x41))) &
      letter_table[i]) != 0) {
      if(i != 0)
        printf("found it!  @ %c = %d\n", get_letter, i + 1);
      else 
        printf("letter %c without number.\n", get_letter);
      break;              
    }      
  }

  return 0;    
}

以上源代码在Dev-CPP GCC下编译通过。

当然不见得这个就是效率很高的,我只是想通过这篇文章给大家编程时拓宽思路,比如位状态变化就是一个比较好的存储信息的方式。

如果想要查表效率很高,我觉得可以根据用户的具体输入,经过简单数学运算可以得到离结果最近的查表起始点,然后查找。

如果对于位操作比较感兴趣的可以参考我的前面的 《简单介绍编程中位运算的使用》

Posted in:
  • 数据结构及算法理论
  • 计算机学习与研究
Tagged
  • 位运算
  • 信息存储

ROS软路由和VPN服务器组网备忘

突然想起之前某客户要求组建的公司网络,翻了半天,找到草稿图,现整理出来做个备忘,网络情况主要是分为出租户住宅网络和公司办公运营网络,然后通过ADSL宽带连接互联网。

之前的网络构架比较简单,直接是一个企业级路由和一个企业级交换机,然后住户和公司所有的计算机都连接在路由和交换机上,同时在路由上开启了DMZ主机,然后将独立的电脑作为公司的服务器,提供VPN、数据库以及OA等相关业务操作,后来运营一段时间后问题渐渐凸显出来,首先随着住户的增加,不良的带宽使用量上升,大量的P2P应用严重影响了公司外部VPN对业务数据的访问,在开启路由器QoS功能后有一定程度的缓解,但是让住户和公司采用同一个网络毕竟带来了种种不安全的因素。

通过以上考虑,我设计出一个低成本的网络结构方案,当然这个仅供参考,目前尚未实施,可能会有其他问题。

首先将住户的网络独立出去,我建议采用单独的服务器作为ROS软路由,然后在住户客户端采用PPPoE拨号进行网络管理,同时分配一段网络地址池,将ROS挂接到企业路由上,然后所有住户流量经过ROS合理控制后进入企业路由然后经ADSL出口。另外一部分是公司网络部分,公司网络部分采用直接挂接企业路由的办法,同时将服务器和备份存储NAS也一并挂上,同时将服务器作为VPN通道对外开启(当然如果路由器支持VPN功能则更好),然后外部客户端通过VPN验证后登入公司内部网络。

大概画了个图:

Posted in:
  • 计算机应用及维护
  • Windows系统
Tagged
  • vpn
  • ROS软路由
  • 网络组建

ICP备案证书被注销

当前网站备案证书“苏ICP备05028728号”被注销,原因不明,经过与服务器空间商的紧急联系,网站目前临时托管于国外,相关重新备案的手续尚在准备办理之中,给大家带来的不便还望见谅。
此次受影响的域名wangye.org、www.wangye.org。

今天早上发现网站无法访问,相关域名被301重定向到http://127.0.0.1的本机IP,开始以为是DNS问题,经过技术排查发现是主机空间的原因,在与服务器空间商的联系后得知是自己的备案被注销导致站点被暂停运行的原因,由于目前备案手续较为繁琐,所以已经联系空间商将网站临时托管于国外主机,但愿能早日办妥相关备案。

最后感谢大家的帮助和支持!

Posted in:
  • 我的生活点滴
Tagged
  • 网站维护
  • icp备案

© Wang Ye / 王 晔. All rights reserved.