[转载]android AndroidInject框架——我的第一个android小型框架 - 天天_byconan - 博客园

mikel阅读(951)

[转载][android]AndroidInject框架——我的第一个android小型框架 – 天天_byconan – 博客园.

作为一个移动应用开发者,随着需求的日益增多,Android项目的越来越臃肿,代码量越来越大,

现在冷静下来回头看看我们的代码,有多少代码跟业务逻辑没什么关系的

 

所以,本人自不量力,在github上建了个开源项目,希望能一定程度地简化我的代码-。-

现在第一个版本完成,希望有兴趣的朋友能加入一起完善。

本人才疏学浅,代码中有写得不妥的地方希望大家不吝赐教哈!

github地址:

https://github.com/wangjiegulu/androidInject

AndroidInject_1.0.jar:

http://pan.baidu.com/s/1rcSiy

 

主要的思想就是通过注解的方式,把我们要做的事情直接注入进来给我们,“不是我去调用对象,而是对象自己来找我”

现在刚写完了10个注解:

@AINoTitle, @AIFullScreen, @AILayout, @AIView, @AIBean, @AISystemService, @AIClick, @AIItemClick, @AILongClick, @AIItemLongClick

使用方法如下:

Activity中使用:

package com.wangjie.androidinject;

import android.app.AlarmManager;
import android.content.Intent;
import android.location.LocationManager;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.*;
import com.wangjie.androidinject.annotation.annotations.*;
import com.wangjie.androidinject.annotation.present.AIActivity;
import com.wangjie.androidinject.model.Person;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@AIFullScreen
@AINoTitle
@AILayout(R.layout.main)
public class MainActivity extends AIActivity{

    @AIView(id = R.id.btn1, clickMethod = "onClickCallback", longClickMethod = "onLongClickCallback")
    private Button btn1;

    @AIView(clickMethod = "onClickCallback", longClickMethod = "onLongClickCallback")
    private Button btn2;

//    @AIView(id = R.id.btn3)
//    private Button btn3;

//    @AIView(id = R.id.listView, itemClickMethod = "onItemClickCallback", itemLongClickMethod = "onItemLongClickCallbackForListView")
    @AIView(id = R.id.listView)
    private ListView listView;

    @AIBean
    private Person person;

    @AISystemService
    private AlarmManager alarmManager;
    @AISystemService
    private LocationManager locationManager;
    @AISystemService
    private LayoutInflater inflater;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        List<Map<String, String>> list = new ArrayList<Map<String, String>>();
        Map<String, String> map;
        for(int i = 0; i < 10; i++){
            map = new HashMap<String, String>();
            map.put("title", "item_" + i);
            list.add(map);
        }

        SimpleAdapter adapter = new SimpleAdapter(context, list, R.layout.list_item, new String[]{"title"}, new int[]{R.id.list_item_title_tv});
        listView.setAdapter(adapter);

        person.setName("wangjie");
        person.setAge(23);
        System.out.println(person.toString());

        System.out.println("alarmManager: " + alarmManager + ", locationManager: " + locationManager + ", inflater: " + inflater);


    }

    @Override
    public void onClickCallback(View view){
        if(view instanceof Button){
            Toast.makeText(context, "onClickCallback: " + ((Button)view).getText(), Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onLongClickCallback(View view){
        if(view instanceof Button){
            Toast.makeText(context, "onLongClickCallback: " + ((Button)view).getText(), Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onItemClickCallback(AdapterView<?> adapterView, View view, int i, long l) {
        Toast.makeText(context, "onItemClickCallback: " + ((Map<String, String>)adapterView.getAdapter().getItem(i)).get("title"), Toast.LENGTH_SHORT).show();
    }

    @AIClick({R.id.btn3, R.id.toFragmentBtn})
    public void onClickCallbackForBtn3(View view){
        if(view instanceof Button){
            Toast.makeText(context, "onClickForBtn3: " + ((Button)view).getText(), Toast.LENGTH_SHORT).show();
        }

        if(view.getId() == R.id.toFragmentBtn){
            startActivity(new Intent(context, SecendActivity.class));
        }

    }

    @AILongClick({R.id.btn3})
    public void onLongClickCallbackForBtn3(View view){
        if(view instanceof Button){
            Toast.makeText(context, "onLongClickCallbackForBtn3: " + ((Button)view).getText(), Toast.LENGTH_SHORT).show();
        }
    }

    @AIItemClick({R.id.listView})
    public void onItemClickCallbackForListView(AdapterView<?> adapterView, View view, int i, long l){
        Toast.makeText(context, "onItemClickCallbackForListView: " + ((Map<String, String>)adapterView.getAdapter().getItem(i)).get("title"), Toast.LENGTH_SHORT).show();
    }

    @AIItemLongClick(R.id.listView)
    public boolean onItemLongClickCallbackForListView(AdapterView<?> adapterView, View view, int i, long l) {
        Toast.makeText(context, "onItemLongClickCallbackForListView: " + ((Map<String, String>)adapterView.getAdapter().getItem(i)).get("title"), Toast.LENGTH_SHORT).show();
        return true;
    }



}

Fragment中使用:

package com.wangjie.androidinject;

import android.app.AlarmManager;
import android.os.Bundle;
import android.view.View;
import android.widget.*;
import com.wangjie.androidinject.annotation.annotations.*;
import com.wangjie.androidinject.annotation.present.AISupportFragment;
import com.wangjie.androidinject.model.Person;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created with IntelliJ IDEA.
 * Author: wangjie  email:wangjie@cyyun.com
 * Date: 13-12-4
 * Time: 下午4:37
 */
@AILayout(R.layout.fragment_a)
public class FragmentA extends AISupportFragment{

    @AIView
    private Button fragmentABtn1;

    @AIView
    private GridView fragmentGv;

    @AIBean
    private Person person;

    @AISystemService
    private AlarmManager alarmManager;

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        List<Map<String, String>> list = new ArrayList<Map<String, String>>();
        Map<String, String> map;
        for(int i = 0; i < 10; i++){
            map = new HashMap<String, String>();
            map.put("title", "fragment_item_" + i);
            list.add(map);
        }

        SimpleAdapter adapter = new SimpleAdapter(context, list, R.layout.list_item, new String[]{"title"}, new int[]{R.id.list_item_title_tv});
        fragmentGv.setAdapter(adapter);

        person.setName("androidInject");
        person.setAge(1);
        System.out.println(person.toString());

        System.out.println("alarmManager: " + alarmManager);

    }

    @AIClick(R.id.fragmentABtn1)
    private void btnOnclick(View view){
        if(view instanceof Button){
            Toast.makeText(context, "btnOnclick: " + ((Button)view).getText(), Toast.LENGTH_SHORT).show();
        }
    }

    @AILongClick(R.id.fragmentABtn1)
    private void btnOnLongClick(View view){
        if(view instanceof Button){
            Toast.makeText(context, "btnOnLongClick: " + ((Button)view).getText(), Toast.LENGTH_SHORT).show();
        }
    }

    @AIItemClick(R.id.fragmentGv)
    private void gvOnItemClick(AdapterView<?> adapterView, View view, int i, long l){
        Toast.makeText(context, "gvOnItemClick: " + ((Map<String, String>)adapterView.getAdapter().getItem(i)).get("title"), Toast.LENGTH_SHORT).show();
    }

    @AIItemLongClick(R.id.fragmentGv)
    private void gvOnItemLongClick(AdapterView<?> adapterView, View view, int i, long l){
        Toast.makeText(context, "gvOnItemLongClick: " + ((Map<String, String>)adapterView.getAdapter().getItem(i)).get("title"), Toast.LENGTH_SHORT).show();
    }


}

具体注解如下:

@AINoTitle: 类注解, 只适用于Activity(需继承于AIActivity), 设置Activity不显示Title

@AIFullScreen: 类注解, 只适用于Activity(需继承于AIActivity), 设置Activity全屏

@AILayout: 类注解
value[int]: 用于设置该Activity的布局 —- setContentView(resId);

@AIView: 属性注解
id[int]: 用于绑定控件 —- findViewById(resId);(default identifier[R.id.{field name}] if did not set id)
clickMethod[String]: 用于设置控件点击事件的回调方法, 可选, 方法名称任意, 参数必须为(View view)
longClickMethod[String]: 用于设置控件长按的回调方法, 可选, 方法名任意, 参数必须为(View view)
itemClickMethod[String]: 用于设置控件item点击的回调方法, 可选, 方法名任意, 参数必须为(AdapterView, View, int, long)
itemLongClickMethod[String]: 用于设置控件item长按的回调方法, 可选, 方法名任意, 参数必须为(AdapterView, View, int, long)

@AIBean: 属性注解, 为该属性生成一个对象并注入, 该对象必须有个默认的不带参数的构造方法

@AISystemService: 属性注解,为该属性注入系统服务对象

@AIClick: 方法注解
value[int[], 所要绑定控件的id]: 用于绑定控件点击事件的回调方法, 方法名称任意, 参数必须为(View view)

@AIItemClick: 方法注解
value[int[], 所要绑定控件的id]: 用于绑定控件item点击事件的回调方法, 方法名称任意, 参数必须为(AdapterView, View, int, long)

@AILongClick: 方法注解
value[int[], 所要绑定控件的id]: 用于绑定控件长按事件的回调方法, 方法名称任意, 参数必须为(View view)

@AIItemLongClick: 方法注解
value[int[], 所要绑定控件的id]: 用于绑定控件item长按事件的回调方法, 方法名称任意, 参数必须为(AdapterView, View, int, long)

[转载]简单配置vps,防ddos攻击 - -Neil - 博客园

mikel阅读(910)

[转载]简单配置vps,防ddos攻击 – -Neil – 博客园.

防人之心不可无。 网上总有些无聊或者有意的人。不多说了。上干货,配置vps apf防小流量ddos攻击。

对于大流量的ddos攻击, 需要机房的硬件防火墙,vps内部可能也扛不住。

1. 安装 DDoS deflate

DDoS deflate的原理是通过netstat命令找出 发出过量连接的单个IP,并使用iptables防火墙将这些IP进行拒绝。由于iptables防火墙拒绝IP的连接远比从Apache层面上来得高 效,因此iptables便成了运行在Apache前端的“过滤器”。同样的,DDoS deflate也可以设置采用APF(高级防火墙)进行IP阻止。

 

1
2
3
wget http://www.inetbase.com/scripts/ddos/install.sh
chmod +x install.sh
./install.sh
主要功能与配置

1、可以设置IP白名单,在 /usr/local/ddos/ignore.ip.list 中设置即可;

2、主要配置文件位于 /usr/local/ddos/ddos.conf ,打开此文件,根据提示进行简单的编辑即可;

3、DDoS deflate可以在阻止某一IP后,隔一段预置的时候自动对其解封;

4、可以在配置文件中设置多长时间检查一次网络连接情况;

5、当阻止IP后,可以设置Email提醒

简单配置一下:

1
2
3
4
5
6
7
8
9
10
FREQ=1 #检测的频率为1分钟
NO_OF_CONNECTIONS=100 #当单个IP超过100个连接请求时判定为DDOS
APF_BAN=1 #如果打算使用APF阻止IP,则设置为1(需要预先安装APF);如果使用iptables,则设置为0;
KILL=1 #是否阻止
EMAIL_TO="webmaster@firstVM.com" #接收邮件
BAN_PERIOD=600 #阻止时长,10分钟

 

2. 安装配置apf。

APF(Advanced Policy Firewall)是 Rf-x Networks 出品的Linux环境下的软件防火墙,被大部分Linux服务器管理员所采用,使用iptables的规则,易于理解及使用。

适合对iptables不是很熟悉的人使用,因为它的安装配置比较简单,但是功能还是非常强大的。

脚本安装:

1
2
3
4
root@linux:/home/zhangy# tar -xvzf apf-current.tar.gz 
root@linux:/home/zhangy# cd apf-9.7-1 
root@linux:/home/zhangy/apf-9.7-1# ./install.sh

ubuntu 可以快速安装:

1
sudo aptitude install apf-firewall

 

配置:

1
vi /etc/apf/conf.apf

 

往后翻页,找到:

1
2
3
4
5
6
7
8
9
10
11
12
# Configure inbound (ingress) accepted services. This is an optional
# feature; services and customized entries may be made directly to an ip's
# virtual net file located in the vnet/ directory. Format is comma separated
# and underscore separator for ranges.
#
# Example:
# IG_TCP_CPORTS="21,22,25,53,80,443,110,143,6000_7000"
# IG_UDP_CPORTS="20,21,53,123"
# IG_ICMP_TYPES="3,5,11,0,30,8"
# Common inbound (ingress) TCP ports
IG_TCP_CPORTS="22"

 

默认只有22端口开放。 我们先不管。 访问以下80端口的网站试试。 发现竟然可以访问。 为什么规则没有起作用。

继续查看配置文件。 找啊找。

这一行引起了我的注意:

1
2
3
4
# Untrusted Network interface(s); all traffic on defined interface will be
# subject to all firewall rules. This should be your internet exposed
# interfaces. Only one interface is accepted for each value.
IFACE_IN="eth0"

突然想到, 会不会是监听端口的问题。

我们知道, 如果是真实服务器或者是 xen虚拟化的vps, 其网卡是 eth*。  例如:

1
ifconfig

image

但是, 我这台vps是openvz虚拟化的。 它的网卡一般是 vnet* 的。 比如:

 

image

 

于是改上面的配置文件:

1
2
3
4
# Untrusted Network interface(s); all traffic on defined interface will be
# subject to all firewall rules. This should be your internet exposed
# interfaces. Only one interface is accepted for each value.
IFACE_IN="venet0"

重启 apf:

1
apf -r

提示说找不到 ip_tables 模块。

ip_tables

apf(4677): {glob} unable to load iptables module (ip_tables), aborting.

image

 

于是搜索:  ubuntu  apf  找到这篇文章

http://davidwinter.me/articles/2011/06/05/install-apf-on-ubuntu-11-04/

 

大致意思是说, 在ubuntu中, iptables默认被编译进了内核, 而不是以模块方式运行的。apf默认是使用模块方式调用iptables。 所以要修改apf的配置:

SET_MONOKERN=”1″

 

然后重启 apf

然后看到一长串的日志:

image

 

看样子是成功了。

试一下, 果然80端口不能访问了。

只有22还在。

 

回到配置文件, 我们把端口开放:

1
vi /etc/apf/conf.apf

找到:

1
2
3
4
5
6
7
8
9
10
11
12
# Configure inbound (ingress) accepted services. This is an optional
# feature; services and customized entries may be made directly to an ip's
# virtual net file located in the vnet/ directory. Format is comma separated
# and underscore separator for ranges.
#
# Example:
# IG_TCP_CPORTS="21,22,25,53,80,443,110,143,6000_7000"
# IG_UDP_CPORTS="20,21,53,123"
# IG_ICMP_TYPES="3,5,11,0,30,8"
# Common inbound (ingress) TCP ports
IG_TCP_CPORTS="22,80,443"

 

保存,重启:  apf –r

 

再访问以下,成功了。

 

最后, 关闭apf的调试模式,正式上线:

找到:

1
2
3
4
# !!! Do not leave set to (1) !!!
# When set to enabled; 5 minute cronjob is set to stop the firewall. Set
# this off (0) when firewall is determined to be operating as desired.
DEVEL_MODE="1"

 

改成 0:

1
2
3
4
# !!! Do not leave set to (1) !!!
# When set to enabled; 5 minute cronjob is set to stop the firewall. Set
# this off (0) when firewall is determined to be operating as desired.
DEVEL_MODE="0"

 

欢迎大家访问我的个人独立博客: http://blog.byneil.com

[转载]java break continue label - taimukang - ITeye技术网站

mikel阅读(1119)

[转载]java break continue label – taimukang – ITeye技术网站.

在java中可以利用break、continue和label控制循环跳转。

一、单重循环

break + label: 结束label后的循环体:

public static void main(String[] args) {
    String o="";
    z:
        for(int x=3;x<8;x++){

            if(x==6) break z;
            o=o+x;
        }
    System.out.println(o);
}

输出:345
continue + label:结束本次循环,继续执行label后的循环体:

public static void main(String[] args) {
    String o ="";
    z:
        for(int x=3;x<8;x++){
            if(x==6) continue z;
            o=o+x;
        }
    System.out.println(o);
}

输出:3457
二、多重循环
break:

public static void main(String[] args) {
        String o = "";
        z:
            for (int i = 0; i < 3; i++) {
                for (int x = 3; x < 8; x++) {
                    if (x == 6) break z;
                    o = o + x;
                }
            }
        System.out.println(o);
}

输出:345
continue:

public static void main(String[] args) {
        String o = "";
        z:
            for (int i = 0; i < 3; i++) {
                for (int x = 3; x < 8; x++) {
                    if (x == 6) continue z;
                    o = o + x;
                }
            }
        System.out.println(o);
}

输出: 345345345
注意与单层循环时输出的区别。

三、 特别注意

label与其后的循环体之间不能有其它的代码,否则在循环体内不能再使用该label(编译错误:The label xxx is missing)

[转载]Android客户端与服务器端通过DES加密认证-Android开发源码下载-eoe Android开发者社区_Android开发论坛 - Powered by Discuz!

mikel阅读(969)

[转载]鉴客 Android客户端与服务器端通过DES加密认证-Android开发源码下载-eoe Android开发者社区_Android开发论坛 – Powered by Discuz!.

由于Android应用没有像web开发中的session机制,所以采用PHPSESSID的方式,是没有办法获取客户端登录状态的。
这种情况下,如何在用户登录后,服务器端获取用户登录状态并保持,就必须采用一种“握手”的方式。
每个手机都有自己的IMEI号,那么能不能通过这个标识去做认证呢?
经过试验,答案是可以!
客户端在请求服务器端的时候,请求参数为 IMEI (param 1)及  IMEI&UA (param 2)经过加密的字符串;服务器端对客户端传递的两个参数进行解密,比对两个IMEI值是否相同。如果相同,返回token给客户端,以后每次客户端请求服 务器端的时候,都携带该token。这样服务器就可以获取用户登录状态了。
这里,我采用的DES加密的方式,由于PHP和Java的DES加密是有差异的,所以单独进行处理:

import java.security.Key;
  import java.security.SecureRandom;
  import java.security.spec.AlgorithmParameterSpec;
     
  import javax.crypto.Cipher;
  import javax.crypto.SecretKeyFactory;
  import javax.crypto.spec.DESKeySpec;
  import javax.crypto.spec.IvParameterSpec;
     
     
  import com.sun.org.apache.xml.internal.security.utils.Base64;
  public class Des2
  {
  public static final String ALGORITHM_DES = "DES/CBC/PKCS5Padding";
     
  /**
  * DES算法,加密
  *
  * @param data 待加密字符串
  * @param key  加密私钥,长度不能够小于8位
  * @return 加密后的字节数组,一般结合Base64编码使用
  * @throws CryptException 异常
  */
  public static String encode(String key,String data) throws Exception
  {
  return encode(key, data。getBytes());
  }
  /**
  * DES算法,加密
  *
  * @param data 待加密字符串
  * @param key  加密私钥,长度不能够小于8位
  * @return 加密后的字节数组,一般结合Base64编码使用
  * @throws CryptException 异常
  */
  public static String encode(String key,byte[] data) throws Exception
  {
  try
  {
  DESKeySpec dks = new DESKeySpec(key.getBytes());
  SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
  //key的长度不能够小于8位字节
  Key secretKey = keyFactory.generateSecret(dks);
  Cipher cipher = Cipher.getInstance(ALGORITHM_DES);
  IvParameterSpec iv = new IvParameterSpec("12345678".getBytes());
  AlgorithmParameterSpec paramSpec = iv;
  cipher.init(Cipher.ENCRYPT_MODE, secretKey,paramSpec);
     
  byte[] bytes = cipher.doFinal(data);
  return Base64.encode(bytes);
  } catch (Exception e)
  {
  throw new Exception(e);
  }
  }
  /**
  * DES算法,解密
  *
  * @param data 待解密字符串
  * @param key  解密私钥,长度不能够小于8位
  * @return 解密后的字节数组
  * @throws Exception 异常
  */
  public static byte[] decode(String key,byte[] data) throws Exception
  {
  try
  {
  SecureRandom sr = new SecureRandom();
  DESKeySpec dks = new DESKeySpec(key.getBytes());
  SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
  //key的长度不能够小于8位字节
  Key secretKey = keyFactory.generateSecret(dks);
  Cipher cipher = Cipher.getInstance(ALGORITHM_DES);
  IvParameterSpec iv = new IvParameterSpec("12345678"。getBytes());
  AlgorithmParameterSpec paramSpec = iv;
  cipher.init(Cipher.DECRYPT_MODE, secretKey,paramSpec);
  return cipher.doFinal(data);
  } catch (Exception e)
  {
  throw new Exception(e);
  }
  }
  /**
  * 获取编码后的值
  * @param key
  * @param data
  * @return
  * @throws Exception
  */
  public static String decodeValue(String key,String data)
  {
  byte[] datas;
  String value = null;
  try {
  if(System.getProperty("os.name") != null && (System.getProperty("os.name").equalsIgnoreCase("sunos") || System.getProperty("os.name").equalsIgnoreCase("linux")))
  {
  datas = decode(key, Base64.decode(data));
  }
  else
  {
  datas = decode(key, Base64.decode(data));
  }
     
  value = new String(datas);
  } catch (Exception e) {
  value = "";
  }
  return value;
  }
     
  /**
  * test
  * @param key : 12345678
  */
  public static void main(String[] args) throws Exception
  {
     
  System.out.println("明:cychai ;密:" + Des2.encode("12345678","cychai"));
  }
  }

服务器端PHP:

  class DES
  {
  var $key;
  var $iv; //偏移量
     
  function DES($key, $iv=0)
  {
  $this->key = $key;
  if($iv == 0)
  {
  $this->iv = $key;
  }
  else
  {
  $this->iv = $iv;
  }
  }
  
  //加密
  function encrypt($str)
  {
  $size = mcrypt_get_block_size ( MCRYPT_DES, MCRYPT_MODE_CBC );
  $str = $this->pkcs5Pad ( $str, $size );
     
  $data=mcrypt_cbc(MCRYPT_DES, $this->key, $str, MCRYPT_ENCRYPT, $this->iv);
  //$data=strtoupper(bin2hex($data)); //返回大写十六进制字符串
  return base64_encode($data);
  }
  //解密
  function decrypt($str)
  {
  $str = base64_decode ($str);
  //$strBin = $this->hex2bin( strtolower($str));
  $str = mcrypt_cbc(MCRYPT_DES, $this->key, $str, MCRYPT_DECRYPT, $this->iv );
  $str = $this->pkcs5Unpad( $str );
  return $str;
  }
     
  function hex2bin($hexData)
  {
  $binData = "";
  for($i = 0; $i < strlen ( $hexData ); $i += 2)
  {
  $binData .= chr(hexdec(substr($hexData, $i, 2)));
  }
  return $binData;
  }
     
  function pkcs5Pad($text, $blocksize)
  {
  $pad = $blocksize - (strlen ( $text ) % $blocksize);
  return $text .str_repeat ( chr ( $pad ), $pad );
  }
     
  function pkcs5Unpad($text)
  {
  $pad = ord ( $text {strlen ( $text ) - 1} );
  if ($pad > strlen ( $text ))
  return false;
  if (strspn ( $text, chr ( $pad ), strlen ( $text ) - $pad ) != $pad)
  return false;
  return substr ( $text, 0, - 1 * $pad );
  }
  }
  $str = 'abc';
  $key= '12345678';
  $crypt = new DES($key);
  $mstr = $crypt->encrypt($str);
  $str = $crypt->decrypt($mstr);
     
  echo  $str.' <=> '.$mstr;

需要注意的是: 加密的key必须为8位或者8的倍数,否则在java加密过程中会报错。

[转载]好的用户界面-界面设计的一些技巧 - Wayou - 博客园

mikel阅读(746)

[转载]好的用户界面-界面设计的一些技巧 – Wayou – 博客园.

 

如此有用的文章我已记不得是什么时候发现的了,但在看完的那一刻便想将之翻译,分享给大家自己也受用。

时间过了很久,来到了2014年,终于静下心来花了大把时间连同图片一起译成了中文。像我这样业余的翻译六级分数只够及格的程序员,不敢说做到信雅达,但求意思到位。

 

1 尽量使用单列而不是多列布局

单列布局能够让对全局有更好的掌控。同时用户也可以一目了然内容。而多列而已则会有分散用户注意力的风险使你的主旨无法很好表达。最好的做法是用一个有逻辑的叙述来引导用户并且在文末给出你的操作按钮。

 

2 放出礼品往往更具诱惑力

给用户一份精美小礼品这样的友好举动再好不过了。具体来讲,送出礼品也是之有效的获得客户忠诚度的战术,这是建立在人们互惠准则上的。而这样做所带来的好处也是显而易见的,会让你在往后的活动进展(不管是推销,产品更新还是再次搞活动)中更加顺利。

 

3 合并重复的功能而使界面简洁

在整个产品开发期间我们会有意无意地创建很多模块,版面或者元素,而它们的功能都是相近的。此种情况已经表明过度设计了。时刻警惕这些冗余的功能模块,它无用且降低了电脑性能。此外,界面上模块越多,用户的学习成本就越大。所以请考虑重构你的界面使它足够精简。

 

4 客户的评价好过自吹自擂

在获得项目机会或提高项目转化率时客户的好评是一种极为有效的手段。当潜在客户看到其他人对你的服务给予好评时,项目机会会大增。所以试着提供一些含金量高的证据证明这些好评是真实可信的。

 

5 频繁展示你的主旨来加深印象

多次重复主旨口号这种方法适用于界面很长或者分页的情况。首先你肯定不想满屏刷出相同的信息,这样会让人生厌。但当页面足够长的时候这些重复就显示 自然多了并且也不显得拥挤。所在在页面顶部放一个按钮然后在页面底部再适当放个突出的按钮的做法没有什么不妥。这样当用户到达页面底部在思考接下来该做什 么的时候,你提供的按钮就可以获得一个潜在的合同或者即使用户不需要你的服务这个按钮也可以起到过滤的作用。

 

6 将选项与按钮区分开来

诸如颜色,层次及模块间的对比这些视觉上的设计可以很好地帮助用户使用产品:他时刻知道当前所处的页面以及可以转到哪些页面。要传达这样一个好的界 面,你就需要将可点击的元素(比如连接,按钮),可选择的元素(比如单选多选框)以及普通的文字明显区分开来。在下图的例子中,我将点击操作的元素设置为 蓝色,选中的当前元素为黑色。这样适当的设计可以让用户很方面地在产品的各模块间切换。但千万不要把这三种元素设计得混乱不堪。

 

7 给出推荐而不是让用户来选择

当展示许多项服务时,给出一个重磅的推荐项是个不错的做法,尽管推荐的设置无法满足所有用户。这么做是有理论依据的,一些研究已经揭示了这么一种现象:当面临的选择越多时,用户就越难做出决定。所以你可以高亮某个选项来帮助用户做出选择。

 

8 给出撤销操作来代替确定操作

假设你刚点击了一个连接或者按钮,撤销操作可以让操作流畅自然,这也符合人类的本能。而每次操作都弹一个确定框则好像是在质问用户你明白不明白这个 操作会产生什么后果。我还是更习惯假设用户每次操作都是正确的,其实只有极少数情况下才会发生误操作。所以,为了防止误操作而设计的确认窗口其实是不人性 化的,用户每次操作都需要进行毫无意义的确定。所以请考虑在你的产品里实现撤销操作来增加用户的操作友好度吧。

 

9 指出产品适用人群而不是做成全年龄

你是想把产品做成大众化的呢还是有精确的适用人群?在产品定位上你需要更精确些。通过不断了解目标客户的需求及标准,你能把产品做得更好得到更多与 客户交流的机会,并且让客户觉得你很专业,在这方面是独家提供的优质服务。把产品定位得精确的风险就是可能缩小了目标潜在客户的范围,也使自身变得不那么 全能。但这种做得更专业的精神却反过来会赢得信任,权威。

(贴士:喜欢下图中可爱的小人物造型么?去了解MicroPersonas吧)

 

10 试着直接果断而不要唯唯诺诺

你可以通过不确定而颤抖的声音来表达传递自己的意思,当然也可以通过很自信的方式表达。如果你在界面中的表述用语多以问号结束,比如”也许”,”可 能”,”感兴趣?” 或者”想要试试么?”,那么你完全还可以把语气变得更坚定一些。不过万事无绝对,或许适当放松措词让用户有自行思考的余地也是可以的。

 

11 界面要有鲜明对比让人容易区分

把主要功能区从界面中突出显示出来效果会好很多。使你的主要口号醒目有很多种方法。通过明暗色调的对比来突显。通过为元素添加阴影渐变等效果让界面 富有层次感来张显主题。最后,你甚至可以在色相环上专门选择互补色(比如黄色与紫色)来设计你的界面,以达到突出重心的目的。综合所有这些,最后得到的界 面会使你的主要意图与界面其他元素有明显的区分,得到完美的呈现。

 

12 指明产地

指明你的地区,所提供的服务,产品来自哪里意义重大,同时也将与客户的沟通引入了一个更具体带有地域特色的场景中。指出具体来自哪里,国家,省分及 城市,也是一种在进行自我介绍或产品展示时被常常提及的。当你在界面设计中实现这点时,让人觉得非常友好。同时指明区域也会隐形提高产品的声誉,好上加 好。

 

13 精简表单内容

人生性就懒惰,在填写表单时也是同样的道理,没人愿意填写一大堆表单字段。表单中每个字段都会有失去用户的风险。不是每个人打字都很快速的,并且在 移动设备上进行输入更是相当麻烦的事情。问下自己表单中是不是每个字段都必需,然后尽量减少表单中的字段。如果你确实需要一大堆信息让用户填写,试着将它 们分散在不同页面,在表单提交后还可以继续补充。过多字段很容易让整个表单显示臃肿,当然想简洁也很容易,只放少数字段。

 

14 暴露选项而不要将操作隐藏

你使用的任何一个下拉框都会对用户造成信息的隐藏而需要额外的操作才能显示。如果这些信息是贯穿整个操作所必需的,那你最好把它展示出来做得更显而易见一点。下拉框最好用在选择日期,省份等约定俗成的地方。对于程序中重要的选项最好还是不要做成下拉形式。

 

15 把界面做得环环相扣要好过直白的排版

一个平淡无奇行文无疑会让用户失去兴趣而继续阅读。是的,单列滚动的长页面是不错的,但是我们应该适当地设置一些小节,并且环环相扣,来提高用户的兴趣使其继续阅读。但需要注意的是节与节之间的留白不要太大。

 

16 不要放太多链接分散用户注意力

为了满足各式用户的需求,在页面上放些链接链到这里链到那里是常见的做法。如果你的主要目的是想让用户点击页面最后那个下载按扭什么的话,就需要三 思了。因为用户可能点击了其他链接离开页面了。所以你需要注意页面的链接数量,最好将用于导航与用于操作的链接用样式区分开。尽量移除页面不需要的链接会 让用户点击到你的功能按钮。

 

17 将操作的状态或者进度呈现出来

现如今大多界面当中已经呈现了各色样式的进度条或者标明状态的图标,比如邮件有已读或未读的状态,电子帐单有支付或未支付的状态。而在界面上呈现这样的状态对于用户来说是很有必要的。这样用户就可以知道某些操作是否成功,接下来准备进行怎样的操作。

 

18 不要让用户觉得是在完成任务

试想界面上有这样两个按钮:一个是”获取折扣”,另一个是”立即注册”。我敢打赌大多数人会点击第一个,因为第二个按扭让人感觉不到有利可图,并 且”注册”让人联想到填不完的表单。也就是说让用户感受到获利的按钮更有可能被点击。这种让用户感到好处的文字信息也可是放在按钮旁边,不一定要做为按钮 的标题。当然,正常的按钮还是有用处的,一般用于重复性操作频繁的地方。

 

19 让操作直观而不是让人觉得找不到上下文

不用说直接在元素身上进行操作是更直观明了的方式。比如在一个列表中,我们想让用户对每个条目进行操作那么就把按钮放到当前条目上,而不要把放到列 表之外。再比如就是直接点击元素就进入编辑状态(比如页面上的地址信息点击后可以进行编辑)。这种方式比传统的选中再点击相应的按钮进行操作要简洁省事得 多。当然,对于一般性的操作本身就不需要有什么上下文的,就没必要这么做了,比如页面上的前进,后退按扭。

20 尽量显示全部内容而不要额外页面

在一个足够大的宽屏界面上最好还是直接给出表单,这比点击按钮再弹出表单要好很多。首先减少了点击操作,流程变得简洁也节省了时间。其次,直接呈现出表单可以让用户知道表单有多长,其实也是在告诉用户注册花不了多少时间。当然,这条规则适合注册表单非常简单的情况。

 

21 让界面平滑显示而不要死板地呈现

用户进行操作过程中,界面上的元素会经常出现,隐藏,打开,关闭,放大缩小移位等。给这些元素增加些自然的动画,淡入淡出效果不但美观,也更符合实 际,本来元素尺寸位置的变化就是一个需要时间的动画过程。但要注意动画时间不要设置过长,那样会让想尽快完成操作的用户不耐烦。

22 循序渐进的引导而不要直接让用户注册

与其让用户马上注册,何不让用户先进行一些体验式的操作呢。这个体验过程可以展示程序的功能,特性等。一旦用户通过简单几步的操作了解了程序的价值 所在,那么它会更愿意填写注册表单的。这种循序渐进的引导可以尽量推迟用户注册的时间但又可以让用户在没注册的情况下进行个性化设置等简单操作。

23 过多边框会让界面四分五裂

过程边框会喧宾夺主。不用说,边框确实在划分区域进行版块设置时有很大的作用,但同时其明显的线条也会吸引走用户的注意力。为了达到划分版块又不转 移用户注意力的目的,在排版时可以将界面上不同区域的元素通过空白进行分组,用上不同的背景色,将文字对齐方式进行统一,还有就是为不同区域设置不同的样 式。当使用所见即所得的界面设计工具时,我们经常在界面上方便地拖出很多区块来,这些区块多了就会显得杂乱无章。所以我们又会到处放些横线来分界。一个更 好的做法是将区块垂直对齐,这样做不会让那些多余的线条来扰乱视觉。

 

24 展示产品带来的好处而不要罗列产品特性

市场就是这样的,用户永远只关心自身利益而产品特性对他们来说倒不是那么重要。只有利益才更直观地体现出使用产品所带来的价值。Chris Guillebeau在他的著作《100美元起家》中指出,相比压力,冲突,烦心事和未知的未来,人们在乎得更多的是爱,金钱,认同感和自由支配的空闲时 间。所以我相信在展示产品特性时回归到利益上是必要的。

 

25 不要把产品设计得过于依赖于数据

界面上经常需要呈现不同数量的数据,从0,1,10,100到10000+等。这里存在个普遍的问题就是:在程序最开始使用的0条数据到过度到有数 据之前,该如何进行显示界面。这也是我们经常忽视了的地方。当程序初始没有数据时,用户看到的就是一片空白,此时用户可能不知道该进行哪些操作。利用好没 有数据的初始界面可以让用户学习和熟悉如何使用程序,在程序中创建数据。力臻完美永远是我们追求的目标,界面设计也不例外。

 

26 默认将用户引入

将界面做成默认用户选中想要使用你的产品,意味首如果用户真的需要使用,那么可以直接点击确定而不需要额外点选了。当然,也有另一种做法就是默认不 选中服务,用户需要的话可以手动点选。前者这种设计更好的原因有两点。一是用户不需要额外点选,非常省事,因为默认设置为用户需要我们的产品或服务。二是 这种做法某种程度上是在向用户推荐产品,暗示了其他人都选择了我们。当然,将界面设计成默认选择的样子多少存在点争议,有点强迫用户的感觉。如果你想道德 一点,你可以要么把让用户选择的文字写得模棱两可,要么使用双重否定这样不那么直白的描述,这两种方式都可以让用户觉得没有那么强的感觉是被强迫选择使用 产品的。

 

27 界面设计得一致,不要增加用户的学习成本

自从Donald Norman的一系列著作面世后,界面设计中尽量保持一致性成了一个普遍遵循的准则。在设计中保持一致性可以减少用户的学习成本,用户不需要学习新的操 作。当我们点击按钮,或者进行拖拽操作,我们期望这样的操作在整个程序的各个界面都是一致的,会得到相似的结果出来。反之我们需要新情境下重新学习某种操 作会产生何种结果。可以在很多方面下功夫来实现一个一致的界面,包括颜色,方向,元素的表现形式,位置,大小,形状等。不过在让界面变得一致之前,记住一 点,适当的打破整体的一致性也是可取的。这偶尔的不一致性的设计用在你需要强调的地方可以起到很大的作用。所以世事无绝对,我们应遵从一致的设计准则,但 适当地打破这种常规。

 

28 使用较贴切的默认值会减少操作

适当的默认值和预先填充好的表单字段可以大量减少用户的工作量。在节省用户宝贵的时间上面,这是种非常常见的做法,可以帮助用户快速填完表单或者注册信息。

 

29 遵从一些约定而不要去重新设计

界面设计中约定俗成的东西跟之前的界面一致性很相似。如果我们遵从了界面中一愣的约定,用户用起来会很方便。相反,不一致和没有遵从约定的设计则会 提高学习成本。有了界面设计中这些约定,我们想都不用想就知道界面右上角(大多数情况下)的叉叉是关闭程序用的,或者点击一个按钮后我们能够预测到将会发 生什么。当然,约定是会过时的,随着时间的推移,同样的操作也有可能被赋予新的含义。但要记住,当你在界面中打破这些常规时一定要目的明确,并且出发点是 好的。

 

30 让用户觉得可以避免失去而不是获得

我们喜欢成功,没有谁愿意失败。根据心理学得到的可靠结论,人们一般更顷向于避免失去拥有的东西而不是获得新的利益。这一结论也适用于产品的设计和 推广中。试着说明你的产品会帮助客户维护他的利益,保持健康,社会地位等要好过告诉客户这个产品会带来一些他未曾拥有的东西。比如保险公司,它是在销售我 们出事之后可以得到的大笔赔偿呢还是在强调可以帮助我们避免失去拥有的财产?

 

31 具有层次的图形化展示优于直白的文字描述

具有层次的设计可以将界面上重要的部分与不次要部分区分开来。要让界面层次分明,可以在这些方面做文章:对齐方式,间距,颜色,缩进,字体大小,元 素尺寸等。当所有这些调整运用得适当时,可以提高整个界面的可读性。相比在一个很直白的界面上用户一眼就可以从上瞟到底的设计,这样分明的设计也可以让用 户放慢速度来慢慢阅读。这样也使界面更有特色一些。就好比一次旅行,你可以乘坐高铁快速到达景区(从页面顶部瞟到底部),但你也可以慢行以欣赏沿途风光。 所以层次分明的设计让眼睛有可以停留的地方,而不是对着空白单调的一个屏幕。

32 将有关联的功能分组而不是杂乱无章

将各个功能项分组合并起来可以提高程序的可用性。有点常识的人都知道刀子和叉子,或者打开文件和关闭文件是放在一起的。将功能相近的元素放在一起也符合逻辑,符合我们平时的认知。

 

33 使用内联的验证消息而不是提交后再验证

在处理表单时,最好立即检测出用户所填写内容是否符合要求然后给出验证消息。这样错误一出现能就能得到改正。相反,提交后再检查表单会给出错误消息,会让用户感到乏力又要重复之前的工作。

34 放宽对用户输入的要求

对用户输入的数据,尽量放宽限制,包括格式,大小写什么的。这样做可以更人性化一点,也使得界面更加友好。一个再恬当不过的例子就是让用户输入电话 号码的时候,用户有很多种输入方式,带括号的,带破折号的,带空格的,带区号和不带区号的等等。如果你在代码中来处理这些格式的问题,代价也只是你一个人 多写几行代码而以,却可以减少无数用户的工作量。

35 让用户感觉需要快速做出响应而不是毫无时间观念

适当的紧迫感是个有效的战术可以让用户立即做出决定而不是等上个十天半个月。重要的是这种战术屡试不爽,因为它暗示了资源的紧缺或者活动的时间有 限,今天可以买,但明天可能就无法这么低价了。另一方面,这一战术也让用户感到会错失一次大好的机会,再一次,应用了人们害怕失去的本性。当然,这种战术 会被一些人嗤之以鼻,认为是不耿直的做法。不过,这只是种战术而以,并且在保持合法性的前提下应用也无伤大雅。所以请不要为了营销而在界面上制造紧迫的假 象。

 

36 使用饥饿营销

物以稀为贵。饥饿营销给出的信息就是东西不多,只剩几件,明天再来,可能没了。你去比较一下批发与限量版的东西他们的价格差距有多大就知道了。回过 头来看,那些批发商或者大零售商,他们也使用饥饿营销,以获得更好的销量。但在软件行业,我们经常会忘记有饥饿营销这回事。因为数字产品是可以很容易考贝 复制的,不存在缺货的情况。其实,在界面设计中,也可以将其运用起来与现实中的资源紧缺进行联系。想想一次网上研讨会的门票,想想你一个月可以服务的人数 限制,这些信息都可以告知用户是有限的。

 

37 让用户选择而不是重新填写

这一界面设计中的经典准则是有心理学依据的,相比要让某人回想想某样东西,从一堆东西中认出某样东西会更容易些。辨识出一样东西只需要我们稍微回忆 一下,通过一些线索就可以完成。而回想则需要我们全面搜索自己的大脑。也许这也是为什么试卷上选择题会比简答题做得快的原因。所以试着在界面上展示一些用 户之前涉及到的信息让他们进行选择,而不是让他们想半天然后自己填写。

 

原文地址:http://goodui.org

并且还在不断更新中。。。

[转载]asp MD5加密(16位、32位)代码 - 李俊良的日志 - 网易博客

mikel阅读(813)

[转载]asp MD5加密(16位、32位)代码 – 李俊良的日志 – 网易博客.

<%
Private Const Bit2Byt = 8
Private Const Byt2Wor = 4
Private Const Bit2Wor = 32

Private MBit(30)
Private MPow(30)

Private Function LShift(lValue, iShiftBits)
      If iShiftBits = 0 Then
          LShift = lValue
          Exit Function
      ElseIf iShiftBits = 31 Then
          If lValue And 1 Then
              LShift = &H80000000
          Else
              LShift = 0
          End If
          Exit Function
      ElseIf iShiftBits < 0 Or iShiftBits > 31 Then
          Err.Raise 6
      End If

      If (lValue And MPow(31 - iShiftBits)) Then
          LShift = ((lValue And MBit(31 - (iShiftBits + 1))) * MPow(iShiftBits)) Or &H80000000
      Else
          LShift = ((lValue And MBit(31 - iShiftBits)) * MPow(iShiftBits))
      End If
End Function

Private Function RShift(lValue, iShiftBits)
      If iShiftBits = 0 Then
          RShift = lValue
          Exit Function
      ElseIf iShiftBits = 31 Then
          If lValue And &H80000000 Then
              RShift = 1
          Else
              RShift = 0
          End If
          Exit Function
      ElseIf iShiftBits < 0 Or iShiftBits > 31 Then
          Err.Raise 6
      End If
   
      RShift = (lValue And &H7FFFFFFE) \ MPow(iShiftBits)

      If (lValue And &H80000000) Then
          RShift = (RShift Or (&H40000000 \ MPow(iShiftBits - 1)))
      End If
End Function

Private Function RotateLeft(lValue, iShiftBits)
      RotateLeft = LShift(lValue, iShiftBits) Or RShift(lValue, (32 - iShiftBits))
End Function

Private Function AddUnsigned(lX, lY)
      Dim lX4
      Dim lY4
      Dim lX8
      Dim lY8
      Dim lResult

      lX8 = lX And &H80000000
      lY8 = lY And &H80000000
      lX4 = lX And &H40000000
      lY4 = lY And &H40000000

      lResult = (lX And &H3FFFFFFF) + (lY And &H3FFFFFFF)

      If lX4 And lY4 Then
          lResult = lResult Xor &H80000000 Xor lX8 Xor lY8
      ElseIf lX4 Or lY4 Then
          If lResult And &H40000000 Then
              lResult = lResult Xor &HC0000000 Xor lX8 Xor lY8
          Else
              lResult = lResult Xor &H40000000 Xor lX8 Xor lY8
          End If
      Else
          lResult = lResult Xor lX8 Xor lY8
      End If

      AddUnsigned = lResult
End Function

Private Function md5_F(x, y, z)
      md5_F = (x And y) Or ((Not x) And z)
End Function

Private Function md5_G(x, y, z)
      md5_G = (x And z) Or (y And (Not z))
End Function

Private Function md5_H(x, y, z)
      md5_H = (x Xor y Xor z)
End Function

Private Function md5_I(x, y, z)
      md5_I = (y Xor (x Or (Not z)))
End Function

Private Sub md5_FF(a, b, c, d, x, s, ac)
      a = AddUnsigned(a, AddUnsigned(AddUnsigned(md5_F(b, c, d), x), ac))
      a = RotateLeft(a, s)
      a = AddUnsigned(a, b)
End Sub

Private Sub md5_GG(a, b, c, d, x, s, ac)
      a = AddUnsigned(a, AddUnsigned(AddUnsigned(md5_G(b, c, d), x), ac))
      a = RotateLeft(a, s)
      a = AddUnsigned(a, b)
End Sub

Private Sub md5_HH(a, b, c, d, x, s, ac)
      a = AddUnsigned(a, AddUnsigned(AddUnsigned(md5_H(b, c, d), x), ac))
      a = RotateLeft(a, s)
      a = AddUnsigned(a, b)
End Sub

Private Sub md5_II(a, b, c, d, x, s, ac)
      a = AddUnsigned(a, AddUnsigned(AddUnsigned(md5_I(b, c, d), x), ac))
      a = RotateLeft(a, s)
      a = AddUnsigned(a, b)
End Sub

Private Function ConvertToWordArray(AsaiWord)
      Dim lMessageLength
      Dim lNumberOfWords
      Dim lWordArray()
      Dim lBytePosition
      Dim lByteCount
      Dim lWordCount
   
      Const MODULUS_BITS = 512
      Const CONGRUENT_BITS = 448
   
      lMessageLength = Len(AsaiWord)
   
      lNumberOfWords = (((lMessageLength + ((MODULUS_BITS - CONGRUENT_BITS) \ Bit2Byt)) \ (MODULUS_BITS \ Bit2Byt)) + 1) * (MODULUS_BITS \ Bit2Wor)
      ReDim lWordArray(lNumberOfWords - 1)
   
      lBytePosition = 0
      lByteCount = 0
      Do Until lByteCount >= lMessageLength
          lWordCount = lByteCount \ Byt2Wor
          lBytePosition = (lByteCount Mod Byt2Wor) * Bit2Byt
          lWordArray(lWordCount) = lWordArray(lWordCount) Or LShift(Asc(Mid(AsaiWord, lByteCount + 1, 1)), lBytePosition)
          lByteCount = lByteCount + 1
      Loop

      lWordCount = lByteCount \ Byt2Wor
      lBytePosition = (lByteCount Mod Byt2Wor) * Bit2Byt

      lWordArray(lWordCount) = lWordArray(lWordCount) Or LShift(&H80, lBytePosition)

      lWordArray(lNumberOfWords - 2) = LShift(lMessageLength, 3)
      lWordArray(lNumberOfWords - 1) = RShift(lMessageLength, 29)
   
      ConvertToWordArray = lWordArray
End Function

Private Function WordToHex(lValue)
      Dim lByte
      Dim lCount
   
      For lCount = 0 To 3
          lByte = RShift(lValue, lCount * Bit2Byt) And MBit(Bit2Byt - 1)
          WordToHex = WordToHex & Right("0" & Hex(lByte), 2)
      Next
End Function

Public Function MD5(AsaiWord,DTy)
      MBit(0) = CLng(1)
      MBit(1) = CLng(3)
      MBit(2) = CLng(7)
      MBit(3) = CLng(15)
      MBit(4) = CLng(31)
      MBit(5) = CLng(63)
      MBit(6) = CLng(127)
      MBit(7) = CLng(255)
      MBit(8) = CLng(511)
      MBit(9) = CLng(1023)
      MBit(10) = CLng(2047)
      MBit(11) = CLng(4095)
      MBit(12) = CLng(8191)
      MBit(13) = CLng(16383)
      MBit(14) = CLng(32767)
      MBit(15) = CLng(65535)
      MBit(16) = CLng(131071)
      MBit(17) = CLng(262143)
      MBit(18) = CLng(524287)
      MBit(19) = CLng(1048575)
      MBit(20) = CLng(2097151)
      MBit(21) = CLng(4194303)
      MBit(22) = CLng(8388607)
      MBit(23) = CLng(16777215)
      MBit(24) = CLng(33554431)
      MBit(25) = CLng(67108863)
      MBit(26) = CLng(134217727)
      MBit(27) = CLng(268435455)
      MBit(28) = CLng(536870911)
      MBit(29) = CLng(1073741823)
      MBit(30) = CLng(2147483647)
   
      MPow(0) = CLng(1)
      MPow(1) = CLng(2)
      MPow(2) = CLng(4)
      MPow(3) = CLng(8)
      MPow(4) = CLng(16)
      MPow(5) = CLng(32)
      MPow(6) = CLng(64)
      MPow(7) = CLng(128)
      MPow(8) = CLng(256)
      MPow(9) = CLng(512)
      MPow(10) = CLng(1024)
      MPow(11) = CLng(2048)
      MPow(12) = CLng(4096)
      MPow(13) = CLng(8192)
      MPow(14) = CLng(16384)
      MPow(15) = CLng(32768)
      MPow(16) = CLng(65536)
      MPow(17) = CLng(131072)
      MPow(18) = CLng(262144)
      MPow(19) = CLng(524288)
      MPow(20) = CLng(1048576)
      MPow(21) = CLng(2097152)
      MPow(22) = CLng(4194304)
      MPow(23) = CLng(8388608)
      MPow(24) = CLng(16777216)
      MPow(25) = CLng(33554432)
      MPow(26) = CLng(67108864)
      MPow(27) = CLng(134217728)
      MPow(28) = CLng(268435456)
      MPow(29) = CLng(536870912)
      MPow(30) = CLng(1073741824)

      Dim x
      Dim k
      Dim AA
      Dim BB
      Dim CC
      Dim DD
      Dim a
      Dim b
      Dim c
      Dim d
   
      Const S11 = 7
      Const S12 = 12
      Const S13 = 17
      Const S14 = 22
      Const S21 = 5
      Const S22 = 9
      Const S23 = 14
      Const S24 = 20
      Const S31 = 4
      Const S32 = 11
      Const S33 = 16
      Const S34 = 23
      Const S41 = 6
      Const S42 = 10
      Const S43 = 15
      Const S44 = 21

      x = ConvertToWordArray(AsaiWord)
   
      a = &H67452301
      b = &HEFCDAB89
      c = &H98BADCFE
      d = &H10325476

      For k = 0 To UBound(x) Step 16
          AA = a
          BB = b
          CC = c
          DD = d
   
          md5_FF a, b, c, d, x(k + 0), S11, &HD76AA478
          md5_FF d, a, b, c, x(k + 1), S12, &HE8C7B756
          md5_FF c, d, a, b, x(k + 2), S13, &H242070DB
          md5_FF b, c, d, a, x(k + 3), S14, &HC1BDCEEE
          md5_FF a, b, c, d, x(k + 4), S11, &HF57C0FAF
          md5_FF d, a, b, c, x(k + 5), S12, &H4787C62A
          md5_FF c, d, a, b, x(k + 6), S13, &HA8304613
          md5_FF b, c, d, a, x(k + 7), S14, &HFD469501
          md5_FF a, b, c, d, x(k + 8), S11, &H698098D8
          md5_FF d, a, b, c, x(k + 9), S12, &H8B44F7AF
          md5_FF c, d, a, b, x(k + 10), S13, &HFFFF5BB1
          md5_FF b, c, d, a, x(k + 11), S14, &H895CD7BE
          md5_FF a, b, c, d, x(k + 12), S11, &H6B901122
          md5_FF d, a, b, c, x(k + 13), S12, &HFD987193
          md5_FF c, d, a, b, x(k + 14), S13, &HA679438E
          md5_FF b, c, d, a, x(k + 15), S14, &H49B40821
   
          md5_GG a, b, c, d, x(k + 1), S21, &HF61E2562
          md5_GG d, a, b, c, x(k + 6), S22, &HC040B340
          md5_GG c, d, a, b, x(k + 11), S23, &H265E5A51
          md5_GG b, c, d, a, x(k + 0), S24, &HE9B6C7AA
          md5_GG a, b, c, d, x(k + 5), S21, &HD62F105D
          md5_GG d, a, b, c, x(k + 10), S22, &H2441453
          md5_GG c, d, a, b, x(k + 15), S23, &HD8A1E681
          md5_GG b, c, d, a, x(k + 4), S24, &HE7D3FBC8
          md5_GG a, b, c, d, x(k + 9), S21, &H21E1CDE6
          md5_GG d, a, b, c, x(k + 14), S22, &HC33707D6
          md5_GG c, d, a, b, x(k + 3), S23, &HF4D50D87
          md5_GG b, c, d, a, x(k + 8), S24, &H455A14ED
          md5_GG a, b, c, d, x(k + 13), S21, &HA9E3E905
          md5_GG d, a, b, c, x(k + 2), S22, &HFCEFA3F8
          md5_GG c, d, a, b, x(k + 7), S23, &H676F02D9
          md5_GG b, c, d, a, x(k + 12), S24, &H8D2A4C8A
           
          md5_HH a, b, c, d, x(k + 5), S31, &HFFFA3942
          md5_HH d, a, b, c, x(k + 8), S32, &H8771F681
          md5_HH c, d, a, b, x(k + 11), S33, &H6D9D6122
          md5_HH b, c, d, a, x(k + 14), S34, &HFDE5380C
          md5_HH a, b, c, d, x(k + 1), S31, &HA4BEEA44
          md5_HH d, a, b, c, x(k + 4), S32, &H4BDECFA9
          md5_HH c, d, a, b, x(k + 7), S33, &HF6BB4B60
          md5_HH b, c, d, a, x(k + 10), S34, &HBEBFBC70
          md5_HH a, b, c, d, x(k + 13), S31, &H289B7EC6
          md5_HH d, a, b, c, x(k + 0), S32, &HEAA127FA
          md5_HH c, d, a, b, x(k + 3), S33, &HD4EF3085
          md5_HH b, c, d, a, x(k + 6), S34, &H4881D05
          md5_HH a, b, c, d, x(k + 9), S31, &HD9D4D039
          md5_HH d, a, b, c, x(k + 12), S32, &HE6DB99E5
          md5_HH c, d, a, b, x(k + 15), S33, &H1FA27CF8
          md5_HH b, c, d, a, x(k + 2), S34, &HC4AC5665
   
          md5_II a, b, c, d, x(k + 0), S41, &HF4292244
          md5_II d, a, b, c, x(k + 7), S42, &H432AFF97
          md5_II c, d, a, b, x(k + 14), S43, &HAB9423A7
          md5_II b, c, d, a, x(k + 5), S44, &HFC93A039
          md5_II a, b, c, d, x(k + 12), S41, &H655B59C3
          md5_II d, a, b, c, x(k + 3), S42, &H8F0CCC92
          md5_II c, d, a, b, x(k + 10), S43, &HFFEFF47D
          md5_II b, c, d, a, x(k + 1), S44, &H85845DD1
          md5_II a, b, c, d, x(k + 8), S41, &H6FA87E4F
          md5_II d, a, b, c, x(k + 15), S42, &HFE2CE6E0
          md5_II c, d, a, b, x(k + 6), S43, &HA3014314
          md5_II b, c, d, a, x(k + 13), S44, &H4E0811A1
          md5_II a, b, c, d, x(k + 4), S41, &HF7537E82
          md5_II d, a, b, c, x(k + 11), S42, &HBD3AF235
          md5_II c, d, a, b, x(k + 2), S43, &H2AD7D2BB
          md5_II b, c, d, a, x(k + 9), S44, &HEB86D391
   
          a = AddUnsigned(a, AA)
          b = AddUnsigned(b, BB)
          c = AddUnsigned(c, CC)
          d = AddUnsigned(d, DD)
      Next
   
   if DTy=32 then
    MD5=LCase(WordToHex(a) & WordToHex(b) & WordToHex(c) & WordToHex(d))
   else
    MD5=LCase(WordToHex(b) & WordToHex(c))
   end if
End Function

Response.Write "“123456”16位加密结果为["&MD5("123456",16)&"]<br />“123456”32位加密结果为["&MD5("123456",32)&"]"
%>

[转载]android:layout_gravity 和 android:gravity 区别-Android新手入门-eoe Android开发者社区_Android开发论坛 - Powered by Discuz!

mikel阅读(941)

[转载]android:layout_gravity 和 android:gravity 区别-Android新手入门-eoe Android开发者社区_Android开发论坛 – Powered by Discuz!.

Android:layout_gravity 和 Android:gravity 的区别

从名字上可以看到,android:gravity是对元素本身说的,元素本身的文本显示在什么地方靠着换个属性设置,不过不设置默认是在左侧的。

android:layout_gravity是相对与它的父元素说的,说明元素显示在父元素的什么位置。

比如说button: android:layout_gravity 表示按钮在界面上的位置。 android:gravity表示button上的字在button上的位置。

可选值

这两个属性可选的值有:top、bottom、left、right、center_vertical、fill_vertical、center_horizontal、fill_horizontal、center、fill、clip_vertical。

而且这些属性是可以多选的,用“|”分开。

默认这个的值是:Gravity.LEFT

对这些属性的描述:

出自:

http://androidmirror.com/guide/topics/resources/drawable-resource.html

http://android.toolib.net/reference/android/graphics/drawable/ClipDrawable.html

Value Description
top Put the object at the top of its container, not changing its size.
将对象放在其容器的顶部,不改变其大小.
bottom Put the object at the bottom of its container, not changing its size.
将对象放在其容器的底部,不改变其大小.
left Put the object at the left edge of its container, not changing its size.
将对象放在其容器的左侧,不改变其大小.
right Put the object at the right edge of its container, not changing its size.
将对象放在其容器的右侧,不改变其大小.
center_vertical Place object in the vertical center of its container, not changing its size.
将对象纵向居中,不改变其大小.
垂直对齐方式:垂直方向上居中对齐。
fill_vertical Grow the vertical size of the object if needed so it completely fills its container.
必要的时候增加对象的纵向大小,以完全充满其容器.
垂直方向填充
center_horizontal Place object in the horizontal center of its container, not changing its size.
将对象横向居中,不改变其大小.
水平对齐方式:水平方向上居中对齐
fill_horizontal Grow the horizontal size of the object if needed so it completely fills its container.
必要的时候增加对象的横向大小,以完全充满其容器.
水平方向填充
center Place the object in the center of its container in both the vertical and horizontal axis, not changing its size.
将对象横纵居中,不改变其大小.
fill Grow the horizontal and vertical size of the object if needed so it completely fills its container. This is the default.
必要的时候增加对象的横纵向大小,以完全充满其容器.
clip_vertical Additional option that can be set to have the top and/or bottom edges of the child clipped to its container’s bounds. The clip is based on the vertical gravity: a top gravity clips the bottom edge, a bottom gravity clips the top edge, and neither clips both edges.

附加选项,用于按照容器的边来剪切对象的顶部和/或底部的内容. 剪切基于其纵向对齐设置:顶部对齐时,剪切底部;底部对齐时剪切顶部;除此之外剪切顶部和底部.
垂直方向裁剪
clip_horizontal Additional option that can be set to have the left and/or right edges of the child clipped to its container’s bounds. The clip is based on the horizontal gravity: a left gravity clips the right edge, a right gravity clips the left edge, and neither clips both edges.

附加选项,用于按照容器的边来剪切对象的左侧和/或右侧的内容. 剪切基于其横向对齐设置:左侧对齐时,剪切右侧;右侧对齐时剪切左侧;除此之外剪切左侧和右侧.
水平方向裁剪

简单记忆 : horizontal 都是操作的水平方向,即横向, vertical 都是炒作的垂直方向,即纵向。

 

对于LinearLayout何时生效的问题

参看:也谈layout_gravity和gravity
http://www.lephone.net/viewthread.php?tid=325

对于 LinearLayout

当 android:orientation=”vertical”  时, 只有水平方向的设置才起作用,垂直方向的设置不起作用。即:left,right,center_horizontal 是生效的。

当 android:orientation=”horizontal” 时, 只有垂直方向的设置才起作用,水平方向的设置不起作用。即:top,bottom,center_vertical 是生效的。

[转载]java.lang.ClassNotFoundException: Didn't find class "*****Activity" on path: /data/app/*******.apk - lovexieyuan520的专栏 - 博客频道 - CSDN.NET

mikel阅读(1342)

[转载]java.lang.ClassNotFoundException: Didn’t find class “*****Activity” on path: /data/app/*******.apk – lovexieyuan520的专栏 – 博客频道 – CSDN.NET.

很多人出现了java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{*****Activity}: java.lang.ClassNotFoundException: Didn’t find class “*****Activity” on path: /data/app/*******.apk的错误,在Android开发中,我也遇到了这个问题,纠结了两天,终于解决了,结合我自己加上网上的找到的,现提供给大家。

 


 

1。Manifest文件中注册的Activity的名称,有没有写错,包名有没有搞错,有些网友,可能只写一个类名,前面用点号代替,但是这个类不在默认的包内,所以报这个错,那么只要写上类的全名,即可。

 


 

2。有些Android,需要一些第三方的包,直接将其引入,在以前是可以的,但是在 最新的adt中不行,必须在程序中新建一个libs文件夹,将第三方的jar文件copy到libs文件夹中,才行,很多人因为这样才报错,特别是以前的 项目,默认并没有这个libs文件夹,但是新版本的adt,默认就建了libs这个文件夹。

 


 

3。有一点也很重要,在Java Build Path面板下的Order and Export中,一定要把你引入的jar文件,勾上,否则,跟没引用一样,切记。

 


一般也就是以前的原因了,如果大家有看不明白的,或者有什么其他原因的,请跟我留言,共同分享,共同进步!

[转载]世界上最优秀的20款移动开发框架 - 白砂糖的博客 - eoe移动开发者社区

mikel阅读(923)

[转载]世界上最优秀的20款移动开发框架 – 白砂糖的博客 – eoe移动开发者社区.

本文收集了20款针对开发者的移动开发框架,以帮助他们为移动爱好者开发出新颖、有用、有趣味的应用。

1.Fries

Fries是一款稳定的HTML-CSS-JS框架,用于在实际项目和原型设计中创造类似于Android的原生UI界面。该框架包含所有的重要组件,比如Form、工具栏、列表、按钮、下拉列表及标签。它还专门针对PhoneGap进行了优化,能容易地转换为本地应用。

源代码

2. Appium

**
**

Appium是一款开源自动化测试工具。可对任何语言的iOS应用和Android应用进行测试,测试可使用Java、Objective-C、 JavaScript、PHP、Python、Ruby、C#、Clojure、Perl等众多语言编写。目前只针对Mac OS X ,且需要有 Node.js来支撑。

源代码

3. Junior

**
**

Junior为前端框架,用来构建基于HTML5的移动Web应用,外观与行为跟本地应用相似。它采用针对移动性能优化的CSS3转换,支持旋转灯 箱效果,包含多样的Ratchet UI组件。整个框架使用Zepto(类似JQuery语法的轻量级移动设备js类库),且整合了 backbone.js的视图和路由。Junior十分易于使用,且提供详细的文档及案例,便于学习。

源代码

4. Enyo

**
**

Enyo,为JavaScript开发框架,最初发布于HP TouchPad的webOS之上。现在发布了2.0版本,成为跨平台框架,不再只针 对webOS(1.0版本只针webOS)。新版本的Enyo支持桌面与移动,可工作于所有主流浏览器,拥有丰富的跨平台UI组件,以及构建应用所需的强 大的布局库。

源代码

5. Sidetap

**
**

Sidetap是一款简洁轻量级的移动Web应用开发框架(缩减压缩后只有2KB)。它专注于提供类似于Facebook移动应用这样的侧导航形式。导航部分解决后,利用它创建简单的移动Web应用就变得相当简单了。

源代码

6. Mobello

**
**

Mobello是一个开源JavaScript UI框架,目的是简化移动Web应用的开发过程。利用该框架,可在移动端提供与本地应用相似的体 验。它针对触控事件进行了优化,并提供20多种广泛应用的UI组件。它还提供了集成开发环境Mobello Studio,在其中可利用HTML5、 CSS和Mobello框架开发移动应用。

源代码

7. Moobile

**
**

Moobile是基于MooTools的移动Web应用框架,是一个新项目。它专注于提供类iOS的体验,并对按钮、图片、列表等提供较好的控制。 它还支持各种过渡样式,比如淡入淡出、幻灯片等,并可显示类本地应用的提示框(alert)。Moobile所创建的界面更具有弹性,可很好地工作于 iPhone和iPad上。

源代码

8. Spine Mobile

**
**

Spine Mobile是一个构建在SpineJS之上的JavaScript框架,用于构建看起来外观像本地应用的移动Web应用。该框架带有专用控制器、面板布局、硬件加速的转换和触摸事件。

源代码

9. Zoey

**
**

它是一个采用HTML5-CSS3技术实现的框架,用于构建移动应用。它基于Zepto.js构建,轻量,压缩后只有6kb。Zoey拥有的大量 UI控件,比如:导航、列表、按纽、控件分组、表单、表格。这个框架支持iOS和Android,并自带一个覆盖所有功能的程序骨架。

源代码

10. iUI

**
**

iUI为移动Web框架。该框架包含JavaScript库、CSS和图片集,用于开发可触摸Web应用。它所创建的应用有着iPhone SDK构建的本机应用程序那样的外观和感觉,可运行于大部分智能手机和平板电脑上,只要它包含一个符合标准的Web浏览器。

源代码

11. Lungo.js

**
**

Lungo.jS是一个使用HTML5、CSS3和 JavaScript技术的移动Web开发框架。所创建应用可运行于所有流行平台之上 (iOS、Android、Blackberry和WebOS)。它支持触控事件,如单击、双击和滑动。无需使用图片,全部采用向量声称。

源代码

12. Wink Toolkit

**
**

Wink Toolkit为JavaScript框架,用来创建移动Web应用。该框架的核心提供了开发移动应用应具备的所有基础功能,从触摸事件处理到DOM操作和CSS转换等。此外,它还提供非常多的UI控件来帮助改进Web应用的外观。

源代码

13. The M Project

**
**

The M
Project是一款HTML5 JS框架,可构建跨平台的移动Web应用(如OS、Android、Palm webOS、BlackBerry平台)。其JavaScript部分采用
JQuery,并包含所有jQuery UI核心文件,如离线支持、国际化等。The-M-Project并不是独立的,它需要引入nodeJS和一个称为Espresso!的构建工具,该工具可使你更容易地结构化代码、构建并运行在内嵌服务器上。

源代码

14. DHTMLX Touch

**
**

DHTMLX Touch为JavaScript库,基于HTML5,用于创建移动Web应用。它不只是一组UI小工具,而是一个完整的框架,可以 针对移动和触摸设备创建跨平台的Web应用。它兼容主流的Web浏览器,用它创建的应用,可在iPad、iPhone、Android智能手机等上面流畅 运行。

源代码

15. Zepto.js

**
**

Zepto.js是支持移动WebKit浏览器的JavaScript框架,具有与jQuery兼容的语法。轻量级,大小为2-5k的库,通过不错的API处理绝大多数的基本工作。

源代码

16. jQuery Mobile

**
**

jQuery Mobile是
jQuery发布的针对手机和平板设备、经过触控优化的Web框架。它基于jQuery,在不同移动设备平台上可提供统一的用户界面。该框架基于渐近增强技术,并利用HTML5和CSS3特性。

源代码

17. Jo

**
**

Jo为基于HTML5的开源移动应用框架。该框架提供丰富的平台支持,包括webOS、iOS、Android、Symbian、Safari、 Chrome甚至是 Mac OS®X Dashboard小部件。Jo也兼容PhoneGap。Jo 的简单性和轻量级与 PhoneGap的强大功能 相结合,最终将生成一个有效的工具,可以针对广泛的平台开发丰富的移动本地应用程序。

源代码

18. Sencha Touch

**
**

它是一款HTML5移动应用框架。通过它可以创建Web应用,在外观和感觉上与Apple iOS 和Google Android本地应用十分相像。它利用HTML5发布音频/视频,进行本地存储;利用CSS3提供圆角、背景渐变、阴影等广泛使用的样式。

源代码

19. WebApp.Net

**
**

WebApp.Net是一款基于Ajax技术的JavaScript框架,用于构建移动Web应用。它提供了一整套组件(开关按钮、单选按钮组等),可帮助开发者创建外观和行为与本地移动应用十分相似的网站

源代码

20. Helios

**
**

Helios为开源框架,为iOS应用提供必要的后台服务,从数据同步、推送通知,到应用内购买、passbook继承。它可帮助开发人员在数分钟的时间内构建出一个包含客户端和服务器端的应用。

源代码

原文链接:20 Useful Mobile Frameworks for
Developers

from http://www.csdn.net/article/2013-07-09/2816161

[转载]关于讯飞语音SDK开发学习 - 或、许 - 博客园

mikel阅读(1185)

[转载]关于讯飞语音SDK开发学习 – 或、许 – 博客园.

前奏,浑浑噩噩已经工作一年多,这一年多收获还是挺多的。逛园子应该有两年多了,工作后基本上是天天都会来园子逛逛,园子 里还是有很多牛人写了一些不错的博客,帮我解决很多问题。但是一直没写过博客,归根到底一个字“懒”,还有就是不知道该写 些什么…

今 天把我最近研究讯飞语音东东,分享一下,不过有些还是前辈们提供的。之前公司让我做一个小的语音识别功能,一开始我就建议使用讯飞语音,个人觉得讯飞识别 正确率还是可观的。可是老总说不能考 虑联网,还有就是钱的问题。想到微软自带语音识别引擎(基于win7)。第一次接触到语音识别,没什么头绪,只有收集相关资料 。最后成品出来了,但是识别效果不是那么满意,老总说那就将就用吧,我想他都那样说了,我也没多大意见…开年后老总老总 买了个iphone5玩了siri后,觉得我们现在那个语音太丑陋了,让换一个解决方案,识别率要达到90%。国内有好几家公司做语音识 别的比如科大讯飞、云知声、捷通华声以及紫冬锐意语音都做了一定开放。市面上我知道语音助手有百度语音助手、虫洞语音助手 、360语音助手以及科大讯飞语点;前两个我不知道采用那家公司的还是自己研发的不过都没开开放,360语音助手采用讯飞的。然 后我就继续提议使用讯飞语音SDK,于是乎同事们都下载讯飞语点来玩玩,老总说那就试试讯飞语音SDK。

先 做一个简单demo,看看识别效果,感觉识别率上能够满足要求。一般要的结果不光只是要把所说的话翻译成文字,而是需要的是 语义的理解:例如我要去北京,直接返回北京这个关键。目前讯飞还没把这个接口开放出来,公司负责人说今年会把这个开放出来 。那现在只能使用关键词识别语法,一种是直接是文本词库;另一种是ABNF语法。ABNF写法有点烦杂(语法文件里使用到的词句都是指定的,对于无法枚举 的词句暂时没有很好的解决办法。),就直接采用文本词库(因为关键词有点多)。讯飞还有专门人负责关于讯飞语音问题解答(QQ群:153789256)。

讯飞提供msc.dll这个DLL,调用DLL的封装:

/// <summary>
        /// MSCDLL入口封装
        /// </summary>
        private class MscDll
        {
            #region MscDLL
           
            /// <summary>
            /// 初始化MSC的ISR部分
            /// </summary>
            /// <param name="configs">初始化时传入的字符串,以指定合成用到的一些配置参数,各个参数以“参数名=参数值”的形式出现,大小写不敏感,不同的参数之间以“,”或“\n”隔开,不设置任何值时可以传入NULL或空串:</param>
            /// <returns>如果函数调用成功返回MSP_SUCCESS,否则返回错误代码,错误代码参见msp_errors</returns>
            [DllImport("msc.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern int QISRInit(string configs);
           
            /// <summary>
            /// 开始一个ISR会话
            /// </summary>
            /// <param name="grammarList">uri-list格式的语法,可以是一个语法文件的URL或者一个引擎内置语法列表。可以同时指定多个语法,不同的语法之间以“,”
            /// 隔开。进行语音听写时不需要语法,此参数设定为NULL或空串即可;进行语音识别时则需要语法,语法可以在此参数中指定,也可以随后调用QISRGrammarActivate指定识别所用的语法。</param>
            /// <param name="_params">本路ISR会话使用的参数,可设置的参数及其取值范围请参考《可设置参数列表_MSP20.xls》,各个参数以“参数名=参数值” 的形式出现,不同的参数之间以“,”或者“\n”隔开。</param>
            /// <param name="errorCode">如果函数调用成功则其值为MSP_SUCCESS,否则返回错误代码,错误代码参见msp_errors。几个主要的返回值: MSP_ERROR_NOT_INIT 未初始化 MSP_ERROR_INVALID_PARA 无效的参数; MSP_ERROR_NO_LICENSE 开始一路会话失败</param>
            /// <returns>MSC为本路会话建立的ID,用来唯一的标识本路会话,供以后调用其他函数时使用。函数调用失败则会返回NULL。</returns>
            [DllImport("msc.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern IntPtr QISRSessionBegin(string grammarList, string _params, ref int errorCode);
           
            /// <summary>
            /// 传入语法
            /// </summary>
            /// <param name="sessionID">由QISRSessionBegin返回过来的会话ID</param>
            /// <param name="grammar">语法字符串</param>
            /// <param name="type">语法类型,可以是uri-list、abnf、xml等</param>
            /// <param name="weight">本次传入语法的权重,本参数在MSP 2.0中会被忽略。</param>
            /// <returns>如果函数调用成功返回MSP_SUCCESS,否则返回错误代码,错误代码参见msp_errors</returns>
            [DllImport("msc.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern int QISRGrammarActivate(string sessionID, string grammar, string type, int weight);

            /// <summary>
            /// 写入用来识别的语音
            /// </summary>
            /// <param name="sessionID">由QISRSessionBegin返回过来的会话ID</param>
            /// <param name="waveData">音频数据缓冲区起始地址</param>
            /// <param name="waveLen">音频数据长度,其大小不能超过设定的max_audio_size</param>
            /// <param name="audioStatus">用来指明用户本次识别的音频是否发送完毕,可能值如下:
            /// MSP_AUDIO_SAMPLE_FIRST = 1 第一块音频
            /// MSP_AUDIO_SAMPLE_CONTINUE = 2 还有后继音频
            /// MSP_AUDIO_SAMPLE_LAST = 4 最后一块音频</param>           
            /// <param name="epStatus">端点检测(End-point detected)器所处的状态,可能的值如下:
            /// MSP _EP_LOOKING_FOR_SPEECH = 0 还没有检测到音频的前端点。
            /// MSP _EP_IN_SPEECH = 1 已经检测到了音频前端点,正在进行正常的音频处理。
            /// MSP _EP_AFTER_SPEECH = 3 检测到音频的后端点,后继的音频会被MSC忽略。
            /// MSP _EP_TIMEOUT = 4 超时。
            /// MSP _EP_ERROR= 5 出现错误。
            /// MSP _EP_MAX_SPEECH = 6 音频过大。</param>
            /// <param name="recogStatus">识别器所处的状态</param>
            /// <returns></returns>
            [DllImport("msc.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern int QISRAudioWrite(string sessionID, byte[] waveData, uint waveLen, AudioStatus audioStatus, ref  EpStatus epStatus, ref RecogStatus recogStatus);

            /// <summary>
            /// 获取识别结果
            /// </summary>
            /// <param name="sessionID">由QISRSessionBegin返回过来的会话ID</param>
            /// <param name="rsltStatus">识别结果的状态,其取值范围和含义请参考QISRAudioWrite的参数recogStatus</param>
            /// <param name="waitTime">与服务器交互的间隔时间,可以控制和服务器的交互频度。单位为ms,建议取值为5000</param>
            /// <param name="errorCode">如果函数调用成功返回MSP_SUCCESS,否则返回错误代码,错误代码参见msp_errors</param>
            /// <returns>函数执行成功并且获取到识别结果时返回识别结果,函数执行成功没有获取到识别结果时返回NULL</returns>
            [DllImport("msc.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern IntPtr QISRGetResult(string sessionID, ref RecogStatus rsltStatus, int waitTime, ref int errorCode);

            /// <summary>
            /// 结束一路会话
            /// </summary>
            /// <param name="sessionID">由QISRSessionBegin返回过来的会话ID</param>
            /// <param name="hints">结束本次会话的原因描述,用于记录日志,便于用户查阅或者跟踪某些问题</param>
            /// <returns></returns>
            [DllImport("msc.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern int QISRSessionEnd(string sessionID, string hints);

            /// <summary>
            /// 获取与识别交互相关的参数
            /// </summary>
            /// <param name="sessionID">由QISRSessionBegin返回过来的会话ID</param>
            /// <param name="paramName">要获取的参数名称;支持同时查询多个参数,查询多个参数时,参数名称按“,” 或“\n”分隔开来</param>
            /// <param name="paramValue">获取的参数值,以字符串形式返回;查询多个参数时,参数值之间以“;”分开,不支持的参数将返回空的值</param>
            /// <param name="valueLen">参数值的长度</param>
            /// <returns></returns>
            [DllImport("msc.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern int QISRGetParam(string sessionID, string paramName, string paramValue, ref uint valueLen);

            /// <summary>
            /// 逆初始化MSC的ISR部分
            /// </summary>
            /// <returns></returns>
            [DllImport("msc.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern int QISRFini();

            /// <summary>
            /// 上传用户自定义词库
            /// </summary>
            /// <param name="sessionID">由QISRSessionBegin返回过来的会话ID</param>
            /// <param name="dataName">词库名称</param>
            /// <param name="userData">词库数据采用是utf8格式</param>
            /// <param name="lenght">词库大小</param>
            /// <param name="paramValue">参数值</param>
            /// <param name="errorCode">如果函数调用成功返回MSP_SUCCESS,否则返回错误代码,错误代码参见msp_errors</param>
            /// <returns>函数执行成功并且返回exID(词库编号)</returns>
            [DllImport("msc.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern IntPtr QISRUploadData(string sessionID, string dataName, byte[] userData, uint lenght, string paramValue, ref int errorCode);

            #endregion
        }

说明一下:“QISRUploadData”(上传词库)这个函数在开发文档里面没的,讯飞遗漏了。

具体实现(关键词识别,文本词库):

类:MscNet

#region 定义字段

        //返回错误代号
        private int ret = 0;
        private RecoErrors Re = null;
        /// <summary>
        /// 会话ID
        /// </summary>
        private string sess_id = null;
        /// <summary>
        /// 参数
        /// </summary>
        private string param = null;
        /// <summary>
        /// 语法
        /// </summary>
        private string grammar = null;
        //错误消息通知托管
        public delegate void delegdateOnerror(string Msg);
        private string path = null;
        /// <summary>
        /// 识别数据返回的事件
        /// </summary>
        public event EventHandler<DataArrivedEventArgs> DataArrived;
        /// <summary>
        /// 识别过程结束的事件
        /// </summary>
        public event EventHandler ISREnd;
        /// <summary>
        /// 正在识别
        /// </summary>
        public event EventHandler Spoting;

        #endregion

        #region 构造函数

        /// <summary>
        /// 构造函数,初始化引擎
        /// </summary>
        /// <param name="appid">appid</param>
        /// <param name="param">参数</param>      
        /// <param name="grammar">语法ID</param>
        /// <param name="path">路径</param>
        public MscNet(string appid, string param, string path, string grammar)
        {
            this.path = path;
            this.param = param;
            this.grammar = grammar;
            Re = new RecoErrors();
            //引擎初始化,只需初始化一次
            ret = MscDll.QISRInit("appid=" + appid);
            try
            {
                Re.GetError(ret);
            }
            catch (MscException ex)
            {
                RaiseError(ex.Message.ToString());
            }
        }
        #endregion

        #region 公共方法

        /// <summary>
        /// 开始识别语音
        /// </summary>
        /// <param name="buffer">音频数据</param>
        public void InterpretVoice(byte[] buffer)
        {
            //用来指明用户本次识别的音频是否发送完毕
            AudioStatus audioStatus = AudioStatus.ISR_AUDIO_SAMPLE_LAST;
            //端点检测(End-point detected)器所处的状态
            EpStatus ep_status = EpStatus.ISR_EP_NULL;
            //识别器所处的状态
            RecogStatus rec_status = RecogStatus.ISR_REC_NULL;
            //识别结果的状态
            RecogStatus rslt_status = RecogStatus.ISR_REC_NULL;
            Loadgrammar();
            int ret = MscDll.QISRAudioWrite(sess_id, buffer, (uint)buffer.Length, audioStatus, ref ep_status, ref rec_status);
            try
            {
                Re.GetError(ret);
                do
                {
                    if (rslt_status == RecogStatus.ISR_REC_STATUS_INCOMPLETE)
                    {
                        Spoting(this, new EventArgs());//通知正在识别
                    }
                    IntPtr p = MscDll.QISRGetResult(sess_id, ref rslt_status, 0, ref ret);
                    Re.GetError(ret);
                    if (p != IntPtr.Zero)
                    {
                        string tmp = PtrToStr(p);
                        DataArrived(this, new DataArrivedEventArgs(tmp));//激发识别数据到达事件                    
                    }
                    System.Threading.Thread.Sleep(500);
                } while (rslt_status != RecogStatus.ISR_REC_STATUS_SPEECH_COMPLETE);
            }
            catch (MscException ex)
            {
                RaiseError(ex.Message);
            }
            finally
            {
                try
                {
                    ret = MscDll.QISRSessionEnd(sess_id, string.Empty);
                    Re.GetError(ret);
                    ISREnd(this, new EventArgs());//通知识别结束 
                }
                catch (MscException ex)
                {
                    RaiseError(ex.Message);
                }
            }
        }

        /// <summary>
        /// 上传词库词库采用是utf8格式
        /// </summary>
        /// <param name="txtFile">词库名称</param>
        /// <param name="path">词库路径</param>
        /// <param name="param">参数</param>
        /// <returns>返回词库编号</returns>
        public string GetExID(string txtFile, string path, string param)
        {
            string filePath = Path.Combine(path, txtFile);
            string tmp = string.Empty;
            if (!string.IsNullOrEmpty(filePath))
            {
                try
                {
                    sess_id = PtrToStr(MscDll.QISRSessionBegin(null, param, ref ret));
                    Re.GetError(ret);
                    try
                    {
                        using (FileStream fs = File.Open(filePath, FileMode.Open))
                        {
                            long len = fs.Length;
                            byte[] buffer = new byte[len];
                            fs.Read(buffer, 0, (int)len);
                            IntPtr p = MscDll.QISRUploadData(sess_id, "sces", buffer, (uint)fs.Length, "dtt=keylist", ref ret);
                            Re.GetError(ret);
                            if (p != IntPtr.Zero)
                            {
                                tmp = PtrToStr(p);
                            }
                        }
                    }
                    catch (FileNotFoundException ex)
                    {
                        RaiseError(ex.Message);
                    }

                }
                catch (MscException ex)
                {
                    RaiseError(ex.Message);
                }
                finally
                {
                    try
                    {
                        ret = MscDll.QISRSessionEnd(sess_id, null);
                        Re.GetError(ret);
                    }
                    catch (MscException ex)
                    {
                        RaiseError(ex.Message.ToString());
                    }
                }
            }
            else
            {
                RaiseError("路径不正确!");
            }
            return tmp;
        }

        /// <summary>
        /// 对MSC的ISR部分进行逆初始化。
        /// </summary>
        public void QISRFini()
        {
            try
            {
                ret = MscDll.QISRFini();
                Re.GetError(ret);
            }
            catch (MscException ex)
            {
                RaiseError(ex.Message.ToString());
            }
        }

        #endregion

        #region 受保护方法
        /// <summary>
        /// 加载语法 
        /// </summary>
        private void Loadgrammar()
        {
            try
            {
                sess_id = PtrToStr(MscDll.QISRSessionBegin(grammar, param, ref ret));
                Re.GetError(ret);
            }
            catch (MscException ex)
            {
                RaiseError(ex.Message);
            }
        }

        /// <summary>
        /// 指针转字符串
        /// </summary>
        /// <param name="p">指向非托管代码字符串的指针</param>
        /// <returns>返回指针指向的字符串</returns>
        private string PtrToStr(IntPtr p)
        {
            List<byte> lb = new List<byte>();
            try
            {
                while (Marshal.ReadByte(p) != 0)
                {
                    lb.Add(Marshal.ReadByte(p));
                    p = p + 1;
                }
            }
            catch (AccessViolationException ex)
            {
                RaiseError(ex.Message);
            }
            return Encoding.Default.GetString(lb.ToArray());
        }       
        #endregion

        #region 事件
        /// <summary>
        /// 错误通知事件
        /// </summary>
        public event delegdateOnerror OnError;
        private void RaiseError(string Msg)
        {
            if (OnError != null)
            {
                OnError(Msg);
            }
        }
        /// <summary>
        /// 有识别数据返回的事件参数,包含了识别的文本结果
        /// </summary>
        public class DataArrivedEventArgs : EventArgs
        {
            public string result;
            public DataArrivedEventArgs(string rs)
            {
                result = rs;
            }
        }
        #endregion

如果采用ABNF语法,只是与文本词库加载语法方式有点不一样:

/// <summary>
        /// 加载语法 
        /// </summary>
        private void Loadgrammar()
        {
            try
            {
               
               //sess_id = PtrToStr(MscDll.QISRSessionBegin(grammar, param, ref ret));              
                /*ABNF语法*/
                sess_id = PtrToStr(MscDll.QISRSessionBegin(null, "rst=plain,sub=asr,ssm=1,aue=speex,auf=audio/L16;rate=16000,cfd=350", ref ret));
                em.GetError(ret);
                string grammar1 = "#ABNF 1.0 GB2312;\n mode voice;\n language zh-cn;\n\n\n root $main;\n public $main = 我[想要]看$place1;\n $place1=足球;\n";
                ret = MscDll.QISRGrammarActivate(sess_id, grammar1, "abnf", 0);//将语法ID传入QISRSessionBegin
                /*end */
                em.GetError(ret);             
            }
            catch (MscException ex)
            {
                RaiseError(ex.Message.ToString());
            }
        }

常量的枚举:

#region 错误代号
    enum ErrorCode
    {
        MSP_SUCCESS= 0,
        MSP_ERROR_FAIL = -1,
        MSP_ERROR_EXCEPTION = -2,

        /* General errors 10100(0x2774) */
        MSP_ERROR_GENERAL = 10100,     /* 0x2774 */
        MSP_ERROR_OUT_OF_MEMORY = 10101,     /* 0x2775 */
        MSP_ERROR_FILE_NOT_FOUND = 10102,     /* 0x2776 */
        MSP_ERROR_NOT_SUPPORT = 10103,     /* 0x2777 */
        MSP_ERROR_NOT_IMPLEMENT = 10104,     /* 0x2778 */
        MSP_ERROR_ACCESS = 10105,     /* 0x2779 */
        MSP_ERROR_INVALID_PARA = 10106,     /* 0x277A */
        MSP_ERROR_INVALID_PARA_VALUE = 10107,     /* 0x277B */
        MSP_ERROR_INVALID_HANDLE = 10108,     /* 0x277C */
        MSP_ERROR_INVALID_DATA = 10109,     /* 0x277D */
        MSP_ERROR_NO_LICENSE = 10110,     /* 0x277E */
        MSP_ERROR_NOT_INIT = 10111,     /* 0x277F */
        MSP_ERROR_NULL_HANDLE = 10112,     /* 0x2780 */
        MSP_ERROR_OVERFLOW = 10113,     /* 0x2781 */
        MSP_ERROR_TIME_OUT = 10114,     /* 0x2782 */
        MSP_ERROR_OPEN_FILE = 10115,     /* 0x2783 */
        MSP_ERROR_NOT_FOUND = 10116,     /* 0x2784 */
        MSP_ERROR_NO_ENOUGH_BUFFER = 10117,     /* 0x2785 */
        MSP_ERROR_NO_DATA = 10118,     /* 0x2786 */
        MSP_ERROR_NO_MORE_DATA = 10119,     /* 0x2787 */
        MSP_ERROR_SKIPPED = 10120,     /* 0x2788 */
        MSP_ERROR_ALREADY_EXIST = 10121,     /* 0x2789 */
        MSP_ERROR_LOAD_MODULE = 10122,     /* 0x278A */
        MSP_ERROR_BUSY = 10123,     /* 0x278B */
        MSP_ERROR_INVALID_CONFIG = 10124,     /* 0x278C */
        MSP_ERROR_VERSION_CHECK = 10125,     /* 0x278D */
        MSP_ERROR_CANCELED = 10126,     /* 0x278E */
        MSP_ERROR_INVALID_MEDIA_TYPE = 10127,     /* 0x278F */
        MSP_ERROR_CONFIG_INITIALIZE = 10128,     /* 0x2790 */
        MSP_ERROR_CREATE_HANDLE = 10129,     /* 0x2791 */
        MSP_ERROR_CODING_LIB_NOT_LOAD = 10130,     /* 0x2792 */

        /* Error codes of network 10200(0x27D8)*/
        MSP_ERROR_NET_GENERAL = 10200,     /* 0x27D8 */
        MSP_ERROR_NET_OPENSOCK = 10201,     /* 0x27D9 */   /* Open socket */
        MSP_ERROR_NET_CONNECTSOCK = 10202,     /* 0x27DA */   /* Connect socket */
        MSP_ERROR_NET_ACCEPTSOCK = 10203,     /* 0x27DB */   /* Accept socket */
        MSP_ERROR_NET_SENDSOCK = 10204,     /* 0x27DC */   /* Send socket data */
        MSP_ERROR_NET_RECVSOCK = 10205,     /* 0x27DD */   /* Recv socket data */
        MSP_ERROR_NET_INVALIDSOCK = 10206,     /* 0x27DE */   /* Invalid socket handle */
        MSP_ERROR_NET_BADADDRESS = 10207,     /* 0x27EF */   /* Bad network address */
        MSP_ERROR_NET_BINDSEQUENCE = 10208,     /* 0x27E0 */   /* Bind after listen/connect */
        MSP_ERROR_NET_NOTOPENSOCK = 10209,     /* 0x27E1 */   /* Socket is not opened */
        MSP_ERROR_NET_NOTBIND = 10210,     /* 0x27E2 */   /* Socket is not bind to an address */
        MSP_ERROR_NET_NOTLISTEN = 10211,     /* 0x27E3 */   /* Socket is not listenning */
        MSP_ERROR_NET_CONNECTCLOSE = 10212,     /* 0x27E4 */   /* The other side of connection is closed */
        MSP_ERROR_NET_NOTDGRAMSOCK = 10213,     /* 0x27E5 */   /* The socket is not datagram type */
        MSP_ERROR_NET_DNS=10214,
        /* Error codes of mssp message 10300(0x283C) */
        MSP_ERROR_MSG_GENERAL = 10300,     /* 0x283C */
        MSP_ERROR_MSG_PARSE_ERROR = 10301,     /* 0x283D */
        MSP_ERROR_MSG_BUILD_ERROR = 10302,     /* 0x283E */
        MSP_ERROR_MSG_PARAM_ERROR = 10303,     /* 0x283F */
        MSP_ERROR_MSG_CONTENT_EMPTY = 10304,     /* 0x2840 */
        MSP_ERROR_MSG_INVALID_CONTENT_TYPE = 10305,     /* 0x2841 */
        MSP_ERROR_MSG_INVALID_CONTENT_LENGTH = 10306,     /* 0x2842 */
        MSP_ERROR_MSG_INVALID_CONTENT_ENCODE = 10307,     /* 0x2843 */
        MSP_ERROR_MSG_INVALID_KEY = 10308,     /* 0x2844 */
        MSP_ERROR_MSG_KEY_EMPTY = 10309,     /* 0x2845 */
        MSP_ERROR_MSG_SESSION_ID_EMPTY = 10310,     /* 0x2846 */
        MSP_ERROR_MSG_LOGIN_ID_EMPTY = 10311,     /* 0x2847 */
        MSP_ERROR_MSG_SYNC_ID_EMPTY = 10312,     /* 0x2848 */
        MSP_ERROR_MSG_APP_ID_EMPTY = 10313,     /* 0x2849 */
        MSP_ERROR_MSG_EXTERN_ID_EMPTY = 10314,     /* 0x284A */
        MSP_ERROR_MSG_INVALID_CMD = 10315,     /* 0x284B */
        MSP_ERROR_MSG_INVALID_SUBJECT = 10316,     /* 0x284C */
        MSP_ERROR_MSG_INVALID_VERSION = 10317,     /* 0x284D */
        MSP_ERROR_MSG_NO_CMD = 10318,     /* 0x284E */
        MSP_ERROR_MSG_NO_SUBJECT = 10319,     /* 0x284F */
        MSP_ERROR_MSG_NO_VERSION = 10320,     /* 0x2850 */
        MSP_ERROR_MSG_MSSP_EMPTY = 10321,     /* 0x2851 */
        MSP_ERROR_MSG_NEW_RESPONSE = 10322,     /* 0x2852 */
        MSP_ERROR_MSG_NEW_CONTENT = 10323,     /* 0x2853 */
        MSP_ERROR_MSG_INVALID_SESSION_ID = 10324,     /* 0x2854 */

        /* Error codes of DataBase 10400(0x28A0)*/
        MSP_ERROR_DB_GENERAL = 10400,     /* 0x28A0 */
        MSP_ERROR_DB_EXCEPTION = 10401,     /* 0x28A1 */
        MSP_ERROR_DB_NO_RESULT = 10402,     /* 0x28A2 */
        MSP_ERROR_DB_INVALID_USER = 10403,     /* 0x28A3 */
        MSP_ERROR_DB_INVALID_PWD = 10404,     /* 0x28A4 */
        MSP_ERROR_DB_CONNECT = 10405,     /* 0x28A5 */
        MSP_ERROR_DB_INVALID_SQL = 10406,     /* 0x28A6 */
        MSP_ERROR_DB_INVALID_APPID = 10407,    /* 0x28A7 */

        /* Error codes of Resource 10500(0x2904)*/
        MSP_ERROR_RES_GENERAL = 10500,     /* 0x2904 */
        MSP_ERROR_RES_LOAD = 10501,     /* 0x2905 */   /* Load resource */
        MSP_ERROR_RES_FREE = 10502,     /* 0x2906 */   /* Free resource */
        MSP_ERROR_RES_MISSING = 10503,     /* 0x2907 */   /* Resource File Missing */
        MSP_ERROR_RES_INVALID_NAME = 10504,     /* 0x2908 */   /* Invalid resource file name */
        MSP_ERROR_RES_INVALID_ID = 10505,     /* 0x2909 */   /* Invalid resource ID */
        MSP_ERROR_RES_INVALID_IMG = 10506,     /* 0x290A */   /* Invalid resource image pointer */
        MSP_ERROR_RES_WRITE = 10507,     /* 0x290B */   /* Write read-only resource */
        MSP_ERROR_RES_LEAK = 10508,     /* 0x290C */   /* Resource leak out */
        MSP_ERROR_RES_HEAD = 10509,     /* 0x290D */   /* Resource head currupt */
        MSP_ERROR_RES_DATA = 10510,     /* 0x290E */   /* Resource data currupt */
        MSP_ERROR_RES_SKIP = 10511,     /* 0x290F */   /* Resource file skipped */

        /* Error codes of TTS 10600(0x2968)*/
        MSP_ERROR_TTS_GENERAL = 10600,     /* 0x2968 */
        MSP_ERROR_TTS_TEXTEND = 10601,     /* 0x2969 */  /* Meet text end */
        MSP_ERROR_TTS_TEXT_EMPTY = 10602,     /* 0x296A */  /* no synth text */

        /* Error codes of Recognizer 10700(0x29CC) */
        MSP_ERROR_REC_GENERAL = 10700,     /* 0x29CC */
        MSP_ERROR_REC_INACTIVE = 10701,     /* 0x29CD */
        MSP_ERROR_REC_GRAMMAR_ERROR = 10702,     /* 0x29CE */
        MSP_ERROR_REC_NO_ACTIVE_GRAMMARS = 10703,     /* 0x29CF */
        MSP_ERROR_REC_DUPLICATE_GRAMMAR = 10704,     /* 0x29D0 */
        MSP_ERROR_REC_INVALID_MEDIA_TYPE = 10705,     /* 0x29D1 */
        MSP_ERROR_REC_INVALID_LANGUAGE = 10706,     /* 0x29D2 */
        MSP_ERROR_REC_URI_NOT_FOUND = 10707,     /* 0x29D3 */
        MSP_ERROR_REC_URI_TIMEOUT = 10708,     /* 0x29D4 */
        MSP_ERROR_REC_URI_FETCH_ERROR = 10709,     /* 0x29D5 */

        /* Error codes of Speech Detector 10800(0x2A30) */
        MSP_ERROR_EP_GENERAL = 10800,     /* 0x2A30 */
        MSP_ERROR_EP_NO_SESSION_NAME = 10801,     /* 0x2A31 */
        MSP_ERROR_EP_INACTIVE = 10802,     /* 0x2A32 */
        MSP_ERROR_EP_INITIALIZED = 10803,     /* 0x2A33 */

        /* Error codes of TUV */
        MSP_ERROR_TUV_GENERAL = 10900,     /* 0x2A94 */
        MSP_ERROR_TUV_GETHIDPARAM = 10901,     /* 0x2A95 */   /* Get Busin Param huanid*/
        MSP_ERROR_TUV_TOKEN = 10902,     /* 0x2A96 */   /* Get Token */
        MSP_ERROR_TUV_CFGFILE = 10903,     /* 0x2A97 */   /* Open cfg file */
        MSP_ERROR_TUV_RECV_CONTENT = 10904,     /* 0x2A98 */   /* received content is error */
        MSP_ERROR_TUV_VERFAIL = 10905,     /* 0x2A99 */   /* Verify failure */

        /* Error codes of IMTV */
        MSP_ERROR_IMTV_SUCCESS = 11000,     /* 0x2AF8 */   /* 成功 */
        MSP_ERROR_IMTV_NO_LICENSE = 11001,     /* 0x2AF9 */   /* 试用次数结束,用户需要付费 */
        MSP_ERROR_IMTV_SESSIONID_INVALID = 11002,     /* 0x2AFA */   /* SessionId失效,需要重新登录通行证 */
        MSP_ERROR_IMTV_SESSIONID_ERROR = 11003,     /* 0x2AFB */   /* SessionId为空,或者非法 */
        MSP_ERROR_IMTV_UNLOGIN = 11004,     /* 0x2AFC */   /* 未登录通行证 */
        MSP_ERROR_IMTV_SYSTEM_ERROR = 11005,     /* 0x2AFD */   /* 系统错误 */

        /* Error codes of HCR */
        MSP_ERROR_HCR_GENERAL = 11100,
        MSP_ERROR_HCR_RESOURCE_NOT_EXIST = 11101,

        /* Error codes of http 12000(0x2EE0) */
        MSP_ERROR_HTTP_BASE = 12000,    /* 0x2EE0 */

        /*Error codes of ISV */
        MSP_ERROR_ISV_NO_USER = 13000,    /* 32C8 */    /* the user doesn't exist */
    }
    #endregion

    #region ISR枚举常量
    public enum AudioStatus
    {
        ISR_AUDIO_SAMPLE_INIT = 0x00,
        ISR_AUDIO_SAMPLE_FIRST = 0x01,
        ISR_AUDIO_SAMPLE_CONTINUE = 0x02,
        ISR_AUDIO_SAMPLE_LAST = 0x04,
        ISR_AUDIO_SAMPLE_SUPPRESSED = 0x08,
        ISR_AUDIO_SAMPLE_LOST = 0x10,
        ISR_AUDIO_SAMPLE_NEW_CHUNK = 0x20,
        ISR_AUDIO_SAMPLE_END_CHUNK = 0x40,

        ISR_AUDIO_SAMPLE_VALIDBITS = 0x7f /* to validate the value of sample->status */
    }

    public enum EpStatus
    {
        ISR_EP_NULL = -1,
        ISR_EP_LOOKING_FOR_SPEECH = 0,          ///还没有检测到音频的前端点
        ISR_EP_IN_SPEECH = 1,                   ///已经检测到了音频前端点,正在进行正常的音频处理。
        ISR_EP_AFTER_SPEECH = 3,                ///检测到音频的后端点,后继的音频会被MSC忽略。
        ISR_EP_TIMEOUT = 4,                     ///超时
        ISR_EP_ERROR = 5,                       ///出现错误
        ISR_EP_MAX_SPEECH = 6                   ///音频过大
    }

    public enum RecogStatus
    {
        ISR_REC_NULL = -1,
        ISR_REC_STATUS_SUCCESS = 0,             ///识别成功,此时用户可以调用QISRGetResult来获取(部分)结果。
        ISR_REC_STATUS_NO_MATCH = 1,            ///识别结束,没有识别结果
        ISR_REC_STATUS_INCOMPLETE = 2,          ///正在识别中
        ISR_REC_STATUS_NON_SPEECH_DETECTED = 3, ///保留
        ISR_REC_STATUS_SPEECH_DETECTED = 4,     ///发现有效音频
        ISR_REC_STATUS_SPEECH_COMPLETE = 5,     ///识别结束
        ISR_REC_STATUS_MAX_CPU_TIME = 6,        ///保留
        ISR_REC_STATUS_MAX_SPEECH = 7,          ///保留
        ISR_REC_STATUS_STOPPED = 8,             ///保留
        ISR_REC_STATUS_REJECTED = 9,            ///保留
        ISR_REC_STATUS_NO_SPEECH_FOUND = 10     ///没有发现音频
    }
    #endregion
}

自定义异常:

[Serializable] //声明为可序列化的 因为要写入文件中  
    public class MscException : ApplicationException//由用户程序引发,用于派生自定义的异常类型  
    {
        /// <summary>  
        /// 默认构造函数  
        /// </summary>  
        public MscException() { }
        public MscException(string message)
            : base(message) { }
        public MscException(string message, Exception inner)
            : base(message, inner) { }
    } 
    /// <summary>
    /// 是否出错
    /// </summary>
    internal class RecoErrors
    {
        public RecoErrors() { }
        /// <summary>  
        /// 是否发生错误.  
        /// </summary>  
        /// <param name="id">错误ID</param>  
        public virtual void GetError(int id)
        {
            if (id != 0)
            {               
                var ex = new MscException(((ErrorCode)id).ToString("G"));
               // var ex = new MscException(Enum.GetName(typeof(ErrorCode),id));
                throw ex;
            }
        }
    }

讯飞语音支持边录边上传,不过我这里采用是一次性上传。起初我采用的是边录边上传,不过感觉有数字混合后识别正常率不好(还没跟讯飞那边沟通。),最后才使用一次性上传,毕竟语音文件也不是大就200KB一下。讯飞语音识别不支持多线程识别。

我做的这个语音识别产品,做成服务端与客户端。服务端:放在一个能连接外网机子上提供语音识别(做了一个简单队列),客户端:将音频数据采集后发送到局域网内的语音识别服务端进行识别。

以上有些代码是借助别人的,第一次写大家尽量不要吐槽,不过可以给点意见。大家相互学习…