银河下的约书亚树,加利福尼亚州,美国 (© Chao Zhang/Getty Images)

Welcom to 评论 - lizhenqiu blog!

    #2243

    作者:北京市
    人生遇到的每个人,出场顺序真的很重要,很多人如果换一个时间认识,就会有不同的结局。
    文章:成功的故事只能倒叙着讲  发表时间:2016-09-01, 00:31:29  
    展开↯

    #2244

    作者:广西南宁市
    discuz 3.x 核心文件class_core.php解析
    class_core.php是discuz 3.x的核心文件,几乎所有PHP脚本都有引用此文件初始化论坛运行环境。以下解析引用3.2版discuz。

    line 12-15:常量定义
    IN_DISCUZ: true //用于防止内部PHP引用文件被直接调用。 DISCUZ_ROOT: E:\\project\\discuz\\ //论坛所在的物理路径 DISCUZ_CORE_DEBUG: false //核心代码是否测试模式 DISCUZ_TABLE_EXTENDABLE: false //未知
    Run code
    Cut to clipboard


      line 17: 设置自定义异常处理功能
      处理方法位于:core::handleException静态方法。

      line 24-30:定义自动加载类函数 该方法位于:core::autoload($class)
      if(function_exists('spl_autoload_register')) { spl_autoload_register(array('core', 'autoload')); //自动加载类函数 } else { function __autoload($class) { return core::autoload($class); } }
      Run code
      Cut to clipboard

        该方法简述:引用./source/class/文件夹下的类文件。方法参数为类名称,类名称如有_下划线,则前缀为子文件夹名称,后缀为文件夹名_类名。 ./source/class/子文件夹/子文件夹名_类 例:$class = "discuz_base",则引用类文件为: ./source/class/discuz/discuz_base.php 所有引用过的文件名都存储在core::imports数组内。

        line 33:执行C::createapp()静态方法.
        C::creatapp();
        Run code
        Cut to clipboard

          该方法为最重要的方法,是初始化论坛的方法,该方法创建discuz_application类对象,使用单一工厂模式。 discuz_application类位于: ./source/class/discuz/discuz_application.php

          C::createapp()方法不直接创建discuz_application类实例,而是通过执行discuz_application::instance()静态方法间接创建。

          discuz_application::instance()静态方法new一个实例,构造函数初始化了论坛环境。(详情请看discuz_application.php解析)。

          另外,该文件结尾用简写重定义了类名: line 208-209: C重定义core类名; DB重定义discuz_database类名。

          discuz_application.php解析:

          该类位于./source/class/discuz/discuz_application.php,被core对象间接实例化。该类有两个最重要的方法,一个是构造函数,一个是init方法。

          构造函数解析:

          line 57-62:构造函数对论坛参数的初始化,分别用4个方法实施:
          public function __construct() { $this->_init_env(); $this->_init_config(); $this->_init_input(); $this->_init_output(); }
          Run code
          Cut to clipboard

            (1)$this->_init_env():

            初始化环境变量 line 87-93:常量定义 MAGIC_QUOTES_GPC:true(5.4版以上为false) ICONV_ENABLE:true MB_ENABLE:true EXT_OBGZIP:true TIMESTAMP:当前时间截 并设当前时区为格林尼治时区

            line 94: 引用核心函数库:./cource/function/function_core.php。 引用成功并定义常量:DISCUZ_CORE_FUNCTION:true

            line 99-104:设置ini:memory_limit:128M line 106:检测爬虫:IS_ROBOT:false

            line 108-112:清除不必要的全局变量。
            foreach ($GLOBALS as $key => $value) { if (!isset($this->superglobal[$key])) { $GLOBALS[$key] = null; unset($GLOBALS[$key]); } }
            Run code
            Cut to clipboard

              line 114-203:定义全局变量:$_G,对象本身的var属性也保存一份其引用。

              (2)$this->_init_config() 初始化环境:

              line 289: 引用./conifg/config_global.php配置参数文件

              line 299:检测并设定$_config['security']['authkey']的值。
              if(empty($_config['security']['authkey'])) { $_config['security']['authkey'] = md5($_config['cookie']['cookiepre'].$_config['db'][1]['dbname']); }
              Run code
              Cut to clipboard

                line 303-315: 检测配置参数是否存在debug配置参数,如果没有则 定义常量DISCUZ_DEBUG:false,否则设为true。

                line 316-317:常量定义:STATICURL:static/,则存入var属性。

                line 319-320: 将所有$_config数组参数,存入:$this->config和$this->var['config']。

                line 322: $_config['cookie']['cookiepath']参数值前加/斜线。

                line 325: 重定义$this->var['config']['cookie']['cookiepre']值。

                (3)$this->_init_input()初始化输入

                line 236-240: 如果魔术引号功能开启,则去除$_GET,$_POST,$_COOKIE反斜线;

                line 243-246: 根据$this->config['cookie']['cookiepre']值,将带有此前缀的cookie都存入$this->var['cookie'],key不带前缀。

                line 251-253: POST值合并入GET内; GET值存入$this->var['gp_'.键名]中。

                line 255-257:$_GET['page']url编码。

                line 259-261: 处理掉无效的$_GET['handlekey'],该值只能含有字母数字和下划线。

                line 264-268: 将$_GET值存入$this->var['gp_'.键名]中,所有值做addslashes引用(即引号和\作\引用)

                line 270-273: 初始化$_GET['mod'],存入$this->var['mod'],mod参数为执行的模块名; 初始化$_GET['inajax'],存入$this->var['inajax'],该值判断请求是否ajax请求; 初始化$_GET['page'],存入$this->var['page']; 初始化$this->var['cookie']['sid'],存入$this->var['sid'],一般情况为空值。

                line 275-278: 如果$this->var['cookie']['saltkey']不存在,则生成该值,并存入cookie,有效期1个月。

                line 279: 根据$this->var['cookie']['saltkey']和$this->var['config']['security']['authkey'],生成$this->var['authkey']值。

                (4)$this->_init_output() 初始化输出:

                line 337-342:判断网页是否启用gzip压缩,设定$this->config['output']['gzip']布尔值;并决定设定$_G['gzipcompress']的布尔值。
                if(!empty($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') === false) { $this->config['output']['gzip'] = false; } $allowgzip = $this->config['output']['gzip'] && empty($this->var['inajax']) && $this->var['mod'] != 'attachment' && EXT_OBGZIP; setglobal('gzipcompress', $allowgzip);
                Run code
                Cut to clipboard

                  line 344-346: 开启输出缓存。
                  if(!ob_start($allowgzip ? 'ob_gzhandler' : null)) { ob_start(); }
                  Run code
                  Cut to clipboard

                    line 348-353: 设定$_G['charset']和常量CHARSET的字符编码值,取值于$this->config['output']['charset']。 将字符编码输出于网页头部。
                    setglobal('charset', $this->config['output']['charset']); define('CHARSET', $this->config['output']['charset']); //默认输出字符编码标识 if($this->config['output']['forceheader']) { @header('Content-Type: text/html; charset='.CHARSET); }
                    Run code
                    Cut to clipboard

                      discuz_application::init()方法解析:

                      该方法也主要初始化论坛环境,准备好相关的数据库连接类、设置、用户、会话等等相关参数。

                      (1)$this->init_db():
                      private function _init_db() { if($this->init_db) { $driver = function_exists('mysql_connect') ? 'db_driver_mysql' : 'db_driver_mysqli'; if(getglobal('config/db/slave')) { $driver = function_exists('mysql_connect') ? 'db_driver_mysql_slave' : 'db_driver_mysqli_slave'; } DB::init($driver, $this->config['db']); } }
                      Run code
                      Cut to clipboard

                        DB类位于./source/class/discuz_database.php,实际上就是discuz_database类。DB::init()根据参数配置实例化mysql连接类。

                        (2)
                        文章:【转】从PHP的模板引擎看Discuz!模板机制  发表时间:2016-08-31, 18:07:48  
                        展开↯

                        #2245

                        作者:广西南宁市
                        开发自己的模板引擎
                        自定义模板引擎类
                        MyTpl.class.php
                        <?php class MyTpl { private $tpl_vars = array(); //分配 public function assign($key,$value){ $this->tpl_vars[$key] = $value; } public function display($tpl){ $contents = file_get_contents($tpl); foreach ($this->tpl_vars as $k => $v){ //替换 将{$name} 替换成真实的数据 $contents = str_replace('{$'."$k".'}',"$v", $contents); $compile = './templates_c/'.md5('show.html') . '.php'; file_put_contents($compile, $contents); require $compile; } } } $tpl = new MyTpl; $tpl-> assign('name','张四'); $tpl-> display('./template/show.html');
                        Run code
                        Cut to clipboard

                          自定义视图
                          template/show.html
                          <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> {$name} </body> </html>
                          Run code
                          Cut to clipboard
                            文章:常用html、demo代码  发表时间:2016-08-31, 17:38:37  
                            展开↯

                            #2246

                            作者:广西南宁市
                            我讲个笑话,你可别哭啊
                            文章:我看过一个故事  发表时间:2016-08-31, 17:28:05  
                            展开↯

                            #2247

                            作者:广西南宁市
                            PHP常用函数总结 一般来说,字符串、数组、数据库类的函数是相对来使用比较多的类别。 //===============================时间日期============================ //y返回年最后两位,Y年四位数,m月份数字,M月份英文。d月份几号数字,D星期几英文 $date=date("Y-m-d"); //include,include_once.require,require_once //require("file.php") 在PHP程序执行前就会先读入require所指定引进的文件,如出现错误是致命的。 //include("file.php") 可以放在PHP程序的任何位置,PHP程序执行到时才读入include指定引入的文件,如出现错误会提示 //===============================输出打印=============================== //sprintf("%d","3.2") ;//只格式化,返回格式化后的字符串,不输出。 //printf("%d","3.2") ;//即格式化,又输出 //print("3.2") ;//只输出 //echo "nihao","aa";//可以输出多个字符串 //print_r(array("a","b","c"));//将数组的键值与元素依次显示 //===============================常用字符串函数=============================== //获取字符串长度,有多少个字符,空格也算 $str=" sdaf sd "; $len=strlen($str); //用第一个参数里的字符串,把后面数组里的每个元素连接起来,返回一个字符串。 $str=implode("-",array("a","b","c")); //字符串分割方法,返回一个数组,用第一个参数里的字符分割后面的字符串,指定字符的前后和之间都截取,如果指定字符在开头或结尾则返回的数组开头或结尾的元素为空字符串 //没有分割到字符串就返回给数组对应元素一个空值。最后一个限制返回数组长度,可不限制,则一直分割下去。 $array=explode("a","asddad addsadassd dasdadfsdfasdaaa",4); //print_r($array); //剔除字符串左边开头的空格,并返回 //如有第二个参数则是剔除左边开头的空格换成剔除第二个参数里的字符串 $str=ltrim("a asd ","a"); //剔除字符串右边开头的空格 $str=rtrim(" asd "); //把第一个字符串两边以第二个参数开头的字符串剔除。如没有第二个参数,默认剔除掉字符串两边开头的空格 $str=trim(" sdsdfas ","a"); //从字符串第一个参数里的指定位置开始取多长(多少个)字符,字符串中第一个字符位置从0算。 //如果第二个参数为负则从字符串结尾倒数第几个开始取多长的字符串。结尾最后一个字符算-1,截取方向总是从左到右 $str=substr("abcdefgh",0,4); //将第三个参数的第一个参数字符串用参数二字符串替换 $str=str_replace("a","","abcabcAbca"); //与str_replace用法同,只是不区分大小写 //$str=str_ireplace("a"," ","abcabcAbca"); //返回括号里字符串的字符全部大写的字符串 $str=strtoupper("sdaf"); //将括号里第一个字符串变成大写后返回 $str=ucfirst("asdf"); //用echo等将括号里字符串打印在网页上时原汁原味打印出括号里的字符串,包括标签字符 $str=htmlentities("<br/>"); //返回第二个参数字符串在第一个字符串里出现的次数 $int=substr_count("abcdeabcdeablkabd","ab"); //返回第二个字符串在第一个字符串第一次出现的位置,第一个字符位置算0 $int=strpos("asagaab","ab"); //返回第二个字符串在第一个字符串最后一次出现的位置,第一个字符位置算0 $int=strrpos("asagaabadfab","ab"); //截取返回参数一中从左至右第一个出现的参数二到参数一最后一个字符的字符串 $str=strstr("sdafsdgaababdsfgs","ab"); //截取返回参数一中从左至右最后一个出现的参数二到参数一最后一个字符的字符串 $str=strrchr("sdafsdgaababdsfgs","ab"); //将参数二中每一个字符在参数一中相同字符前加"\" $str=addcslashes("abcdefghijklmn","akd"); //将参数一的字符串填充到参数二指定的长度(单字符个数),参数三为指定填充的字符串,不写默认空格 //参数四填充位置,0在参数一左侧开头填充,1右侧开头,2两边开头同时。不写默认在右侧开头填充 $str=str_pad("abcdefgh",10,"at",0); //依次比较两字符串对应字符阿斯克码值,第一对不一样的,如果参数一里大于参数二里的返回1,反之返回-1,两字符串完全一样返回0 $int1=strcmp("b","a"); //返回第一个参数格式化后的数字格式,第二个参数为保留几个小数,参数三为将小数点换成参数三,参数四为整数部分每三位用什么字符分割 //后面三个参数都不写,则默认去掉小数部分,整数每隔三位用逗号,分割。参数三,参数四必须同时存在 $str=number_format(1231233.1415,2,"d","a"); //===============================常用数组方法=============================== $arr=array("k0"=>"a","k1"=>"b","k2"=>"c"); //返回数组元素个数 $int=count($arr); //判断第二参数的数组元素中是否有第一个参数元素 $bool=in_array("b",$arr); //返回括号中数组所有键值组成的新数组原数组不改变 $array=array_keys($arr); //判断第二个参数的数组中是否有第一个参数的键值,返回真假 $bool=array_key_exists("k1",$arr); //返回原数组中所有元素值组成的新数组,键值从0开始自增,原数组不变 $array=array_values($arr); //返回当前数组指针指向的键值 $key=key($arr); //返回当前数组指针指向的元素值 $value=current($arr); //返回当前数组指针指向元素的键值及元素值组成的数组,再将指针推向下一位,最后指针指向的是一个空元素返回空 //返回的数组中有四个固定键值对应的元素值分别是返回元素的键值及元素值,其中0,'key'键值都对应返回元素键值,1,'value'键值都对应返回的元素值 $array=each($arr); //先将数组指针推向下一位,再返回指针移动后指向的元素值 $value=next($arr); //将数组指针推向上一位,再返回指针移动后指向的元素值 $value=prev($arr); //让数组指针重置指向第一个元素并返回元素值 $value=reset($arr); //将数组指针指向最后一位元素,并返回最后一位元素值 $value=end($arr); //将第一个参数以后的参数作为元素追加入第一个参数数组的末尾,索引从最小的没用过的数值开始计,返回之后的数组长度 $int=array_push($arr,"d","dfsd"); //将第一个参数数组后面所有参数作为元素添加到第一个参数数组开头处,键值以0从第一个元素处重新累加,原非数值的键值保持不变,原元素排序位置不变,返回之后的数组长度 $int=array_unshift($arr,"t1","t2"); //返回从数组尾部提取最后一个元素值,并把最后一个元素从原数组中剔除 $value=array_pop($arr); //array_pop相反,提取返回数组头一个元素值,并把头一个元素从原数组中剔除 $value=array_shift($arr); //让第一个参数数组达到第二个参数数值长度,将第三个参数作为元素添加到第一个参数数组的末尾,索引从最小没用过数值开始计并返回,原数组不改变 $array1=array_pad($arr,10,"t10"); //返回一个将原数组中多余重复元素剔除掉的新数组,原数组不改变 $array=array_unique($array1); //将原数组键值打破重新以元素值的阿斯克码值从小到大排序,索引从数字0开始重计 $int=sort($array); //和sort相反,以元素值阿斯柯码值大小降序重新排序,索引从0重新计 $int=rsort($array); //返回将第一个参数数组中每一个元素值依次作为键值付给参数二数组的数组,两数组长度必须一致,原数组不改变 $array=array_combine(array("a","b","c","d","e"),$arr); //将两个数组合并并返回原数组不变 $array=array_merge($arr,array("a","b","c")); //在第一个参数数组中从第二个参数数值位置开始截取到第三个参数数值长度的数组键值+元素并返回,数组第一个元素位置从0计 $array=array_slice($arr,2,1); //截取功能和array_slice()一样,只是将截取部分在原数组中剔除 $array=array_splice($arr,2,1); //将第一个参数作为第一个元素,每次自增参数三的值,自增后再作为一个元素存在数组中,直到值达到参数二的值存到数组中为止并返回这个数组 //参数一,参数二可以是数字,可以是单个字符,单字符就按阿斯柯码值算,第三个参数不写默认每次自增1 $array=range(3,9,2); //将原数组元素与对应键值的对应关系重新随机排列返回真假 $bool=shuffle($arr); //计算数组中所有数值型元素值的和 $int=array_sum(array("a",2,"cssf")); //把一个数组分割为新的数组块,新数组每个元素都是一个数组,新数组每个元素内有几个元素由参数二决定 //第三个参数决定元素的键值是否保留原键值可不写,true为保留,默认false不保留 $array=array_chunk(array("a"=>"a","b","c","d","e","f","g","h"),2,true);
                            Run code
                            Cut to clipboard
                              文章:常用html、demo代码  发表时间:2016-08-31, 16:47:52  
                              展开↯

                              #2248

                              作者:广西南宁市
                              php图片验证码为什么必须加上ob_clean();才能正常显示。
                              ob_clean
                              Run code
                              Cut to clipboard
                                这个函数的作用就是用来丢弃输出缓冲区中的内容,如果你的网站有许多生成的图片类文件,那么想要访问正确,就要经常清除缓冲区。
                                If you work on an extremely large project with a lot of source and required files, like myself, you will be well-advised to always clear the output buffer prior to creating an image in php.
                                文章:YOURPHP验证码不显示问题解决方法清理图片缓存  发表时间:2016-08-31, 16:39:34  
                                展开↯

                                #2249

                                作者:广西南宁市
                                求救啊,郁闷那?我想用API使一个窗口在最前台并取得焦点,怎么不行啊?
                                我新建一个文件名为 &quot;New &quot;的文本文件,在后台或者最小化时,用如下函数到前台怎么没用啊?
                                Option Explicit
                                Private Declare Function SwitchToThisWindow Lib &quot;user32.dll &quot; (ByVal hwnd As Long, ByVal bRestore As Boolean)
                                Private Declare Function FindWindow Lib &quot;user32 &quot; Alias &quot;FindWindowA &quot; (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
                                Private Declare Function GetForegroundWindow Lib &quot;user32 &quot; () As Long
                                Private Declare Function SetFocusAPI& Lib &quot;user32 &quot; Alias &quot;SetFocus &quot; (ByVal hwnd As Long)
                                Private Declare Function BringWindowToTop Lib &quot;user32 &quot; (ByVal hwnd As Long) As Long
                                Private Declare Function SetActiveWindow Lib &quot;user32 &quot; (ByVal hwnd As Long) As Long
                                Private Declare Sub Sleep Lib &quot;kernel32 &quot; (ByVal dwMilliseconds As Long)
                                Private Declare Function SetForegroundWindow Lib &quot;user32 &quot; (ByVal hwnd As Long) As Long
                                Private Const EM_SETPASSWORDCHAR = &HCC
                                Private Const HWND_TOPMOST& = -1
                                Private Const SWP_NOSIZE& = &H1
                                Private Const SWP_NOMOVE& = &H2
                                Private Declare Function SetWindowPos Lib &quot;user32 &quot; (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
                                Private Sub Command1_Click()
                                Dim hdl As Long
                                Dim b
                                hdl = FindWindow( &quot;Notepad &quot;, &quot;New &quot;) &#39;vbNullString #32770
                                &#39;SetWindowPos hdl, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE
                                &#39;b = SwitchToThisWindow(hdl, True)
                                &#39;SetFocusAPI (hdl)
                                &#39;SetActiveWindow (hdl)
                                &#39;AppActivate &quot;New &quot;
                                &#39; BringWindowToTop (hdl)
                                SetForegroundWindow (hdl)
                                End Sub
                                以上函数我都试过了,为什么窗口就是不到前台呢?

                                ------解决方案--------------------
                                用showwindow试试
                                ------解决方案--------------------
                                SetForegroundWindow是可以的
                                问题是你的FindWindow可能没找到hwnd,debug看看hdl可能是0吧?
                                你是英文版系统吗,英文版Notepad标题好像也不是New呀?
                                换成这样试试
                                hdl = FindWindow( &quot;Notepad &quot;, vbNullString)
                                注意前提:1、Notepad要已打开;2、Notepad不是最小化状态,否则请用showwindow

                                Win32

                                第一课∶认识API

                                一、什么是API

                                首先,有必要向大家讲一讲,什么是API。所谓API本来是为C和C++程序员写的。API

                                说来说去,就是一种函数,他们包含在一个附加名为DLL的动态连接库文件中。用标准的定义来讲,API就是Windows的32位应用程序编程接口,是一系列很复杂的函数,消息和结构,它使编程人员可以用不同类型的编程语言编制出的运行在Windows95和Windows NT

                                操作系统上的应用程序。可以说,如果你曾经学过VC,那么API对你来说不是什么问题。但是如果你没有学过VC,或者你对Windows95的结构体系不熟悉,那么可以说,学习API

                                将是一件很辛苦的事情。

                                如果你打开WINDOWS的SYSTEM文件夹,你可以发现其中有很多附加名为DLL的文件。一个DLL中包含的API函数并不只是一个,数十个,甚至是数百个。我们能都掌握它嘛回答是否定的∶不可能掌握。但实际上,我们真的没必要都掌握,只要重点掌握Windos系统本身自带的API函数就可以了。但,在其中还应当抛开掉同VB本身自有的函数重复的函数。如,VB的etAttr命令可以获得文件属性,SetAttr可以设置文件属性。对API来讲也有对应的函数GetFileAttributes和SetFileAttributes,性能都差不多。如此地一算,剩下来的也就5、600

                                个。是的,也不少。但,我可以敢跟你说,只要你熟悉地掌握100个,那么你的编程水平比现在高出至少要两倍。尽管人们说VB和WINDOWS具有密切的关系,但我认为,API更接近WINDOWS。如果你学会了API,首要的收获便是对WINDOWS体系结构的认识。这个收获是来自不易的。

                                如果你不依靠API会怎么样我可以跟你说,绝大多是高级编程书本(当然这不是书的名程叫高级而高级的,而是在一开始的《本书内容》中指明《本书的阅读对象是具有一定VB

                                基础的读者》的那些书),首先提的问题一般大都是从API开始。因此可以说,你不学API,你大概将停留在初级水平,无法往上攀登。唯一的途径也许就是向别人求救∶我快死了,快来救救我呀,这个怎么办,那个怎么办烦不烦呢当然,现在网上好人太多(包括我在内,嘻嘻),但,你应当明白,通过此途径,你的手中出不了好的作品。这是因为缺乏这些知识你的脑子里根本行不成一种总体的设计构思。

                                二、API文本游览器。

                                很多API函数都是很长很长的。想看什么样子吗如下就是作为例子的API DdeClientTransaction函数∶

                                Declare Function DdeClientTransaction Lib "user32" (pData As Byte,ByVal cbData As Long,ByVal hConv As Long,ByVal hszItem As Long,ByVal wFmt As Long,ByVal wType As Long,ByVal dwTimeout As Long,pdwResult As Long) As Long

                                哇!这么长如果你从来没有接触过API,我想你肯定被吓住了。你也许考虑,该不该继续学下去。不过不要担心,幸运的是Microsoft的设计家们为我们提供了有用的工具,这便是API

                                文本查看器。

                                通过API文本查看器,我们可以方便地查找程序所需要的函数声明、结构类型和常数,然后将它复制到剪贴板,最后再粘贴到VB程序的代码段中。在大多数情况下,只要我们确定了程序所需要的函数、结构和常数这三个方面后,就可以通过对API文本游览器的以上操作将他们加入到程序段中,从而程序中可以使用这些函数了。这些是学习API最基本的常识问题,它远远占不到API的庞大的体系内容。今后我们把精力浪费(这绝不是浪费)在哪里呢那就是∶

                                什么时候使用什么函数,什么时候使用什么结构类型,什么时候使用什么常数。

                                三、API函数声明。

                                让我们回想一下。在VB中,如何声明函数呢我想,如果你正在看此文,那么你绝对能够回答得出这个问题。以下便是你应该很熟悉的函数声明∶

                                Function SetFocus (ByVal hwnd As Long) As Long

                                即,这行代码定义了名为SetFocus的函数,此函数具有一个Long型数据类型的参数,并按值传递(ByVal),函数执行后将返回一个Long型数据。

                                API函数的声明也很类似,如,API中的SetFocus 函数是这样写的∶

                                Declare Function SetFocus Lib "user32" Alias "SetFocus" (ByVal hwnd As Long) As Long

                                有点复杂了一些。是的,是复杂了点。但我可以告诉你,除了这些多出来的部分,其他部分还是和你以前学到的东西是一样的。函数在程序中的调用也是一样。如:Dim dl As Long

                                dl&=SetFoucs(Form1.Hwnd)

                                但,一点是清楚的。它不象你自己写的程序那样能够看到里面的运行机理,也不像VB

                                自带的函数那样,能够从VB的联机帮助中查到其用法。唯一的方法就是去学、查VB以外的资料。

                                Declare 语句用于在模块级别中声明对动态链接库 (DLL) 中外部过程的引用。对此,你只要记住任何API函数声明都必须写这个语句就可以了。

                                Iib 指明包含所声明过程或函数的动态链接库或代码资源。也就是说,它说明的是,函数或过程从何而来的问题。

                                如在上例中,SetFocus Lib "user32"说明 函数 SetFocus 来自 user32.dll文件。主要的dll动态连接库文件有∶

                                user32.dllWindows管理。生成和管理应用程序的用户接口。

                                GDI32.dll图形设备接口。产生Windows设备的图形输出

                                Kernel32.dll系统服务。访问操作系统的计算机资源。

                                注意,当DLL文件不在Windows或System文件夹中的时候,必须在函数中说明其出处(路径)。如,SetFocus Lib "c:Mydlluser32"函数声明中的Alias 是可选的。表示将被调用的过程在动态链接库 (DLL) 中还有另外的名称(别名)。如,Alias "SetFocus",说明SetFocus函数在User32.dll中的另外一个名称是,SetFocus。怎么两个名都一样呢当然,也可以是不同的。在很多情况下,Alias说明的函数名,即别名最后一个字符经常是字符A,如SetWindowsText函数的另一个名称是

                                SetWindowsTextA,表示为Alias "SetWindowsTextA"。这个A只不过是设计家们的习惯的命名约定,表示函数属于ANSI版本。

                                那么,别名究竟有什么用途呢从理论上讲,别名提供了用另一个名子调用API的函数方法。如果你指明了别名,那么 尽管我们按Declare语句后面的函数来调用该函数,但在函数的实际调用上是以别名作为首要选择的。如,以下两个函数(Function,ABCD)声明都是有效的,他们调用的是同一个 SetFocus函数∶

                                Declare Function SetFocus Lib "user32" "SetFocus" (ByVal hwnd As Long) As Long

                                Declare ABCD SetFocus Lib "user32" Alias "SetFocus" (ByVal hwnd As Long) As Long

                                需要注意的是,选用Alias的时候,应注意别名的大小写;如果不选用Alias 时的时候,函数名必须注意大小写,而且不能改动。当然,在很多情况下,由于函数声明是直接从API

                                文本游览器中拷贝过来的,所以这种错误的发生机会是很少的,但您有必要知道这一点。

                                最后提醒你一句,API声明(包括结构、常数)必须放在窗体或模块的"通用(General Declarations)段。

                                (杭州元帅注:在窗体里的API声明必须 Private Declare Function ......)

                                四、数据类型与"类型安全"

                                API函数中使用的数据类型基本上和VB中的一样。但作为WIN32的API函数中,不存在Integer

                                数据类型。另外一点是在API函数中看不到Boolean数据类型。 Variant数据类型在API函数中是以Any的形式出现,如Data As Any。尽管其含义是允许任意参数类型作为一个该API函数的参数传递,但这样做存在一定的缺点。其原因是,这将会使得对目标参数的所有类型检查都会被关闭。这自然会给各种类型的参数调用带来了产生错误的机会。

                                为了强制执行严格的类型检查,并避免上面提到的问题,一个办法是在函数里使用上面提到到Alias技术。如对API函数 GetDIBits 可进行另外一种声明方法。如下∶

                                GetDIBits函数的原型∶

                                Public Declare Function GetDIBits Lib "gdi32" Alias "GetDIBits" (ByVal aHDC As Long,ByVal hBitmap As Long,ByVal nStartScan As Long,ByVal nNumScans As Long,lpBits As Any,lpBI As BITMAPINFO,ByVal wUsage As Long) As Long

                                GetDIBits函数的改型∶

                                Public Declare Function GetDIBitsLong Lib "gdi32" Alias "GetDIBits" (ByVal aHDC As Long,ByVal hBitmap As Long,ByVal nStartScan As Long,ByVal nNumScans As Long,lpBits As Long,lpBI As BITMAPINFO,ByVal wUsage As Long) As Long

                                通过本课程前面所学到的知识,我们已经可以得知原型 GetDIBits函数也好,改型 GetDIBitsLong函数也好,实际将调用的都是Alias所指定的 GetDIBits原函数。但你应当看到,两者的区别在于,我们在改型的函数中强制指定lpBits参数为Long形。这样就会使得函数调用中发生的错误机率减少到了最小。这种方法叫做"安全类型"声明。

                                API函数中经常看到的数据类型有∶Long,String,Byte,Any....(也就这些吧。)

                                五、常数

                                对于API常数来讲,没有什么太特别的学问。请看VB中的以下代码∶

                                Msg=MsgBox("您好",vbOKCancel)

                                我们知道,vbOKCancel这个常数的值等于1。对上面的代码我们完全可以这样写,而不会影响代码的功能∶

                                Msg=MsgBox("您好",1)

                                但你大概不太愿意选择后一种,因为这会使得看懂代码费劲起来。这种方法也被API采取了。只是API常数必须在事情之前做好初始化声明VB本身是看不懂的。其内容仍然来自与API

                                文本游览器。具体形式如下等等∶

                                Public Const ABM_ACTIVATE=&H6

                                Public Const RIGHT_CTRL_PRESSED=&H4

                                Public Const RPC_E_SERVER_DIED=&H

                                Private Const RPC_S_CALL_FAILED_DNE=1727&

                                在常数的初始化中,有些程序使用Global,如Global Const ABM_ACTIVATE=&H6,但我认为Public完全可以代替它。过去我也用过Global,但现在不大用了。一会儿用这个,一会儿用那个,各程序之间不能保持一致性了,起码看起来别扭。

                                六、结构

                                结构是C和C++语言中的说法。在VB中一般称为自定义数据类型。想必很多朋友都已经认识它。在API领域里,我更喜欢把它叫做结构,因为API各种结构类型根本不是我定义(自定义)的。

                                在VB中,API结构同样由TYPE.......END TYPE语句来定义。如,在API中,点(Point)结构的定义方法如下:Public Type POINTAPIXAs Long '点在X坐标(横坐标)上的坐标值YAs Long '点在Y坐标(纵坐标)上的坐标值

                                End Type

                                又如,API中矩形(Rect)结构的定义如下∶

                                Public Type RECT

                                Left As Long '矩形左上角的X坐标

                                Top As Long '矩形左上角的Y坐标

                                Right As Long '矩形右下角的X坐标

                                Bottom As Long '矩形右下角的Y坐标

                                End Type

                                这些内容同样可以从API文本游览器中拷贝过来。这些结构中的变量名可随意改动,而不会影响结构本身。也就是说,这些成员变量都是虚拟的。如,POINTAPI结构可改为如下∶

                                Public Type POINTAPI

                                MyX As Long '点在X坐标(横坐标)上的坐标值

                                MyY As Long '点在Y坐标(纵坐标)上的坐标值

                                End Type

                                不过,一般来讲,是没有这种必要的。结构本身是一种数据类型,因此,使用时必须声明具体变量为该结构型,才能在程序中真正使用到该结构。结构的声明方法和其他数据的声明方法一样,如,以下语句把变MyPoint声明为POINTAPI结构类型∶

                                MyPoint As POINTAPI

                                引用结构中的成员变量也十分简单,在结构名后面加上一个".",然后紧接着写要引用的成员变量即可。这很象VB中的引用一个对象的某个属性。如,假如我们把上面已经声明的MyPoint结构中的X变量的值赋给变量Temp&

                                则代码如下∶

                                Temp&=MyPoint.X

                                但,特别注意的是,你千万不要认为上例中的MyPoint是一个值。它不是值,而是地址(指针)。值和地址是完全不同的概念。结构要求按引用传递给WINDOWS函数,即所有API

                                函数中,结构都是按ByRef传递的(在Declare语句 中ByRef是默认型)。对于结构的传递,你不要试图采用ByVal,你将一无所获。由于结构名实际上就是指向这个结构的指针(这个结构的首地址),所以,你也就传送特定的结构名就可以了(参见小结,我用红色字体来突出了这种传递方式)。

                                由于结构传送的是指针,所以函数将直接对结构进行读写操作。这种特性很适合于把函数执行的结果装载在结构之中。

                                七、小结

                                以下的程序是为了总结本课中学到的内容而给出的。启动VB,新建一个项目,添加一个命令按钮,并把下面的代码拷贝到代码段中,运行它。

                                Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long

                                Private Type POINTAPI '定义点(Point)结构XAs Long '点在X坐标(横坐标)上的坐标值YAs Long '点在Y坐标(纵坐标)上的坐标值

                                End Type

                                Sub PrintCursorPos()Dim dl AS Long

                                Dim MyPoint As POINTAPI

                                dl&= GetCursorPos(MyPoint) '调用函数,获取屏幕鼠标坐标

                                Debug.Print "X="&Str(MyPoint.X)&" and"& "Y="&Str(MyPoint.Y)

                                End Sub

                                Private Sub Command1_Click()

                                PrintCursorPos

                                End Sub

                                输出结果为(每次运行都可能得到不同的结果,这得由函数调用时鼠标指针在屏幕中所处的位置而决定)∶

                                X=240and Y=151程序中,GetCursorPos函数用来获取鼠标指针在屏幕上的位置。

                                以上例子中,你可以发现,以参数传递的MyPpint结构的内容在函数调用后发生了实质性变化。这是由于结构是按ByRef传递的原因。

                                第二课∶句柄、矩形和画点函数

                                一、句柄

                                今天开始,我向大家讲有关API的是实质性内容。我们就从"句柄"开始。

                                只要你来到了API的世界,经常碰到的问题之一就是句柄。那么究竟什么是句柄呢

                                如果你从来都没有听说过"句柄"这个词,可能首先觉得句柄当中有很多内容。其实不然,所谓句柄实际上是一个数据,是一个Long (整长型)的数据。在API中,它经常是以一个参数的形式传递给各种API函数。如:Public Declare Function GetWindow& Lib "user32" (ByVal hwnd As Long,ByVal wCmd As Long)

                                其中,hwnd就是句柄。在VB里,句柄是一种属性,您打开VB中的对象游览器看一看Form

                                窗体或者PictureBox控件等究竟有没有hwnd属性。是有的。VB中的解释是这样的∶

                                Microsoft Windows 运行环境,通过给应用程序中的每个窗体和控件分配一个句柄(或 hWnd)来标识它们。hWnd 属性用于Windows API调用。许多 Windows 运行环境函数需要活动窗口的 hWnd 作为参数。

                                如果想更透彻一点地认识句柄,我可以告诉大家,句柄是一种指向指针的指针。我们知道,所谓指针是一种内存地址。应用程序启动后,组成这个程序的各对象是住留在内的。如果简单地理解,似乎我们只要获知这个内存的首地址,那么就可以随时用这个地址访问对象。但是,如果您真的这样认为,那么您就大错特错了。我们知道,Windows是一个以虚拟内存为基础的操作系统。在这种系统环境下,Windows内存管理器经常在内存中来回移动对象,依此来满足各种应用程序的内存需要。对象被移动意味着它的地址变化了。如果地址总是如此变化,我们该到哪里去找该对象呢

                                为了解决这个问题,Windows操作系统为各应用程序腾出一些内存储地址,用来专门登记各应用对象在内存中的地址变化,而这个地址(存储单元的位置)本身是不变的。Windows

                                内存管理器在移动对象在内存中的位置后,把对象新的地址告知这个句柄地址来保存。这样我们只需记住这个句柄地址就可以间接地知道对象具体在内存中的哪个位置。这个地址是在对象装载(Load)时由系统分配给的,当系统卸载时(Unload)又释放给系统。

                                句柄地址(稳定)→记载着对象在内存中的地址────→对象在内存中的地址(不稳定)→

                                实际对象

                                但是,必须注意的是程序每次从新启动,系统不能保证分配给这个程序的句柄还是原来的那个句柄,而且绝大多数情况的确不一样的。假如我们把进入电影院看电影看成是一个应用程序的启动运行,那么系统给应用程序分配的句柄总是不一样,这和每次电影院售给我们的门票总是不同的一个座位是一样的道理。

                                在VB中获得一个对象的句柄十分简单,如要获取Form1窗体的句柄,就可以这样写∶

                                Form1.Hwnd

                                对象的句柄还可以通过API函数来获得,如∶

                                GetActiveWindow返回位于最顶部的具有输入焦点的窗口句柄

                                GetFocus获得当前线程里补获鼠标输入的窗口句柄

                                GetForegroundWindow从位于前台的线程里返回活动窗口的句柄

                                GetCursor取得当前指针的句柄

                                GetDesktopWindow获取整个桌面的句柄

                                GetWindow获得一个窗口的句柄,该窗口与某源窗口有特定的关系

                                《以上函数说明均可在WinAPI.hlp文件中找到。》

                                本教程提供了演示例程──play1.vbp,正是为了说明这些函数的具体用法的。

                                程序运行后,用鼠标做一些任何你想做的事情,并观察各项目数据的变化。

                                通过本程序,注意观察以下几点∶

                                1,线程内与线程外。(VB不支持多线程)。其他应用程序对此程序来说都是线程外。

                                2,在windows95操作系统下,各个窗体(包括一些控件,如文本框,图片框等,MICROSORT对它们均统称为窗体)拥有各自的鼠标指针。这和win16下各应用程序使用同样一个指针是截然不同的。

                                3,每次从新启动,各窗体的句柄都有所变化。Text5 的装载和卸载过程中,句柄始终是在变化着的。这说明了上面提的影院售门票中存在的现象是真实的。

                                获得对象句柄的函数还有很多,以后碰到它们时再介绍给大家。

                                二、驾驶句柄

                                只要弄清了什么是句柄,尤其是窗口句柄,那么操纵一个对象就变得自如一多了。比如,可以通过GetWindowText API函数,我们可以轻松地获得某特定窗口的标题。

                                GetWindowText 在VB中的声明如下:Private Declare Function GetWindowText& Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long,ByVal lpString As String,ByVal cch As Long)

                                于是,我们可以通过以下一段代码来获得Form1的窗口标题。(新建一个项目,添加一个命令按钮,把以下的代码拷贝过去,还有上面的函数声明。你就可以运行了)

                                Private Sub Command1_Click()

                                Dim dl As Long

                                Dim FormCaption As String

                                FormCaption=Space(128)

                                dl&=GetWindowText(Form1.hwnd,FormCaption,128)

                                Print FormCaption

                                End Sub

                                注∶其中128是指字符串变量FormCaption的长度(又称缓冲区大小)

                                这有必要吗为了获得Form1窗体的标题,何必写这么多代码呢难道这就是API。是的,的确在VB中用 Print Form1.Caption 一行代码就可以抵挡住以上代码了。但是,假如我们启动我们设计的应用程序后,想要在用鼠标点一下别的应用程序的时候,让我们的应用程序显示出那个窗体的标题,那又该怎么办呢比方说,我们另外启动的是Micorsoft Word,用鼠标点击Word时让程序显示出"您选择了Microsoft Word"字样。显然只靠VB是办不到的,还得靠API这老手。

                                当然,您已经具备了这种能力,可以办到这件事情。让我们一起来。

                                关键的问题是如何获得Word程序的句柄。首先要认清的是,对VB的应用程序来说,Word

                                是属于进程外应用程序。正和您已经想到的那样,我们可以使用前一个示范程序用到过的

                                GetForegroundWindow API函数获取它的句柄。因为,当我们用鼠标点击Word时,Word

                                将成为前台活动窗体。接着呢当然是 GetWindowText函数显示它的标题就可以了。我们可以采用Timer控件来完成这一切。剩下的事情就不用我多说了。本教程附带的

                                Program2.vbp程序是,为那些懒得由自己动手写这几行代码的人准备的,但愿您不是。如果你还没有写过API应用程序,可以说这是一个好的机会,还是动一动你的手吧,会有好处的。

                                程序正常运行了没有哈,这下感觉到API的魅力了吧还想不想继续学下去呀!

                                三、矩形和点

                                关于矩形和点,我们在上一个课堂中简单提了一下。在这里,就做一下详细的介绍。

                                先从简单点(Point)结构的开始。点的结构如下∶

                                Type POINTAPIxas Longyas Long

                                End Type

                                在英语里,点叫Point,那么为什么不叫POINT,而叫POINTAPI呢原来,VB中有Point

                                方法,这只是为了不必要的冲突或重名。Point用于描述一个位置,当然是一个点的位置了。在屏幕坐标中,x指的是从屏幕左边界到指定点的距离,y指的是从屏幕顶边界到指定点的距离。初次之外,没有太多的学问了,还是那句老话──牢记按引用传递。

                                矩形的结构和点结构差不到哪儿去,只不过是用两个点来描述的。它的结构定义如下

                                Public Type RECT

                                Left As Long

                                Top As Long

                                Right As Long

                                Bottom As Long

                                End Type

                                以下图描述了RECT结构各字段的含义。

                                可以看出,一个矩形区域是通过矩形的左上角的一个点和右下角的一个点,共两个点来描述的。其中,left和top字段描述了巨型的第一个角的位置,right和bottom字段描述了矩形的第二个角即右下角的位置。

                                在VB中,描述一个窗体或控件所处的矩形位置时,经常用Left,top以及Width,height来描述的。其中,Width是一个巨型区域的宽度,Height是高度。在此,您应当看到,RECT结构中并不是这样。如,想要获得宽度,必须从right中减掉left。

                                API中有若干个函数用来处理矩形数据结构,如,下表所列∶函数功能

                                EquaRect 判断两个矩形是否相同,如果相同则返回True(非0)

                                InflateRect 增加或减少矩形的尺寸

                                InterSectRect获得两个矩形相重叠的部分,即一个新的矩形

                                IsRectEmpty 如矩形为空,则返回TRUE

                                OffsetRect 按规定的偏移量移动一个矩形的位置

                                ptInRect 判断一个指定点是否位于给出的矩形的内部

                                SetRect 设置巨型的参数字段值

                                SetRectEmpty将所有字段都设为0,从而将矩形置空

                                SubtractRect 将一个矩形从另一个巨型里减去。"即切掉"

                                UnionRect 获得同时包含两个矩形区域的最小矩形。

                                CopyRect将一个矩形的内容复制给另一个

                                这几个函数,都是很好理解和实际应用的。Program3.vbp示范程序是,为帮助大家了解这些函数的具体使用方法而设计的。此程序应用了以上函数列表中的多数函数。在阅读程序原代码时,请注意理解vbNotXorPen绘图模式的应用。

                                第三课∶窗口函数

                                一、 关于窗口函数

                                在上一堂课里,我们已经提出了"句柄"的概念,并为此进行了较深度的讨论。现在来想,我要补充的是,句柄并非是仅仅是窗口才有的。似乎所有的WINDOWS对象都具有句柄。如,GDI对象中的画笔、刷子等,不久即将要学习的设备场景等也有自己的句柄,等等。但,和一些控件不同,这些对象并不属于窗口。

                                什么是窗口呢有一句非常有趣的话∶如果它位于屏幕,那么它肯定是在一个窗口里;如果它不在于屏幕,它仍然可能在一个窗口里。窗体也是窗口;滚动条、列表框,文本框,甚至是桌面上的快捷图表也是窗口。更有趣的是,就连作为背景的桌面也是窗口。

                                很多控件基本上都提供了hWnd属性,但没有提供的也有。对于这些控件可以用SetFocus

                                方法,将输入焦点设向控件,然后用API函数GetFocus取得当前具有焦点的那个窗口的句柄。当然,这一过程应当写在GoFocus事件中。在我碰到过的问题中有一个有趣的事情是,VB提供的IE控件的hWnd属性不管用。这个问题我一般都采用上述方法来解决的。

                                很多窗口函数都能对系统的任何窗体进行操作。这意味了VB程序可以直接操纵正在运行中的其他窗体。大家知道,如果对VB设计出的程序未做特殊的处理,那么我们可以启动多个该应用程序实例。我们可以利用API窗口函数来判断一个窗体的先例是否在运行当中,从而可以做到如果有先例则停止启动。很多应用程序就是这个样子的。比如四通利方中文平台,在已经启动的情况下再此启动,程序会告诉用户"四通利方已经在运行",并停止启动。

                                窗口函数主要可分为四个类型(也许说为"这是为了这次讲课分类出来的"更适合一些)∶

                                1、窗口分级函数;

                                2、窗口位置与大小函数;

                                3、窗口信息函数;

                                4、其他窗口函数。

                                以下我们就一一讲述。但由于窗口函数比较多,在这里就选择性的进行讨论。关于窗口函数有多少,具体的用法如何,您可以注意"小雁侠"的VB API站点的技术文档,或者本站

                                程序下载栏目中的WinAPI帮助文。由于帮助文其内容来自"小雁侠"的网站,因此其内容更新比较起来会较晚一些。

                                二、窗口分级函数

                                系统中运行的窗口是有级别的高低之分的。谁不知道这样这当然是废话。很多文章都是采用类似的这种废话来做导语,在这里我只不过也是学学而罢。

                                一、父子关系。

                                每个窗口都可能有自己的父窗口和子窗口。但,系统中运行的窗口是有限的,说明总得有个窗口是没有其父,我们把它叫做顶级窗口。一般把一个应用程序的主窗口就是顶级窗口,VB独立窗体及MDI窗体都是顶级窗口。窗口间的父子关系一般遵循以下规则∶

                                1、父窗口显示时,所有包容在其中的可见的子窗口会随着父窗口的显示而显示出来。

                                2、父窗口隐藏时,所有包容在其中的子窗口会随着父窗口的隐藏而隐藏。

                                3、父窗口被卸载时,哈,您已经知道我想说什么了,当然是∶跟着自动卸载。

                                4、父窗口移动时,跟着移动。

                                二、兄弟关系及Z序列

                                当然,一位父亲有好几个儿女,都是常见的事情。同样,一个父窗口可以拥有多个子窗体。比如,位于一个窗体中的各种控件之间以及MDI窗口的各子窗口之间的关系。父窗口与子窗口的显示、隐藏、卸载及移动,其先后顺序是显而易见的。那么各兄弟窗口之间的情况会是如何呢

                                显然,两个互相重叠的两个子窗体不能都同时显示出它的全貌,自然有个显示的顺序规则。这个顺序规则叫做Z序列。有个解释为,如果把屏幕坐标看层X和Y轴组成的平面(事实上正是如此),那么作为三维坐标系统Z轴可看做是垂直于屏幕的坐标轴。这样,可以认为屏幕上的所有窗口是垂直于这个Z轴的。在Z轴上,谁在前,谁在后,就产生了一个Z序列。很生动!可用WINDOWS API函数和Visual Basic Z序列方法对Z序列进行控制。

                                有了以上简单的知识以后,我们就不难应用API窗口分级函数,主要有以下及个∶

                                窗口分级函数

                                函数名说明

                                FindWindow 按类名或窗口名(Caption)查找一个窗口

                                FindWindowEx 类似于FindWindow提供了更多的功能

                                GetLastActivePopup针对指定的窗口,取回上一个活动的弹出式窗口的句柄

                                GetParent 获得指定窗口父窗口的句柄

                                GetTopWindow 获得指定窗口的第一个子窗口的句柄

                                GetWindow 如给定一个窗口句柄,该函数能取回具有特定关系的另一个窗口 的句柄。如,第一个子窗口、父窗口或窗口列表内的上一个或下一个窗口。

                                SetParent 改变任何窗口的父窗口。

                                从我个人的经验来看,我最常用的是GetWindow和SetParent函数。

                                三、窗口位置与大小函数

                                Windows API函数基本上都是(尤其是USER32.DLL动态连接库内的函数)以屏幕像素为度量单位的。这一点很重要,必须牢记。为此,在使用API函数的时候,我们经常把窗体或图片框控件的ScaleMode属性设置为3,即vbPixels(像素)。

                                理解窗口位置及大小函数的关键在于分清屏幕坐标、窗口坐标及客户坐标这三个概念。以下图展示了这三个坐标系统之间的关系。

                                屏目、窗口与客户区坐标系统

                                只要对这些坐标有了明确的概念,对使用窗口位置及大小函数就不难了。关于窗口的位置,有些函数返回的是上一堂课学习到的RECT结构。有关窗口位置及大小函数如下表所列∶

                                窗口位置及大小函数

                                函数名说明

                                BringWindowToTop 使指定的窗口进入可见窗口列表的顶部,如它被部分或全部隐藏,则令其全部可见。同时,该窗口成为当前活动窗口。只有从前台线程调用时,才生效。

                                ChildWindowFromPoint 在规定的坐标取得某子窗口的句柄(如果有的话),这儿的坐标是指相对于父窗口的客户区坐标。

                                ChildWindowFromPointEx与 ChildWindowFromPoint相同,功能更强。

                                ClientToScreen 判断指定点在窗口客户区内的屏幕坐标。

                                GetClientRect 获得对窗口客户区进行表述的一个矩形(RECT)。这是以像素为单位判断客户区大小的一个简便的方法。

                                GetWindowPlacement 获得指定窗口的一个WINDOWPLACEMENT结构。该结构说明了窗口的状态。

                                GetWindowRect 用于获得一个矩形(RECT)结构,它描述了窗体在屏幕坐标系统中的位置。

                                MapWindowPoints 对某窗口客户区坐标内的一个或多个点进行转换,用另一窗口的客户区坐标表示。

                                MoveWindow 移动指定窗口的位置,并能改变它的大小。

                                OpenIcon 将一个最小化窗口恢复为原始状态。

                                ScreenToClient 针对屏幕内一个指定的点,用某个特定窗口内的客户区坐标表示它。

                                SetWindowsPos 更改窗口的位置和大小,并能修改它在内部窗口列表内的位置(这个列表起着控制窗口先是顺序)。

                                SetWindowPlacement 在一个WINDOWPLACEMENT结构的基础上,设置某窗口的特征。该结构描述了窗口的状态,以及它在最小化、最大化或正常显示时的位置。

                                WindowFromPoint 根据屏幕上一个指定的点,判断哪个窗口正位于它的下面。

                                以上函数的具体用法均可在WinAPI帮助文中找到。在这些函数当中,SetWindowsPos

                                函数的使用率比较高,现在很多人都是用这个函数来实现"窗口总在前面"的效果,即通过

                                HWND_TOPMOST常数把窗口置于列表顶部。如果想把From1置于列表顶部,方法如下∶

                                SetWindowPos Form1.hWnd,HWND_TOPMOST,Form1.Left/Screen.TwipsPerPixelX,Fo rm1.Top Screen.TwipsPerPixelY,Form1.Width Screen.TwipsPerPixelX,Form1.Height Screen.TwipsPerPixelY,0您可以把这行代码放在Paint事件中。

                                另外,GetWindowRect函数、MoveWindow函数以及下一课堂即将要学到的

                                GetCursorPos函数的相互配合能够实现一个拖动无标题栏的窗口。这是您必须掌握的技巧之一。感兴趣的朋友,可以到《前线》的《源码解析》栏目,下载第4号演示程序。以下是其主要的代码部分∶

                                Private MyRect As RECT

                                Private MyPoint As POINTAPI

                                Private Movex As Long,Movey As Long

                                Private Sub Image1_MouseDown(Button As Integer,Shift As Integer,XAs Single,YAs Single)

                                Dim dl&

                                dl&=GetWindowRect(Form1.hwnd,MyRect)

                                dl&=GetCursorPos(MyPoint)

                                If Button=1Then

                                Movex=MyPoint.X-MyRect.Left

                                Movey=MyPoint.Y-MyRect.Top

                                End If

                                End Sub

                                Private Sub Image1_MouseMove(Button As Integer,Shift As Integer,XAs Single,YAs Single)

                                Dim dl&

                                dl&=GetCursorPos(MyPoint)

                                If Button=1Then

                                dl&=MoveWindow(Form1.hwnd,MyPoint.X-Movex,MyPoint.Y-Movey,_MyRect.Right-MyRect.Left,MyRect.Bottom-MyRect.Top,-1)

                                End If

                                End Sub

                                在MouseDown事件中,程序首先用 GetWindowRect 函数确定窗口在屏幕中的位置。再次是通过GetCursorPos函数确鼠标在屏幕中的位置。从而可通过计算获得鼠标位置与窗口左上角之间的横向与纵向距离(Movex与Movey)。

                                在紧接着发生的MouseMove事件中程序不断地用GetCursorPos函数获得鼠标当前的位置,并按前面已经求得的Movex与Movey判断窗口所应处的位置,而这在MoveWindow函数调用中直接完成。MoveWindow函数将窗体移动到新的位置。

                                四、窗口信息函数

                                所谓窗口信息函数就是用来获取有关窗口当前状态信息的函数。这类函数主要有∶函数说明

                                GetClassInfo 取得指定窗口的类信息结构

                                GetClassInfoEx 效果类似于GetClassInfo,但增加了一些功能

                                GetClassLong,GetClassWord用于获取窗口类信息

                                SetClassLong,SetClassWord用于设置窗口类信息

                                GetClassName 获取窗口类名

                                GetDesktopWindow 获取整个桌面(屏幕)的窗口句柄

                                GetWindowLong,GetWindowWord 获取与窗口有关的信息

                                SetWindowLong,SetWindowWord 设置与窗口有关的信息

                                GetWindowText获得窗口文本。它的效果大致等价于窗体或控件的Text属性

                                GetWindowTextLength获得窗口文本的长度,用字符数表示。

                                IsChild 判断某窗口是否为另一窗口的子窗口或从属窗口。

                                IsIconic 判断某窗口是否处于最小化状态

                                IsWindow 判断指定的句柄是否为窗口句柄。

                                IsWindowEnabled 判断指定的窗口是否处于活动状态。

                                IsWindowVisible 判断某窗口是否可见。

                                IsZoomed 判断窗口是否处于最大化状态。

                                SetWindowText 设置窗口文本。大致等价于窗体或控件的Text属性。

                                大部分窗口信息函数是非常好理解的,按照有关手册中进行的函数说明,按指定数据类型进行调用即可。有必要说明的是,关于类和窗口的样式位。Windows是用一个长整形的数据的位设置方式来记录类和窗口的样式的。其中,窗口样式由一个32位样式以及另一个32

                                位扩展样式来构成。类样式操作由上述列表中的GetClassLong以及GetClassLong来进行,窗口样式操作由GetWindowLong 以及SetWindowLong来进行。

                                由于样式位的内容较多,我无法在此给出,您可以参考有关手册。这里有必要提醒大家的是,您想改变或获取当前窗口或类的样式,绝大多数情况可以考虑样式位操作。下面,就这个问题举一个简单了例子来说明。

                                下面是用BS_LEFTTEXT样式位将VB复选框或选项按钮的文本在左边和右边之间相互移动来、移动去的程序(是附带的Program1.vbp的部分内容)。程序的原理很简单。首先用

                                GetWindowLong函数获得当前样式位的信息,然后通过位操作来准备新的样式位信息,最后用SetWindowLong实际地去更改。如下∶

                                Dim f&,dl&

                                f&=GetWindowLong(Option1.hWnd,GWL_STYLE) '获得当前样式位的信息

                                If Index=0Then

                                f&=f& Or BS_LEFTTEXT

                                Else

                                f&=f& And Not BS_LEFTTEXT

                                End If

                                dl&=SetWindowLong(Option1.hWnd,GWL_STYLE,f&) '设置新的样式位

                                Option1.Refresh

                                (对Or和And位操作不熟悉的朋友,请参考有关技术资料)

                                在这里,对样式位不进行更详细讨论,主要有这样一个原因。用SetWindowLong函数改变一个样式位之后,不会导致窗口发生相应的变化(至少不会立即变化)。有些样式位可能在运行时候才会成功变化,而大多数都只在窗口创建时才生效。因为,用API方式创建一个窗体已经超出了本教程的范围,就算我在这里对样式位谈得再多,您可能也没有多大用处。同时,微软公司没有告诉我们哪些样式位在运行期间安全地改变,因此对具体的情况,只好靠自己进行具体试验。而从我个人的实际编程经验来看,没有特别的要求,我们不大会涉及到这些样式位操作,很多都可在VB中很方便地实现。

                                本教程还附带了一个Program2.vbp的演示程序。是我本人随便编写的,没什么特别希罕之处。想看就看看好了。

                                最后,想简单提一提的是,使用SetWindowLong函数的时候,改变GWL_WNDPROC

                                数据是非常危险的(系统或VB经常挂死),即更改窗口函数的位置。一般,这种更改在需要进行子类处理的地方应用到。每次试运行程序,都应当习惯性地进行存盘。

                                五、其他窗口函数

                                API中还有以下本教程未列出的窗口函数,以供大家参考。

                                函数名说明

                                AnyPopup 判断是否存在可见的弹出式窗口

                                CascadeWindows 令窗口在一个父窗口内层叠显示

                                CloseWindow 对指定的窗口进行最小化处理(如果它是个钉级窗口)对弹出式及子窗口无效

                                DestroyWindow 清除指定的窗口以及下属所有子窗口与包容窗口

                                DrawAnimatedRects 获得窗口打开或关闭的动画效果

                                EnableWindow 激活或屏蔽(禁用)指定窗口

                                FlashWindow 令指定窗口的标题闪烁显示

                                GetUpdateRect 判断需要更新的那个窗口的位置

                                GetWindowContextHelpId取得与窗口关联在一起的帮助场景

                                InvalidateRect 指定窗口内需要更新的全部或部分客户区

                                IsWindowUnicode 判断一个窗口是否期望文本消息采用Unicode格式

                                LockWindowUpdate 允许或禁止描绘指定的窗口

                                RedrawWindow 一个功能强大的函数,用于控制全部或部分窗口重画

                                ScrollWindow,ScrollWindowEx滚动显示窗口的全部或部分客户区

                                SetWindowContextHelpId设置与窗口关联在一起的帮助场景

                                ShowOwnedPopups 隐藏或显示从属于指定窗口的所有保容弹出窗口

                                ShowWindow 用于设置窗口的状态,其中包括窗口的隐藏、显示、最小化、最大化以及激活等

                                ShowWindowAsync 类似于ShowWindow,增加了对其他进程内的窗口进行操作的能力

                                TileWindows 令窗口在一个父窗口内平铺显示

                                UpdateWindow 立即更新窗口内需要更新的任何部分

                                ValidateRect 指出全部或部分矩形已经更新,毋需再更新

                                其中,FlashWindow函数非常有趣,不妨大家试一试。
                                文章:Visual Basic 6.0常用工具入门教程代码实例  发表时间:2016-08-31, 16:20:18  
                                展开↯

                                #2250

                                作者:广西南宁市
                                AutoRedraw = True 开启自动重绘功能,使窗体print事件产生的字不消失
                                Run code
                                Cut to clipboard
                                  文章:Visual Basic 6.0常用工具入门教程代码实例  发表时间:2016-08-31, 16:19:36  
                                  展开↯

                                  #2251

                                  作者:广西南宁市
                                  vb恢复一个最小化的程序,并激活窗口,最小化还原,还原最小化窗口
                                  Declare Function OpenIcon Lib "user32" Alias "OpenIcon" (ByVal hwnd As Long) As Long 说明 恢复一个最小化的程序,并将其激活 返回值 Long,非零表示成功,零表示失败。会设置GetLastError 参数表 参数 类型及说明 hwnd Long,欲恢复的窗口 注解 针对vb窗体,应使用vb的WindowState属性
                                  Run code
                                  Cut to clipboard
                                    文章:Visual Basic 6.0常用工具入门教程代码实例  发表时间:2016-08-31, 16:18:47  
                                    展开↯

                                    #2252

                                    作者:广西南宁市
                                    vb中API函数findwindow的详细用法
                                    vb中FindWindow函数可以用来返回窗体的句柄。 1、VB6.0中的API声明: Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long 2、具体使用: dim i as long i=FindWindow(vbNullString,"窗体的标题") 注意:这里的vbNullString是空的,没有任何字符,即不传递。和""空字符串是不一样的! 3、例子: 有一个标题名字是计算器的窗体或软件,获取这个计算器的句柄 Option Explicit Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long Private Sub Command1_Click() Dim i As Long i = FindWindow(vbNullString, "计算器") msgbox& i '显示窗体句柄 End sub
                                    Run code
                                    Cut to clipboard

                                      VB检查自身程序已经运行
                                      Private Sub Form_Load() If App.PrevInstance Then End End If End Sub 用DDE实现窗体防止运行多个实例并传递命令 上网的朋友一定都用过网络蚂蚁(Net Ants)的吧?不知你在使用过程中有没有注意过,那就是如果你想调动两个“蚂蚁”为您效力是不可能的——它总会把新运行的关闭。这点在VB中很容易实现: Private Sub Form_Load() If App.PrevInstance Then MsgBox "你已经运行这个应用程序了" End ' 退出新运行的程序 End If End Sub 这样如果你运行这个程序后在运行它,它会弹出一个消息框并拒绝再次运行。这非常容易。 而“蚂蚁”程序的妙处就在于:在重复运行“蚂蚁”时它不仅拒绝运行,而且能把已经运行的“蚂蚁”激活,这样用上面的程序就无能为力了。但事实上实现拒绝运行并激活已运行的 程序有多种方法: 1、用FindWindow函数得到已经运行窗体的句柄(HWND),然后用SetActiveWindow等API函数将其激活。其缺点也很明显,那就是没法传递参数。 2、用FindWindow函数得到已运行窗体的句柄后用SendMessage的方法给窗体传送一个自定义消息(附带参数),然后在窗体中拦截并进行处理,但这样做要修改窗体的标准消息处理程序,用在VC,BC或DELPHI编写的程序中还行,但在VB中工作量太大,并且容易发生“一般保护行错误”使VB崩溃,不太可取(当然,如果你有足够的信心和不怕崩溃的精神,也可以试一下 ^_^ )。 3、使用DDE技术。 所谓DDE技术,就是动态数据交换技术。也许你很奇怪,这与本文所讨论的内容有什么相干的? 且听我慢慢讲来。 为了实现拒绝运行并把已经运行的程序激活并实现各种功能,我们可以先用本文开头提到的方法,检测一下程序有没有被运行过,如果没有,就正常运行,如果已经被运行过,就打通与它的DDE通道,传给它一个(或一些)数据,然后由已经运行的程序对数据进行处理,再去实现各种“意想不到”的功能,这时也许就有人对这你的程序喊:“酷、酷……” ^_^ 好了,耳听为虚,眼见为实,下面让我们动点真格的。 打开VB,新建一个工程,选择菜单中的“工程->工程1 属性”,把工程名称改为“P1”(我爱偷懒,能短则短 ^_^ ),把已有的一个窗体的“LinkTopic”属性改为“FormDDE”,把“LinkMode”属性改为“1 - Source”,添加一个PictureBox控件作为DDE执行控件,命名为picDDE。然后添加一个TextBox控件,命名为“txtInfo”,并把“MultiLine”属性设置为“True”,以便显示多行文本,作为消息显示控件。 最后在窗体代码区输入以下代码: Const COMMANDLINE = "CommandLine=" ' 还是为了省事,定义一个常量 Private Sub Form_LinkExecute(CmdStr As String, Cancel As Integer) Static lngCount As Long Dim Info As String Info = txtInfo.Text ' 保留原有信息 Select Case CmdStr ' CmdStr 是DDE程序传送过来的参数 Case "Max" Me.WindowState = 2 Info = Info + vbNewLine + "窗体已被最大化" Case "ShowTime" Info = Info + vbNewLine + "最后一次运行这个程序的时间是:" + Str(Now) Case "Count" lngCount = lngCount + 1 Info = Info + vbNewLine + "你已经第" + Str(lngCount) + "次重复调用这个程序。" _ + vbNewLine + "但怕您不多给工资,所以只运行了一个 ^_^" End Select If Left(CmdStr, Len(COMMANDLINE)) = COMMANDLINE Then Info = Info + vbNewLine + "新程序曾以命令行形式运行" + vbNewLine + "命令行为:" _ + vbNewLine + Right(CmdStr, Len(CmdStr) - Len(COMMANDLINE)) End If txtInfo.Text = Info ' 把信息显示出来 Cancel = False End Sub Private Sub LinkAndSendMessage(ByVal Msg As String) Dim t As Long picDDE.LinkMode = 0 '-- picDDE.LinkTopic = "P1|FormDDE" ' |______连接DDE程序并发送数据/参数 picDDE.LinkMode = 2 ' | “|”为管道符,是“退格键”旁边的竖线, picDDE.LinkExecute Msg '-- 不是字母或数字! t = picDDE.LinkTimeout '-- picDDE.LinkTimeout = 1 ' |______终止DDE通道。当然,也可以用别的方法 picDDE.LinkMode = 0 ' | 这里用的是超时强制终止的方法 picDDE.LinkTimeout = t '-- End Sub Private Sub Form_Load() If App.PrevInstance Then ' 程序是否已经运行 Me.LinkTopic = "" ' 这两行用于清除新运行的程序的DDE服务器属性, Me.LinkMode = 0 ' 否则在连接DDE程序时会出乱子的 LinkAndSendMessage "Max" '-- LinkAndSendMessage "Count" ' |-----连接DDE接受程序并传送数据/参数 LinkAndSendMessage "ShowTime" '-- If Command <> "" Then ' 如果有命令行参数,就传递过去 LinkAndSendMessage COMMANDLINE + Command End If End ' 结束新程序的运行 End If End Sub 测试一下: 把工程“P1”编译成EXE文件(设名称为 P1.EXE ) 1、打开“我的电脑”,找到 P1.EXE 并执行。可以看到程序正常运行了。 2、再运行一次,这次新程序没有运行成功,而原来运行的程序却被最大化了,而且文本框中有以下 字符: 窗体已被最大化 你已经第 1次重复调用这个程序。 但怕您不多给工资,所以只运行了一个 ^_^ 最后一次运行这个程序的时间是:00-2-6 7:11:01 3、打开 MS-DOS方式 ,用命令行方式再次运行程序,如 “P1 How Are You?” 这时原来运行的程序文本框中又多了几行字: 窗体已被最大化 你已经第 2次重复调用这个程序。 但怕您不多给工资,所以只运行了一个 ^_^ 最后一次运行这个程序的时间是:00-2-6 7:14:32 新程序曾以命令行形式运行 命令行为: How Are You? OK,运行完全正确,然后你就可以把它应用的你的程序中了。
                                      Run code
                                      Cut to clipboard
                                        文章:Visual Basic 6.0常用工具入门教程代码实例  发表时间:2016-08-31, 16:16:30  
                                        展开↯

                                        #2253

                                        作者:广西南宁市
                                        vb app 详解
                                        1.App.Path 返回或设置当前路径。在设计时是不可用的。 比如你写了个程序,然后放在“C:\MyPrograme”下,则 Print App.Path就会打印出C:\MyPrograme。 2.App.EXEName 返回当前正运行的可执行文件的根名(也就是应用程序的名称,不带扩展名)。如果是在开发环境下运行,则返回该工程名。 比较你编译后生成的文件为Hello.exe,则Print App.EXEName会打印Hello(不带.exe)。 3.App.PrevInstance 属性 用来判断是否已经有前一个应用程序实例在运行。 比如说,你写了个程序Good.exe,你若不想运行程序后还没有关闭,但不想再打开一个(重复运行)。你可以在窗体的Form_Load()事件中这样判断。 If App.PrevInstance = Ture Then MsgBox "程序已经打开。",vbInformation,"温馨提示:" End End If 这样你就不会重复打开多次了。 不知道我的回答你是否满意,欢迎随时交流。 追问 先谢谢你,我列出来的我早就知道,能介绍我没列出来的吗?谢谢 追答 这个有点多,呵呵。 1.Comments 属性 返回或设置一个字符串,该字符串包括运行中的应用程序的注释。该属性在运行时是只读的。 2.CompanyName 属性 返回或设置一个字符串,该字符串包括运行中的应用程序的公司或创建者名称。该属性在运行时是只读的。 3.FileDescription 属性 返回或设置一个字符串,该字符串包括运行中应用程序的文件说明信息。该属性在运行时是只读的。 4.Major属性 返回或设置该工程的主要版本号。该属性在运行时是只读的。 5.Minor 属性 返回或设置该工程的小版本号。该属性在运行时是只读的。 若有问题,欢迎随时交流。
                                        Run code
                                        Cut to clipboard
                                          文章:Visual Basic 6.0常用工具入门教程代码实例  发表时间:2016-08-31, 16:14:37  
                                          展开↯

                                          #2254

                                          作者:广西南宁市
                                          #4 自动关机VB工程项目文件打包 下载 (下载后文件后缀修改 .rar)
                                          文章:Visual Basic 6.0常用工具入门教程代码实例  发表时间:2016-08-31, 16:11:43  
                                          展开↯

                                          #2255

                                          作者:广西南宁市
                                          VB 自动关机.exe
                                          Private Const SWP_NOSIZE = &H1 Private Const SWP_NOMOVE = &H2 Private Const HWND_TOPMOST = -1 Private Const HWND_NOTOPMOST = -2 Private Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal X As Long, ByVal Y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long 'Private Declare Function SetFocusAPI& Lib "user32" Alias "SetFocus" (ByVal hwnd As Long) 'Private Declare Function SetForegroundWindow Lib "user32" (ByVal hwnd As Long) As Long Private Declare Function OpenIcon Lib "user32" (ByVal hwnd As Long) As Long Private Sub Form_Load() If App.PrevInstance Then 'MsgBox "系统不允许程序运行多次,请关闭后再试。", vbInformation, "系统提示" Unload Me 'Exit Sub 'Me.SetFocus Dim i As Long i = FindWindow(vbNullString, "自动关机") 'MsgBox& i '显示窗体句柄 'SetForegroundWindow i 'SetFocusAPI& i OpenIcon (i) '最小化窗口还原 End End If 'Me.ZOrder SetWindowPos hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE '设置顶 End Sub Private Sub guanji_Click() Timer1.Enabled = True '启动控件 Timer1.Interval = 1000 '设定跳动频为1秒。1000=1秒 End Sub Private Sub quxiao_Click() 'quxiao.Visible = False Label4.Caption = "0" guanji.Caption = "开始倒计时关机" Timer1.Enabled = False Shell "Shutdown -a" End Sub Private Sub Timer1_Timer() If Label4.Caption = "-1" Then guanji.Caption = "即将关机" Exit Sub End If If Label4.Caption = "1" Then Shell "cmd /c" & "shutdown -s -t 0" Label4.Caption = "-1" Exit Sub End If If Label4.Caption = "0" Then Label4.Caption = Text1.Text * 60 - 1 '以秒计时 Else quxiao.Visible = True Label4.Caption = Label4.Caption - 1 End If guanji.Caption = Label4.Caption & "秒后关机" End Sub
                                          Run code
                                          Cut to clipboard


                                            程序下载 (下载后文件后缀修改 .exe)
                                            文章:Visual Basic 6.0常用工具入门教程代码实例  发表时间:2016-08-31, 16:08:39  
                                            展开↯

                                            #2256

                                            作者:广西南宁市
                                            交易双方讨价还价时使用的筹码就是稀缺资源
                                            文章:常用html、demo代码  发表时间:2016-08-31, 10:01:10  
                                            展开↯

                                            #2257

                                            作者:广西南宁市
                                            任何人群都可从内部分为智者和愚者。
                                            文章:我身边有个这样的人  发表时间:2016-08-31, 09:42:50  
                                            展开↯

                                            #2258

                                            作者:广西南宁市
                                            幸存者偏倚(Survivorship bias)是一种常见的逻辑谬误(所以我说叫“谬误”而不是“偏差”),意思是只能看到经过某种筛选而产生的结果,而没有意识到筛选的过程,因此忽略了被筛选掉的关键信息。这东西的别名有很多,比如“沉默的数据”、“死人不会说话”等等。

                                            空战的例子这样解释:简单来说,专家根据返航飞机翼部和尾部等位置中弹最多的特点,判断出,如果要强化飞机装甲,应该强化翼部和尾部。但如果仅仅根据返航的飞机上的弹孔分布,来研究该加强飞机的哪部分时,就忽略掉了“飞机被击落”这个筛选的过程。也就是说,能返航的飞机都是躲过防空炮火筛选的、没有受过致命伤的。他们多中弹于翼部和尾部,而油箱和驾驶员仓位完好,这恰恰说明翼部和尾部不是致命伤,不应该加强;而油箱和驾驶员仓位受伤的飞机,基本没有活着回来的,因此油箱和驾驶员仓位才是真正致命的地方,这些部位受伤的飞机却因为被击落而被筛出研究样本,从而变成了“不会说话的死人”,或“沉默的数据”。

                                            再举个例子,如果仅仅通过研究大学生来探究高中教育的问题,那就忽略了高考这个筛选器:没有通过高考、没有考上大学的人,他们才是在高中教育真正出现问题的人,而他们不在大学生的研究样本中。

                                            现在看很多人在知乎上讨论的政治问题、经济问题、文化问题,也有此类逻辑谬误。大多数知乎网友的观点和见闻,大多来自于你们能接触到的,可以在网络传播、可以通过新闻媒体扩散的信息,而那些没什么人传播、上不了新闻,却天天发生的事情,我们都不了解。没有调查就没有发言权,就是这个意思咯。
                                            文章:巴菲特三大经典演讲  发表时间:2016-08-30, 17:11:25  
                                            展开↯

                                            #2259

                                            作者:广西南宁市
                                            幸存者偏差 提醒我们:既要关注成功者的经验,又要关注失败者的教训。否则就会犯以偏概全的错误。
                                            文章:巴菲特三大经典演讲  发表时间:2016-08-30, 17:09:24  
                                            展开↯

                                            #2260

                                            作者:广西南宁市
                                            VB将汉字转换成拼音的函数
                                            Private Function Getpy(Txt) Dim d, TmpTxt Dim wzcode, i, TmpWZ, a, b, ii Set d = CreateObject("Scripting.Dictionary") d.Add "a", -20319 d.Add "ai", -20317 d.Add "an", -20304 d.Add "ang", -20295 d.Add "ao", -20292 d.Add "ba", -20283 d.Add "bai", -20265 d.Add "ban", -20257 d.Add "bang", -20242 d.Add "bao", -20230 d.Add "bei", -20051 d.Add "ben", -20036 d.Add "beng", -20032 d.Add "bi", -20026 d.Add "bian", -20002 d.Add "biao", -19990 d.Add "bie", -19986 d.Add "bin", -19982 d.Add "bing", -19976 d.Add "bo", -19805 d.Add "bu", -19784 d.Add "ca", -19775 d.Add "cai", -19774 d.Add "can", -19763 d.Add "cang", -19756 d.Add "cao", -19751 d.Add "ce", -19746 d.Add "ceng", -19741 d.Add "cha", -19739 d.Add "chai", -19728 d.Add "chan", -19725 d.Add "chang", -19715 d.Add "chao", -19540 d.Add "che", -19531 d.Add "chen", -19525 d.Add "cheng", -19515 d.Add "chi", -19500 d.Add "chong", -19484 d.Add "chou", -19479 d.Add "chu", -19467 d.Add "chuai", -19289 d.Add "chuan", -19288 d.Add "chuang", -19281 d.Add "chui", -19275 d.Add "chun", -19270 d.Add "chuo", -19263 d.Add "ci", -19261 d.Add "cong", -19249 d.Add "cou", -19243 d.Add "cu", -19242 d.Add "cuan", -19238 d.Add "cui", -19235 d.Add "cun", -19227 d.Add "cuo", -19224 d.Add "da", -19218 d.Add "dai", -19212 d.Add "dan", -19038 d.Add "dang", -19023 d.Add "dao", -19018 d.Add "de", -19006 d.Add "deng", -19003 d.Add "di", -18996 d.Add "dian", -18977 d.Add "diao", -18961 d.Add "die", -18952 d.Add "ding", -18783 d.Add "diu", -18774 d.Add "dong", -18773 d.Add "dou", -18763 d.Add "du", -18756 d.Add "duan", -18741 d.Add "dui", -18735 d.Add "dun", -18731 d.Add "duo", -18722 d.Add "e", -18710 d.Add "en", -18697 d.Add "er", -18696 d.Add "fa", -18526 d.Add "fan", -18518 d.Add "fang", -18501 d.Add "fei", -18490 d.Add "fen", -18478 d.Add "feng", -18463 d.Add "fo", -18448 d.Add "fou", -18447 d.Add "fu", -18446 d.Add "ga", -18239 d.Add "gai", -18237 d.Add "gan", -18231 d.Add "gang", -18220 d.Add "gao", -18211 d.Add "ge", -18201 d.Add "gei", -18184 d.Add "gen", -18183 d.Add "geng", -18181 d.Add "gong", -18012 d.Add "gou", -17997 d.Add "gu", -17988 d.Add "gua", -17970 d.Add "guai", -17964 d.Add "guan", -17961 d.Add "guang", -17950 d.Add "gui", -17947 d.Add "gun", -17931 d.Add "guo", -17928 d.Add "ha", -17922 d.Add "hai", -17759 d.Add "han", -17752 d.Add "hang", -17733 d.Add "hao", -17730 d.Add "he", -17721 d.Add "hei", -17703 d.Add "hen", -17701 d.Add "heng", -17697 d.Add "hong", -17692 d.Add "hou", -17683 d.Add "hu", -17676 d.Add "hua", -17496 d.Add "huai", -17487 d.Add "huan", -17482 d.Add "huang", -17468 d.Add "hui", -17454 d.Add "hun", -17433 d.Add "huo", -17427 d.Add "ji", -17417 d.Add "jia", -17202 d.Add "jian", -17185 d.Add "jiang", -16983 d.Add "jiao", -16970 d.Add "jie", -16942 d.Add "jin", -16915 d.Add "jing", -16733 d.Add "jiong", -16708 d.Add "jiu", -16706 d.Add "ju", -16689 d.Add "juan", -16664 d.Add "jue", -16657 d.Add "jun", -16647 d.Add "ka", -16474 d.Add "kai", -16470 d.Add "kan", -16465 d.Add "kang", -16459 d.Add "kao", -16452 d.Add "ke", -16448 d.Add "ken", -16433 d.Add "keng", -16429 d.Add "kong", -16427 d.Add "kou", -16423 d.Add "ku", -16419 d.Add "kua", -16412 d.Add "kuai", -16407 d.Add "kuan", -16403 d.Add "kuang", -16401 d.Add "kui", -16393 d.Add "kun", -16220 d.Add "kuo", -16216 d.Add "la", -16212 d.Add "lai", -16205 d.Add "lan", -16202 d.Add "lang", -16187 d.Add "lao", -16180 d.Add "le", -16171 d.Add "lei", -16169 d.Add "leng", -16158 d.Add "li", -16155 d.Add "lia", -15959 d.Add "lian", -15958 d.Add "liang", -15944 d.Add "liao", -15933 d.Add "lie", -15920 d.Add "lin", -15915 d.Add "ling", -15903 d.Add "liu", -15889 d.Add "long", -15878 d.Add "lou", -15707 d.Add "lu", -15701 d.Add "lv", -15681 d.Add "luan", -15667 d.Add "lue", -15661 d.Add "lun", -15659 d.Add "luo", -15652 d.Add "ma", -15640 d.Add "mai", -15631 d.Add "man", -15625 d.Add "mang", -15454 d.Add "mao", -15448 d.Add "me", -15436 d.Add "mei", -15435 d.Add "men", -15419 d.Add "meng", -15416 d.Add "mi", -15408 d.Add "mian", -15394 d.Add "miao", -15385 d.Add "mie", -15377 d.Add "min", -15375 d.Add "ming", -15369 d.Add "miu", -15363 d.Add "mo", -15362 d.Add "mou", -15183 d.Add "mu", -15180 d.Add "na", -15165 d.Add "nai", -15158 d.Add "nan", -15153 d.Add "nang", -15150 d.Add "nao", -15149 d.Add "ne", -15144 d.Add "nei", -15143 d.Add "nen", -15141 d.Add "neng", -15140 d.Add "ni", -15139 d.Add "nian", -15128 d.Add "niang", -15121 d.Add "niao", -15119 d.Add "nie", -15117 d.Add "nin", -15110 d.Add "ning", -15109 d.Add "niu", -14941 d.Add "nong", -14937 d.Add "nu", -14933 d.Add "nv", -14930 d.Add "nuan", -14929 d.Add "nue", -14928 d.Add "nuo", -14926 d.Add "o", -14922 d.Add "ou", -14921 d.Add "pa", -14914 d.Add "pai", -14908 d.Add "pan", -14902 d.Add "pang", -14894 d.Add "pao", -14889 d.Add "pei", -14882 d.Add "pen", -14873 d.Add "peng", -14871 d.Add "pi", -14857 d.Add "pian", -14678 d.Add "piao", -14674 d.Add "pie", -14670 d.Add "pin", -14668 d.Add "ping", -14663 d.Add "po", -14654 d.Add "pu", -14645 d.Add "qi", -14630 d.Add "qia", -14594 d.Add "qian", -14429 d.Add "qiang", -14407 d.Add "qiao", -14399 d.Add "qie", -14384 d.Add "qin", -14379 d.Add "qing", -14368 d.Add "qiong", -14355 d.Add "qiu", -14353 d.Add "qu", -14345 d.Add "quan", -14170 d.Add "que", -14159 d.Add "qun", -14151 d.Add "ran", -14149 d.Add "rang", -14145 d.Add "rao", -14140 d.Add "re", -14137 d.Add "ren", -14135 d.Add "reng", -14125 d.Add "ri", -14123 d.Add "rong", -14122 d.Add "rou", -14112 d.Add "ru", -14109 d.Add "ruan", -14099 d.Add "rui", -14097 d.Add "run", -14094 d.Add "ruo", -14092 d.Add "sa", -14090 d.Add "sai", -14087 d.Add "san", -14083 d.Add "sang", -13917 d.Add "sao", -13914 d.Add "se", -13910 d.Add "sen", -13907 d.Add "seng", -13906 d.Add "sha", -13905 d.Add "shai", -13896 d.Add "shan", -13894 d.Add "shang", -13878 d.Add "shao", -13870 d.Add "she", -13859 d.Add "shen", -13847 d.Add "sheng", -13831 d.Add "shi", -13658 d.Add "shou", -13611 d.Add "shu", -13601 d.Add "shua", -13406 d.Add "shuai", -13404 d.Add "shuan", -13400 d.Add "shuang", -13398 d.Add "shui", -13395 d.Add "shun", -13391 d.Add "shuo", -13387 d.Add "si", -13383 d.Add "song", -13367 d.Add "sou", -13359 d.Add "su", -13356 d.Add "suan", -13343 d.Add "sui", -13340 d.Add "sun", -13329 d.Add "suo", -13326 d.Add "ta", -13318 d.Add "tai", -13147 d.Add "tan", -13138 d.Add "tang", -13120 d.Add "tao", -13107 d.Add "te", -13096 d.Add "teng", -13095 d.Add "ti", -13091 d.Add "tian", -13076 d.Add "tiao", -13068 d.Add "tie", -13063 d.Add "ting", -13060 d.Add "tong", -12888 d.Add "tou", -12875 d.Add "tu", -12871 d.Add "tuan", -12860 d.Add "tui", -12858 d.Add "tun", -12852 d.Add "tuo", -12849 d.Add "wa", -12838 d.Add "wai", -12831 d.Add "wan", -12829 d.Add "wang", -12812 d.Add "wei", -12802 d.Add "wen", -12607 d.Add "weng", -12597 d.Add "wo", -12594 d.Add "wu", -12585 d.Add "xi", -12556 d.Add "xia", -12359 d.Add "xian", -12346 d.Add "xiang", -12320 d.Add "xiao", -12300 d.Add "xie", -12120 d.Add "xin", -12099 d.Add "xing", -12089 d.Add "xiong", -12074 d.Add "xiu", -12067 d.Add "xu", -12058 d.Add "xuan", -12039 d.Add "xue", -11867 d.Add "xun", -11861 d.Add "ya", -11847 d.Add "yan", -11831 d.Add "yang", -11798 d.Add "yao", -11781 d.Add "ye", -11604 d.Add "yi", -11589 d.Add "yin", -11536 d.Add "ying", -11358 d.Add "yo", -11340 d.Add "yong", -11339 d.Add "you", -11324 d.Add "yu", -11303 d.Add "yuan", -11097 d.Add "yue", -11077 d.Add "yun", -11067 d.Add "za", -11055 d.Add "zai", -11052 d.Add "zan", -11045 d.Add "zang", -11041 d.Add "zao", -11038 d.Add "ze", -11024 d.Add "zei", -11020 d.Add "zen", -11019 d.Add "zeng", -11018 d.Add "zha", -11014 d.Add "zhai", -10838 d.Add "zhan", -10832 d.Add "zhang", -10815 d.Add "zhao", -10800 d.Add "zhe", -10790 d.Add "zhen", -10780 d.Add "zheng", -10764 d.Add "zhi", -10587 d.Add "zhong", -10544 d.Add "zhou", -10533 d.Add "zhu", -10519 d.Add "zhua", -10331 d.Add "zhuai", -10329 d.Add "zhuan", -10328 d.Add "zhuang", -10322 d.Add "zhui", -10315 d.Add "zhun", -10309 d.Add "zhuo", -10307 d.Add "zi", -10296 d.Add "zong", -10281 d.Add "zou", -10274 d.Add "zu", -10270 d.Add "zuan", -10262 d.Add "zui", -10260 d.Add "zun", -10256 d.Add "zuo", -10254 TmpTxt = "" For i = 1 To Len(Txt) wzcode = Asc(Mid(Txt, i, 1)) If wzcode > 0 And wzcode < 160 Then TmpWZ = Chr(wzcode) Else If wzcode < -20319 Or wzcode > -10247 Then TmpWZ = "" Else a = d.Items b = d.keys For ii = d.Count - 1 To 0 Step -1 If a(ii) <= wzcode Then Exit For Next TmpWZ = b(ii) End If End If TmpTxt = TmpTxt & TmpWZ Next Set d = Nothing Getpy = TmpTxt End Function
                                            Run code
                                            Cut to clipboard

                                              '调用 Private Sub Form_Load() MsgBox Getpy("新兴网络") End Sub
                                              Run code
                                              Cut to clipboard
                                                文章:Visual Basic 6.0常用工具入门教程代码实例  发表时间:2016-08-30, 17:04:46  
                                                展开↯

                                                #2261

                                                作者:广西南宁市
                                                窗口置顶与取消 这里使用API实现 在变量定义处: Private Const SWP_NOSIZE = &H1 Private Const SWP_NOMOVE = &H2 Private Const HWND_TOPMOST = -1 Private Const HWND_NOTOPMOST = -2 Private Declare Function SetWindowPos Lib "user32" (ByVal hWnd As Long, ByVal hWndInsertAfter As Long, ByVal X As Long, ByVal Y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long 执行语句: SetWindowPos hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE '取消置顶 SetWindowPos hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE '设置顶
                                                Run code
                                                Cut to clipboard
                                                  文章:Visual Basic 6.0常用工具入门教程代码实例  发表时间:2016-08-30, 17:03:03  
                                                  展开↯
                                                  你好,残忍屏蔽广告

                                                  确定要清除编辑框内容吗?

                                                  该删除操作将不可恢复。

                                                  删除 取消

                                                  激活Windows

                                                  转到"设置"以激活Windows。