2023年2月

代码下载地址:
https://files.cnblogs.com/wuhuacong/VBActiveX.rar

由于存在一下几种特点:
1、.NET程序反编译容易,而使用一些混淆工具会导致有些程序不能运行
2、VB6开发ActiveX控件,那叫一个快,VB代码也不是很容易被反编译。
3、结合两者的特点,如果在.NET中使用了封装一些关键代码的ActiveX控件,那么程序的安全性是否好一点呢?

对于这种做法,请大家拍砖讨论,本人提供一个如何实现这种做法的思路。

一、 编写一个封装关键字符串或者实现逻辑的ActiveX控件
1、首先使用VB6创建一个ActiveX的工程项目
Snap1.jpg
2、设置VB ActiveX的工程属性
Snap1-2.jpg

3、编写类模块函数


Option

Explicit



Public

Function
GetString()
As

String


GetString

=

"
ABCDEFG
"


End Function




Public

Function
ValidateString(ByVal str
As

String
)
As

Boolean


ValidateString

=

False



If
str
=

"
ABCD
"

Then


ValidateString

=

True


Else


Err.Raise Err.Number, ,

"
不正确
"


End

If


End Function



Public

Function
GetDateTime()
As

Date



GetDateTime

=

Now



End Function

注意:如果使用Err.Raise函数,在调用过程中会抛出一个异常


二、在.NET程序中引用并使用该ActiveX控件
1、创建一个Windows Form程序
Snap2.jpg
2、添加ActiveX控件的引用

Snap3.jpg

3、编写按钮事件及ActiveX控件调用代码


using
System.Data;

using
System.Drawing;

using
System.Text;

using
System.Windows.Forms;


namespace
TestMyVBControl



{

public

partial

class
Form1 : Form



{

public
Form1()



{

InitializeComponent();

}




private

void
btnTest_Click(
object
sender, EventArgs e)



{

MyVBControl.TestClass test

=

new
MyVBControl.TestClass();

MessageBox.Show(test.GetString());

}




private

void
btnValidate_Click(
object
sender, EventArgs e)



{

MyVBControl.TestClass test

=

new
MyVBControl.TestClass();

try




{

MessageBox.Show(test.ValidateString(

"
ABCD
"
).ToString());
//
正确


MessageBox.Show(test.ValidateString(
"
ABCDE
"
).ToString());
//
有错误


}



catch
(Exception ex)



{

MessageBox.Show(ex.Message);

return
;

}



}




private

void
btnGetDate_Click(
object
sender, EventArgs e)



{

MyVBControl.TestClass test

=

new
MyVBControl.TestClass();

MessageBox.Show(test.GetDateTime().ToString());

}



}



}


结束,收工

地球人都知道,静态HTML页面通常会比服务器端页面如asp、aspx页面要来的快,即使这些页面没有服务器端代码。
另外要命的是,这些页面在主流的搜索引擎能中最为吃香,和那些aspx还带几个尾巴参数的页面比起来,真是天上地下。
如果那天老板发现这个问题,叫你把辛辛苦苦实现的服务器端程序向静态HTML页面靠拢,你会做何感想?
有一种URL重写的方案可以实现对搜索引擎的欺骗,除了这种方法,自动生成静态HTML页面应该是最彻底的方法了。
言归正传,开始介绍如何实现吧
1. 引用Nvelocity0.5,记得是0.5哦,NVelocity0.4我试过好久,好像不行,好像和路径有关系。
2、引用一些需要的命名空间


using
NVelocity;

using
NVelocity.App;

using
NVelocity.Exception;

using
NVelocity.Runtime;

using
NVelocityTemplateEngine;

using
NVelocityTemplateEngine.Interfaces;

3、初始化一些变量来使用


INVelocityEngine fileEngine;

IDictionary context;






///

<summary>


///
初始化NVelocity模板引擎并加载程序的配置信息e

///

</summary>



protected

void
InitTemplateEngine()



{

context

=

new
Hashtable();

string
templateDirectory
=
Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
"
Articles
"
);

fileEngine

=
NVelocityEngineFactory.CreateNVelocityFileEngine(templateDirectory,
true
);

}


4、页面生成代码



public

override

void
Execute()



