posts - 32, comments - 153, trackbacks - 0, articles - 0
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

利用JNI调用C/C++方法实现从控制台输入密码

Posted on 2007-02-24 22:06 Zou Ang 阅读(3069) 评论(6)  编辑  收藏 所属分类:

最近看到一个问题,如何用Java实现从控制台输入密码?
本来以为是很简单的问题,查了一下发现Java居然没提供这样一个方法。目前实现的方式有2个,一个是利用JNI来调用C/C++方法,另一个是使用多线程。
下面是使用JNI的方法:
首先,写出我们的Java类:


public   class  JNIPasswordReader  {

    
private   native  String readPassword();
    
static {
        System.loadLibrary(
" PasswordDLL " );
    }

    
/**
     * 
@param  args
     
*/

    
public   static   void  main(String[] args)  {
        
//  TODO Auto-generated method stub
        JNIPasswordReader reader  =   new  JNIPasswordReader();
        String pwd 
=  reader.readPassword();
        System.out.println(
" \nYour Password is: "   +  pwd);
    }


}

这一段使用System.loadLiberary("..");来加载本地类库,PasswordDLL是文件名,不需要加dll后缀,系统会自动辨认。

编译成JNIPasswordReader.class以后,使用
javah -jni JNIPasswordReader
命令,生成一个JNIPasswordReader.h文件,文件内容如下:

/*  DO NOT EDIT THIS FILE - it is machine generated  */
#include 
< jni.h >
/*  Header for class JNIPasswordReader  */

#ifndef _Included_JNIPasswordReader
#define  _Included_JNIPasswordReader
#ifdef __cplusplus
extern   " C "   {
#endif
/*
 * Class:     JNIPasswordReader
 * Method:    readPassword
 * Signature: ()Ljava/lang/String;
 
*/

JNIEXPORT jstring JNICALL Java_JNIPasswordReader_readPassword
  (JNIEnv 
* , jobject);

#ifdef __cplusplus
}

#endif
#endif

然后,我们需要写一个cpp文件来实现
JNIEXPORT jstring JNICALL Java_JNIPasswordReader_readPassword  (JNIEnv *, jobject);
接口。
于是,我写了一个PasswordDLL.cpp文件,内容如下:

//  这是主 DLL 文件。
#include  " stdafx.h "
#include 
" JNIPasswordReader.h "
#include 
< iostream >
#include 
< iomanip >
#include 
< conio.h >
using   namespace  std;

/*
 * Class:     JNIPasswordReader
 * Method:    readPassword
 * Signature: ()V
 
*/

JNIEXPORT jstring JNICALL Java_JNIPasswordReader_readPassword
  (JNIEnv 
*  env, jobject) {
      
char  str[ 20 =   { 0 }
    jstring jstr;
    
char  ch;
    
char   * pstr  =  str;
    
while ( true )
    
{
        ch 
=  getch();
        
if (isdigit(ch) || isalpha(ch))
        
{
            cout
<< " * " ;
            
* pstr ++   =  ch;
        }

        
else   if (ch  ==   ' \b '   &&  pstr  >  str)
        
{
            
* ( -- pstr)  =   0 ;
            cout
<< " \b \b " ;
        }

        
else   if (ch  ==   0x0A   ||  ch  ==   0x0D )
        
{
            
break ;
        }

    }

    jstr 
=  env -> NewStringUTF(str);
    
return  jstr;
}

我使用VS2005来生成对应的dll文件,在生成之前,需要把$JDK_HOME/include/jni.h和$JDK_HOME/include/win32/jni_md.h这两个文件copy到Microsoft Visio Studio 8/VC/include目录下,我就在这里卡了大概1个小时,一直说找不到jni.h文件

然后就可以使用VS2005来生成dll了,生成好对应的PasswordDLL.dll以后,把该dll文件放到系统变量PATH能找到的地方,比如windows/system32/或者jdk/bin目录,我是放到JDK_HOME/bin下面了
放好以后,
执行java JNIPasswordReader
就可以输入密码了。

关于JNI的更详细内容,可以参考:
《在Windows中实现Java本地方法》http://www.ibm.com/developerworks/cn/java/jnimthds/index.html

我的Password.dll文件
http://www.blogjava.net/Files/richardeee/PasswordDLL.zip


评论

# re: 利用JNI调用C/C++方法实现Java中从控制台输入密码  回复  更多评论   

2007-02-24 22:55 by 喜来乐哈哈
JDK6.0有一个新类Console,可以解决这个问题

Console console = System.console();
if (console != null) {
String user = new String(console.readLine("Enter username:"));
String pwd = new String(console.readPassword("Enter passowrd:"));
console.printf("User is :" + user + "\n");
console.printf("Password is: " + pwd + "\n");
} else {
System.out.println("Console is unavailable");
}

但是在某些情况下System.console()返回一个null。比如输入被重定向。具体的看JDK6的API Doc
http://java.sun.com/javase/6/docs/api/java/io/Console.html

# re: 利用JNI调用C/C++方法实现从控制台输入密码  回复  更多评论   

2007-02-24 23:03 by 喜来乐哈哈
不好意思,刚在你装载的文章里看到我写的方法。我想你应该是知道这种方法的。

是不是这种方法有不符合你的要求的地方?

# re: 利用JNI调用C/C++方法实现从控制台输入密码  回复  更多评论   

2007-02-25 08:09 by Zou Ang
@喜来乐哈哈
呵呵,你的意思是我用JNI么?首先我的JDK版本是5.0的,其次我在写这个之前还真没见到您的那篇JNI文章……其实解决密码输入的最好方法我觉得还是利用JDK6.0的特性,毕竟把Java跟本地代码绑在一块还是不太好

# re: 利用JNI调用C/C++方法实现从控制台输入密码  回复  更多评论   

2007-02-25 10:30 by 喜来乐哈哈
@Zou Ang
同意你的观点, 本地代码是最后一个选择,实在没法才用.

# re: 利用JNI调用C/C++方法实现从控制台输入密码[未登录]  回复  更多评论   

2007-03-14 10:48 by java爱好者
Sun的网站以前有篇文章是讲jdk6之前如何处理密码输入,该文建议的解决方案是用多线程来处理,一个线程专门刷新屏幕输入,防止密码被显示。

# re: 利用JNI调用C/C++方法实现从控制台输入密码  回复  更多评论   

2007-03-14 10:55 by Zou Ang
@java爱好者
这种方法好像在比较慢的机器上会闪烁

只有注册用户登录后才能发表评论。


网站导航: