有了WorldWind学习系列一的基础,我们已经可以进行正常调试运行啦!可以先操作看看软件的功能吧,这样我们才可以知道WorldWind有哪些功能等待我们学习的。
开始我们的“WorldWind学习系列二:擒贼先擒王”分析WorldWind主窗体,从Main函数入口一步步解析学习。至少对于我来说,里面有很多知识要学的。(补充一下:无法进入WorldWind.cs窗体的设计界面,这个问题我早就发现了,但没解决,我们根据功能直接看代码吧)
1. 使用System.Version在内部,读取软件版本信息,并格式化输出。我们在外面配置软件版本,“关于”部分中版本自动更改。
获取格式化版本号
//
Establish the version number string used for user display,
//
such as the Splash and Help->About screens.
//
To change the Application.ProductVersion make the
//
changes in \WorldWind\AssemblyInfo.cs
//
For alpha/beta versions, include " alphaN" or " betaN"
//
at the end of the format string.
Version ver
=
new
System.Version(Application.ProductVersion);
Release
=
string
.Format(
"
{0}.{1}.{2}.{3}
"
, ver.Major, ver.Minor, ver.Build, ver.Revision);
2.判断该软件是否已经有个实例启动,如果有,则不启动。
判断是否已启动实例
//
If World Wind is already running, pass any commandline
//
arguments from this instance, and quit.
IntPtr handle
=
GetWWHandle();
//
此处通过获取线程指针
if
(
!
System.IntPtr.Zero.Equals(handle))
{
if
(args.Length
>
0
)
NativeMethods.SendArgs( handle,
string
.Join(
"
\n
"
,args) );
return
;
}
此处通过获取线程指针的方式,让我们来解析GetWWHandle函数。
public
static
IntPtr GetWWHandle()
{
return
NativeMethods.FindWindow(
null
,
"
NASA World Wind
"
);
}
可知,它调用了NativeMethods类的FindWindow方法,该方法实质上是引用user32.dll的非托管函数FindWindow。也即:GetWWHandle()调用了user32.dll的非托管函数FindWindow。
非托管函数调用
///
<summary>
///
API function to find window based on WindowName and class.
///
</summary>
[DllImport(
"
user32.dll
"
)]
internal
static
extern
IntPtr FindWindow (
string
lpClassName,
string
lpWindowName);
可参看我的平台调用:C# 使用非托管dll函数
注:此处判断是否已经有启动实例的方法可以借鉴。我以前是通过自己写代码判断是否存在进程的方式来确定是否有实例启动了。
判断是否已存在该程序进程
///
<summary>
///
判断是否已经存在该程序进程
///
</summary>
///
<returns></returns>
private
static
bool
IsExistProcess()
{
bool
result
=
false
;
Process[] p
=
Process.GetProcessesByName(Path.GetFileNameWithoutExtension(Application.ExecutablePath));
if
(p
!=
null
&&
p.Length
>
1
)
{
result
=
true
;
}
return
result;
}
3.判断计算机中已经存在的协议数目。主要是针对.Net FrameWork 1.1版的bug(不允许多于50个协议)。因为该软件要启用自己的新协议"worldwind://"。现在2.0以后不存在该问题啦。
// abort if 50 bindings problem present and user opts to go to the download page
if(BindingsCheck.FiftyBindingsWarning()) return;
虽然我们说该功能可以不要,但是其函数中的知识点还是值得一看的。FiftyBindingsWarning()中主要是DetermineProtocolBindings()和IsBindingsHotFixApplied() 。前一个是判断绑定协议数,后一个是判断CLR的版本号。
static
int
DetermineProtocolBindings()
{
int
errorNumber
=
0
;
const
long
sizeOfOneProtocolInfoStructure
=
628
;//此处我们可知协议信息的结构体长度是固定的为628
long
sizeOfAllProtocolInfoStructures
=
0
;
//
request all protocol info structures, but provide no space to store them -
//
this will yield the total size of the structure array in bytes
WSCEnumProtocols(IntPtr.Zero, IntPtr.Zero,
ref
sizeOfAllProtocolInfoStructures,
ref
errorNumber);
if
(errorNumber
!=
WSAENOBUFS)
return
-
1
;
//
not what we expected, unable to determine number of bindings
//
divide total size by size of one structure to get number of bindings.
return
(
int
)(sizeOfAllProtocolInfoStructures
/
sizeOfOneProtocolInfoStructure);
}
//
Determines whether the CLR version is newer than the first one that included the fix.
static
bool
IsBindingsHotFixApplied()
{
//
check if CLR version is 1.1.4322.946 or higher
return
System.Environment.Version
>=
new
Version(
"
1.1.4322.946
"
);
//System.Environment.Version用来读取系统环境的版本号
}
前一个函数DetermineProtocolBindings()同样也调用了外面的非托管代码函数。如下:
[DllImport("Ws2_32.dll")]
static extern int WSCEnumProtocols(IntPtr lpiProtocols, IntPtr lpProtocolBuffer, ref long lpdwBufferLength, ref int lpErrno);
今天先就写到这啦,我分析的太深入了,如果这样写下去要把这个系列写到100篇吧。出于应用为目的其实不用分析的太透彻啦。以后的系列中,我会多以提纲引导方式简化些内容,重点知识点我还会关注的。