{

string
message
=

string
.Format(
"
Create the Helper class file.
"
);

log.Debug(message);


string
sql
=

string
.Format(
"
select * from article
"
);

if
(
!
isCreateAll)



{

sql

=

string
.Format(
"
select * from article where generated =False
"
);

}




using
(IDataReader reader
=
xConfig.ExecuteReader(sql))



{

while
(reader.Read())



{

PrepareClass(reader);

OutputFile();

}



}




sql

=

"
update article set generated =True
"
;

if
(
!
isCreateAll)



{

sql

=

"
update article set generated =True  where generated =False
"
;

}



xConfig.ExecuteNonQuery(sql);

}






///

<summary>


///
Prepares the class content.

///

</summary>



private

void
PrepareClass(IDataReader reader)



{

FileNameOfOutput

=

string
.Format(
"
{0}#{1}
"
, ((DateTime) reader[
"
datetime
"
]).ToString(
"
yyyy-MM-dd
"
), reader[
"
id
"
].ToString());


context.Clear();

context.Add(

"
id
"
, reader[
"
id
"
].ToString());

context.Add(

"
category
"
, reader[
"
category
"
].ToString());

context.Add(

"
title
"
, reader[
"
title
"
].ToString());

context.Add(

"
content
"
, reader[
"
content
"
].ToString());

context.Add(

"
datetime
"
, reader[
"
datetime
"
].ToString());

}







///

<summary>


///
根据模板创建输出的文件

///

</summary>



public

virtual

void
OutputFile()



{

if
(fileEngine
!=

null
)



{

string
filePath
=
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, directoryOfOutput);

string
fileName
=
Path.Combine(filePath, fileNameOfOutput
+
fileExtension);


DirectoryInfo dir

=

new
DirectoryInfo(filePath);

if
(
!
dir.Exists)



{

dir.Create();

}




log.Debug(

string
.Format(
"
Class file output path:{0}
"
, fileName));

using
(StreamWriter writer
=

new
StreamWriter(fileName,
false
))



{

fileEngine.Process(context, writer,

this
.templateFile);

}



}



}


5、界面层生成页面



string
template
=

"
page.htm
"
;

try




{

HelperClassAdapter helper

=

new
HelperClassAdapter(template,
false
);

helper.Execute();

Response.Write(

"
<script>alert('生成成功');</script>
"
);

}



catch
(Exception ex)



{

Helper.ShowError(

this
, ex,
false
);

return
;

}



页面生成就可以了,具体做法自己琢磨就可以了。
页面模板文件


<
HTML
>


<
HEAD
>


<
TITLE
>
$title
</
TITLE
>


<
META
http-equiv
=Content-Type
content
="text/html; charset=UTF-8"
>


<
META
content
="$title"
name
=description
>


<
META
content
="$title"
name
=keywords
>


</
HEAD
>


<
BODY
>


<
strong
class
="style3"
>
$title
</
strong
></
h2
>


<
div
>
$content
</
div
>


<
hr
width
="98%"
/>


<
div
align
="right"
>
$datetime
</
div
>


</
BODY
>


</
HTML
>

1. Visio属性值的转换问题
做过Visio开发的人知道,Visio中的属性值也就是Cell.Formula的值通常包含两对双引号的(如""XX""), 如果要将属性的值转换正常的字符串值,那么需要去除双引号。因此从Visio的Cell的Formula值中得到的字符串需要经过下面方法处理一下:



public

static

string
FormulaStringToString(
string
formula)



{

const

string
OneQuote
=

"
\
""
;



const

string
TwoQuotes
=

"
\
"
\
""
;

string
convertedFormula
=

""
;


try




{

convertedFormula

=
formula;

if
(convertedFormula.StartsWith(OneQuote)
&&
convertedFormula.EndsWith(OneQuote))



{

convertedFormula

=
convertedFormula.Substring(
1
, (convertedFormula.Length
-

2
));

convertedFormula

=
convertedFormula.Replace(TwoQuotes, OneQuote);

}



}



catch
(Exception err)



{

convertedFormula

=

""
;

}




return
convertedFormula;

}


如果是写入到Visio的Cell的Formula中,那么要经过反过程,如下所示:



public

static

string
StringToFormulaForString(
string
input)



{

const

string
quote
=

"
\
""
;



string
result
=

""
;


if
(input
==

null
)



{

return

null
;

}




result

=
input.Replace(quote, (quote
+
quote));

result

=
quote
+
result
+
quote;


return
result;

}


2、获取指定形状指定Cell的值
。除了方法1,还有下面一种方法可以获取Cell的Value值。这种方法比使用Formula获取字符串的方式要好,是因为在Visio2007中下拉列表“资产归属”.对应的Cell的Value可能是INDEX(0,Prop.资产归属.Format),但是如果使用下面的方法就可以正常获取到它具体的值了。



public

static

string
GetShapeCellValue(Shape shapeTarget,
string
strCellType)



{

const

string
CUST_PROP_PREFIX
=

"
Prop.
"
;

string
shapeCellValue
=

string
.Empty;


if
(shapeTarget.get_CellExistsU(CUST_PROP_PREFIX
+
strCellType, (
short
)VisExistsFlags.visExistsAnywhere)
!=

0
)



{

shapeCellValue

=
FormulaStringToString(shapeTarget.get_CellsU(CUST_PROP_PREFIX
+
strCellType).get_ResultStr(VisUnitCodes.visNoCast));

}




return
shapeCellValue;

}


3、给指定的Shape赋值。
方法2是读取,当然还需要写入到指定Shape,指定Cell的值



public

static

bool
SetShapeCellValue(Shape shapeTarget,
string
strCellType,
string
cellValue)



{

const

string
CUST_PROP_PREFIX
=

"
Prop.
"
;

bool
breturn
=

false
;

if
(shapeTarget.get_CellExistsU(CUST_PROP_PREFIX
+
strCellType, (
short
)VisExistsFlags.visExistsAnywhere)
!=

0
)



{

shapeTarget.get_CellsU(CUST_PROP_PREFIX

+
strCellType
+

"
.Value
"
).Formula
=
StringToFormulaForString(cellValue);

}



return

true
;

}


4、判断形状某个属性是否存在。
有时候在做一些操作前,需要判断某个属性是否存在,以免访问指定的Cell不存在而抛出异常。



public

static

bool
ShapeCellExist(Shape shapeTarget,
string
strCellType)



{

const

string
CUST_PROP_PREFIX
=

"
Prop.
"
;

bool
breturn
=

false
;

if
(shapeTarget.get_CellExistsU(CUST_PROP_PREFIX
+
strCellType, (
short
)VisExistsFlags.visExistsAnywhere)
!=

0
)



{

breturn

=

true
;

}




return
breturn;

}


5、取当前操作属性所在的行。
Cell的行号有时候非常重要,因此有必要提供一个函数获取对应Cell在ShapeData中的行号。



public

static

int
GetCustomPropRow(Shape shapeTarget,
string
propName)



{

const

string
CUST_PROP_PREFIX
=

"
Prop.
"
;

int
intCustomRow
=

-
1
;

if
(shapeTarget.get_CellExistsU(CUST_PROP_PREFIX
+
propName, (
short
)VisExistsFlags.visExistsAnywhere)
!=

0
)



{

intCustomRow

=
shapeTarget.get_CellsRowIndexU(CUST_PROP_PREFIX
+
propName);

}




return
intCustomRow;


6、判断Visio图纸上是否有形状图元存在。
如果图纸上没有形状图元,你进行操作的时候可能会抛出“请求被禁用”的异常,因此可以操作前先判断有设备在图纸上为妙。



public

static

bool
HasShapeInWindow(Window window)



{

bool
result
=

false
;

try




{

window.SelectAll();

result

=
(window.Selection.Count
>

0
);

window.DeselectAll();

}



catch




{ ;}



return
result;

}


7、其他的一些功能设置



//
Visio2007的形状窗口中去除搜索形状功能


VisApplication.Settings.ShowShapeSearchPane
=

false
;



Visio2003的ShowShapeSearchPane实现方式




//
屏蔽Visio2007中的动态连接的功能(默认有)


VisApplication.Settings.EnableAutoConnect
=

false
;

VisApplication.Settings.StencilBackgroundColor

=

10070188
;


8、Name和NameU属性的差别
Visio中很多属性都有一个同名+U的属性名称,一般情况下最好使用这个名称如NameU,因此这个是一个唯一的名字,有时候你会发现Name相同,但他们就是不一样,因为他们的NameU名称不一样的。

9、遇到不明白的操作或者属性,多用Visio文档的宏记录功能,然后对VBA代码进行分析和调试。

Visio的二次开发过程中,必定要处理很多Visio事件,事件基本上分为三类:Document事件、Applicaiton事件、AxDrawingControl事件。Document事件是每个文档创建或者打开都需要重新绑定一次的,但是Application事件不变,即不需要重新绑定,AxDrawingControl是ActiveX控件的事件响应。
在C#进行Visio的开发中,通过继承接口IVisEventProc,可以创建事件的侦听处理类,如下所示:


[ComVisible(
true
)]

public

sealed

class
EventSink2 : IVisEventProc



{





..


object
IVisEventProc.VisEventProc(
short
eventCode,
object
source,
int
eventId,

int
eventSequenceNumber,
object
subject,
object
moreInfo)



{



}



}


事件有很多类,有Application级别的,有Document级别的,有Page级别的,有Shape级别的,有Windows级别的,有Cell级别的..............,下面截取一部分事件代码看看



//
Document event codes



case
(
short
)Microsoft.Office.Interop.Visio.VisEventCodes.

visEvtDoc

+
(
short
)Microsoft.Office.Interop.Visio.

VisEventCodes.visEvtDel:

case
(
short
)Microsoft.Office.Interop.Visio.VisEventCodes.

visEvtCodeBefDocSave:

case
(
short
)Microsoft.Office.Interop.Visio.VisEventCodes.

visEvtCodeBefDocSaveAs:

case
(
short
)Microsoft.Office.Interop.Visio.VisEventCodes.

visEvtCodeDocDesign:


//
Page event codes



case
(
short
)Microsoft.Office.Interop.Visio.VisEventCodes.

visEvtPage

+
(
short
)Microsoft.Office.Interop.Visio.

VisEventCodes.visEvtDel:

case
(
short
)Microsoft.Office.Interop.Visio.VisEventCodes.

visEvtPage

+
visEvtAdd:

case
(
short
)Microsoft.Office.Interop.Visio.VisEventCodes.

visEvtPage

+
(
short
)Microsoft.Office.Interop.Visio.

VisEventCodes.visEvtMod:


//
Master event codes



case
(
short
)Microsoft.Office.Interop.Visio.VisEventCodes.

visEvtMaster

+
(
short
)Microsoft.Office.Interop.Visio.

VisEventCodes.visEvtDel:

case
(
short
)Microsoft.Office.Interop.Visio.VisEventCodes.

visEvtMaster

+
(
short
)Microsoft.Office.Interop.Visio.

VisEventCodes.visEvtMod:

case
(
short
)Microsoft.Office.Interop.Visio.VisEventCodes.

visEvtCodeCancelMasterDel:


//
Shape event codes



case
(
short
)Microsoft.Office.Interop.Visio.VisEventCodes.

visEvtShape

+
(
short
)Microsoft.Office.Interop.Visio.

VisEventCodes.visEvtDel:

case
(
short
)Microsoft.Office.Interop.Visio.VisEventCodes.

visEvtCodeShapeBeforeTextEdit:

case
(
short
)Microsoft.Office.Interop.Visio.VisEventCodes.

visEvtShape

+
visEvtAdd:

case
(
short
)Microsoft.Office.Interop.Visio.VisEventCodes.

visEvtShape

+
(
short
)Microsoft.Office.Interop.Visio.

VisEventCodes.visEvtMod:


//
Cell event codes



case
(
short
)Microsoft.Office.Interop.Visio.VisEventCodes.

visEvtCell

+
(
short
)Microsoft.Office.Interop.Visio.

VisEventCodes.visEvtMod:

case
(
short
)Microsoft.Office.Interop.Visio.VisEventCodes.

visEvtFormula

+
(
short
)Microsoft.Office.Interop.Visio.

VisEventCodes.visEvtMod:

还有很多很多..

将事件和我们的处理函数联系起来,还需要对事件进行侦听,即AddAdvise,下面列出一段如何侦听事件的代码供参考



const

string
sink
=

""
;

Event newEvent

=

null
;


EventList applicationEvents

=
eventApplication.EventList;

EventList documentEvents

=
eventDocument.EventList;


newEvent

=
documentEvents.AddAdvise(

(

unchecked
((
short
)VisEventCodes.visEvtAdd)
+
(
short
)VisEventCodes.visEvtShape),

(IVisEventProc)

this
, sink,
"
ShapeAdd
"
);


newEvent

=
documentEvents.AddAdvise(

(

short
)VisEventCodes.visEvtDel
+
(
short
)VisEventCodes.visEvtShape,

(IVisEventProc)

this
, sink,
"
ShapeDelete
"
);


newEvent

=
documentEvents.AddAdvise(

(

short
)VisEventCodes.visEvtMod
+
(
short
)VisEventCodes.visEvtCell,

(IVisEventProc)

this
, sink,
"
CellChanged
"
);


newEvent

=
documentEvents.AddAdvise(

(

short
)VisEventCodes.visEvtCodeShapeExitTextEdit,

(IVisEventProc)

this
, sink,
"
ShapeExitedTextEdit
"
);


newEvent

=
documentEvents.AddAdvise(

(

short
)VisEventCodes.visEvtCodeQueryCancelSelDel,

(IVisEventProc)

this
, sink,
"
QueryCancelSelectionDelete
"
);


具体的使用,最好下载Visio2007 SDK进行学习,自己编写一些例子对事件进行处理

在操作SQLServer的时候, 很多时候记不住具体的函数如何使用, 查找联机帮助还是嫌麻烦, 且有很多时候例子也不好懂, 下面对每个常用的函数用用例子说明,一目了然,你自己在数据库中执行一下,结果就知道什么回事了


--
字符串功能


--

substring


print

substring
(
'
iamagoodperson
'
,
1
,
5
)

select

substring
(
'
iamagoodperson
'
,
1
,
5
)


--
upper


select

upper
(
'
he is a good person
'
)


--
lower


select

LOWER
(
'
this is an VERY interesting job
'
)


--
ltrim


select

ltrim
(
'
i am a good person
'
)


--
rtrim


select

rtrim
(
'
heihei,i do not know why it likes this
'
)



--
replace


select

replace
(
'
iwanttoaskyou
'
,
'
ttoa
'
,
'
i love you
'
)


--
stuff


select

stuff
(
'
我的名字是朱旭杰
'
,
6
,
8
,
'
summer
'
)


--
Date/Time Fuction


--

getdate()


select

getdate
()
as

'
today
'



--
dateadd()


select

dateadd
(yy,
10
,
getdate
())


--
datediff()


select

datediff
(yy,
'
1982/5/3
'
,
getdate
())
as



--
datepart()


select

datepart
(dw,
getdate
())

select

datepart
(yy,
getdate
())

select

datepart
(mm,
getdate
())

select

datepart
(dd,
getdate
())

select

datepart
(ss,
getdate
())

select

datepart
(ms,
getdate
())

select

datepart
(dd,
'
1982/5/3
'
)

print

datepart
(dw,
'
1982/8/22
'
)


--
day(),相当于datepart(dd,时间)


select

day
(
'
1982/5/3
'
)

select

day
(
getdate
())


--
month(),相当于datepart(mm,时间)


select

month
(
getdate
())


--
year(),相当于datepart(yy,时间)


select

year
(
getdate
())


--
数学函数




--
abs()


select

abs
(
-
100.3456
)


--
sin()


select

sin
(
0.54
)


--
cos()


select

cos
(
3.14
)


--
power()


select

power
(
10
,
2
)


--
round 返回数字表达式并四舍五入为指定的长度或精度





select

round
(
100.45
,
1
)

select

round
(
123
,
45
,
-
2
)


--
floor()


select

floor
(
4.9
)

select

floor
(
-
123.99
)


--
ceiling()


select

ceiling
(
4.9
)

select

ceiling
(
-
123.99
)


--
sqrt()


select

sqrt
(
100
)


--
square


select

square
(
10
)

select

square
(
-
15
)


--
转换函数


--

cast()


select

cast
(
100.45

as

int
)

select

cast
(
1345

as

varchar
(
10
))


--
convert()


select

convert
(
int
,
100.56
)

select

convert
(
varchar
(
10
),
2345
)


--
空值函数


--

isnull()


declare

@temp_table

table


(

bookID

VARCHAR
(
10
)
primary

key
,

book_price

float

default

null
,

bookName

varchar
(
50
)

)

insert

into

@temp_table

values
(
'
1
'
,
50
,
'
c#
'
)

insert

into

@temp_table

values
(
'
2
'
,
null
,
'
c
'
)

select
bookID
AS

'
书的编号
'
,
isnull
(book_price,
0
)
as

'
书的价格
'


from

@temp_table



--
nullif(),只要参数里的两个表达式相同就返回null


select

nullif
(
'
iam
'
,
'
iam
'
)


--
coalesce返回其参数中第一个非空表达式


select

coalesce
(
null
,
null
,
'
i am a good boy
'
)