请问各位高手 如何实现IC卡与计算通信啊?
稍微写一小段代码就可以拉
先谢谢了

解决方案 »

  1.   

    是不是非接触的ID卡????
    如果是我可以给你发个DLL与例子.
      

  2.   

    TO  jensgn(风儿.Net) 我也想看看你的代码啊,我正好也需要这样的代码来参考,能不能偶一份哟
      

  3.   

    SPCOM 控件专门做软件与硬件之间的通信。要比MSCOM 好多了。
    你找找看。还有你IC卡是非接触式的还是用读卡器读的那一种?
    你买的硬件产品,可以问问厂家有没有DEMO 或 SDK 开发包。
    用SPCOM 是没什么问题的。要不行你用API 写。
      

  4.   

    对!
    可以用SPCOM 控件,MSCOM 控件或者API 。
      

  5.   

    unit UFunLib;
    interface
    Uses
      Windows,
      Controls,
      SysUtils, Dialogs,
      Classes;//按指定的端口号及波特率初始化串口,同时检测该端口上是否连接了读写器。
    Function MCS_InitComm(Const _bPort: Byte; Const _dwCommBaudRate: DWORD): Word; Stdcall; External
    'MCS_SR.DLL';
    //关闭读写器正在使用的串口
    Function MCS_ExitComm(): Word; Stdcall; External 'MCS_SR.DLL';
    //提供接口函数调用返回值的描述。
    Function MCS_ErrorMsg(Const _wErrNo: Word; _bErrMsg: PChar): Word; Stdcall; External 'MCS_SR.DLL';
    //控制读写器的指示灯的状态
    Function MCS_LED(Const _bOnOff: Byte): Word; Stdcall; External 'MCS_SR.DLL';
    //设置随后操作中的字符串传递方式
    Function MCS_SetStringMode(Const _bStringMode: Byte): Word; Stdcall; External 'MCS_SR.DLL';
    //选择AT45D系列的卡型,并给卡片上电
    Function AT45D_OpenCard(Const _bCardType: Byte): Word; Stdcall; External 'MCS_SR.DLL';
    //给AT45D系列卡片下电
    Function AT45D_CloseCard(): Word; Stdcall; External 'MCS_SR.DLL';
    //将一串字符写入到AT45D系列卡片的存储区内
    Function AT45D_BundleWriteChar(Const _dwAddr, _dwLength: DWORD; _bWriteData: PChar): Word; Stdcall;
      External 'MCS_SR.DLL';
    //从AT45D系列卡片的存储区读取一串字符  
    Function AT45D_BundleReadChar(Const _dwAddr, _dwLength: DWORD; _bWriteData: PChar): Word; Stdcall;
      External 'MCS_SR.DLL';
    //单重DES算法加密
    function  DES_Encrypt(const _bPlainText,_bKey:PChar ):WORD;Stdcall;  External 'MCS_SR.DLL';
    function  SingleDES_Encrypt(const mingwen,miyao:string ):String;Stdcall;
    //单重DES算法解密
    function DES_Decrypt(const _bCipherText,_bKey:PChar ):WORD;Stdcall;  External 'MCS_SR.DLL'; 
    function SendCard(const AddFlag:int64;value,StrFlag:string):integer;stdcall;
    function ReadCard(const AddFlag,ReadLen:int64;StrFlag:string):String;stdcall;
    Function OpenCard(Const _bPort: integer; Const _dwCommBaudRate: integer):integer;stdcall;
    implementationfunction  SingleDES_Encrypt(const mingwen,miyao:string ):string;Stdcall;
    var
      pstr_ErrDes,pstr_Mingwen,pstr_Miyao:PChar;
      int_Ret:integer;
    begin
      result:='';
      Try
        GetMem(pstr_Mingwen, 255);
        GetMem(pstr_ErrDes, 255);
        GetMem(pstr_Miyao, 255);
       
        //字符串传递方式
        int_Ret:= MCS_SetStringMode(Byte(1));    If int_Ret = 0 Then
          Begin
            pstr_Mingwen:= StrCopy(pstr_Mingwen, PChar(Mingwen));
            pstr_Miyao:= StrCopy(pstr_Miyao, PChar(Miyao));        int_Ret:=  DES_Encrypt(pstr_Mingwen,pstr_Miyao );  //单重DES算法加密
            If int_Ret <> 0 Then
              Begin
                If MCS_ErrorMsg(int_Ret, pstr_ErrDes) = 0 Then
                  begin
                    ShowMessage('DES算法加密操作失败,' + String(pstr_ErrDes));
                    exit;
                  end
                Else
                  begin
                    ShowMessage('DES算法加密操作失败,错误描述不可用!');
                    exit;
                  end;
              End;
            result:= pstr_Mingwen ;         
          End
        Else
          Begin
            If MCS_ErrorMsg(int_Ret, pstr_ErrDes) = 0 Then
              begin
                ShowMessage('字符串传递方式设置操作失败,' + String(pstr_ErrDes));
                exit;
              end
            Else
              begin
                ShowMessage('字符串传递方式设置操作失败,错误描述不可用!');
                exit;
              end;
          End;
      Finally
        FreeMem(pstr_ErrDes, 255);
        FreeMem(pstr_Mingwen, 255);
        FreeMem(pstr_Miyao, 255);
      End;
    end;Function OpenCard(Const _bPort: integer; Const _dwCommBaudRate: integer):integer;stdcall;
    var
      int_Ret:integer;
      pstr_ErrDes,pstr_ICType:pchar;
    begin
      result:=-1 ;
          Try
            GetMem(pstr_ErrDes, 255);
            GetMem(pstr_ICType, 255);        //串口设置按指定的端口号及波特率初始化串口,检测该端口上是否连接了读写器;
            int_Ret:= MCS_InitComm(Byte(_bPort), DWORD(_dwCommBaudRate));
            if  int_Ret <> 0 then
              begin
                If MCS_ErrorMsg(int_Ret, pstr_ErrDes) = 0 Then
                  begin
                    ShowMessage('串口设置失败,' + String(pstr_ErrDes));
                    exit;
                  end
                Else
                  begin
                    ShowMessage('串口设置失败,错误描述不可用!');
                    exit;
                  end;
              end;         //设置随后操作中的字符串传递方式 ASCII字符串
            int_Ret:= MCS_SetStringMode(Byte(1));        If int_Ret = 0 Then
              Begin
                int_Ret:= AT45D_OpenCard(Byte(51));  //选择AT45D系列的卡型为AT45D041 卡型代码51 并卡上电             If int_Ret <> 0 Then
                  Begin
                    If MCS_ErrorMsg(int_Ret, pstr_ErrDes) = 0 Then
                      begin
                        ShowMessage('操作失败,' + String(pstr_ErrDes));
                        exit;
                      end
                    Else
                      begin
                        ShowMessage('操作失败,错误描述不可用!');
                        exit;
                      end;
                  End;
               End
            Else
              Begin
                If MCS_ErrorMsg(int_Ret, pstr_ErrDes) = 0 Then
                  begin
                    ShowMessage('卡上电操作失败,' + String(pstr_ErrDes));
                    exit;
                  end
                Else
                  begin
                    ShowMessage('卡上电操作失败,错误描述不可用!');
                    exit;
                  end;
              End;
          Finally
            FreeMem(pstr_ErrDes, 255);
            FreeMem(pstr_ICType, 255);
          End;
      result:=1;
    end;end.
      

  6.   

    可以用SPCOM 控件,MSCOM 控件或者API 
    Windows操作系统的机制禁止应用程序直接访问计算机硬件,但它为程序员提供了一系列的标准API函数,使得应用程序的编制更加方便并且免除了对有关硬件的调试麻烦。在Windows95/NT中,原来Windows3.X的WM_COMMNOTIFY消息已被取消,操作系统为每个通信设备开辟了用户可定义大小的读/写缓冲区,数据进出通信口均由操作系统后台完成,应用程序只需对读/写缓冲区操作即可。WIN95/NT中几个常用的串行通信操作函数如下:
       CreatFile  : 打开串行口
       CloseHandle : 关闭串行口
       SetupComm  : 设置通信缓冲区的大小
       ReadFile   : 读串口操作
       WriteFile  : 写串口操作
       SetCommState : 设置通信参数
       GetCommState : 获取默认通信参数
       ClearCommErro: r清除串口错误并获取当前状态除上述几个函数外,还要经常用到一个重要的记录DCB(设备控制块)。DCB中记录有可定义的串行口参数,设置串行口参数时必须先用GetCommState函数将系统默认值填入DCB控制块,然后才可把用户想改变的自定义值设定。在WIN95/NT中进行串行通信除了解基本的通信操作函数外,还要掌握多线程编程。线程是进程内部执行的路径,是操作系统分配CPU时间的基本实体。每个进程都由单线程开始完成应用程序的执行。串行通信需要利用多线程技术实现,其主要的处理逻辑可以表述如下:进程一开始先由主线程做一些必要的初始化工作,然后主线程根据需要在适当时候建立通信监视线程监视通信口,当指定的串行口事件发生时,向主线程发送WM_COMMNOTIFY消息(由于WIN95取消了WM_COMMNOTIFY消息,因此必须自己创建),主线程对其进行处理。若不需要WM_COMMNOTIFY消息,则主线程终止通信监视线程。多线程同时执行,将会引起对共享资源的冲突。为避免冲突,就要用同步多线程对共享资源进行访问。WIN95提供了许多保持线程同步的方法,笔者采用创建事件对象来保持线程同步。通过CraeteEvent()创建事件对象,使用SetEvent() 或PulseEvent()函数将事件对象设置成信号同步。在应用程序中,利用WaitSingleObject() 函数等待同步的触发,等到指定的事件被其它线程设置为有信号时,才继续向下执行程序。Delphi下的具体实现方法Delphi的强大功能和支持多线程的面向对象编程技术,使得实现串行通信非常简单方便。它通过调用外部的API函数来实现,主要步骤如下:首先,利用CreateFile函数打开串行口,以确定本应用程序对此串行口的占有权,并封锁其它应用程序对此串口的操作;其次,通过GetCommState函数填充设备控制块DCB,再通过调用SetCommState函数配置串行口的波特率、数据位、校验位和停止位。然后,创建串行口监视线程监视串行口事件。在此基础上就可以在相应的串口上操作数据的传输;最后,用CloseHandle函数关闭串行口。具体的程序如下,本程序用Delphi3.0编制在Win95环t境下调试通过,已投入实际应用中,供广大读者参考。程序:
    unit comdemou;
    interface
    uses
    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
    const
    Wm_commNotify=Wm_User+12;
    type
    TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    private
    Procedure comminitialize;
    Procedure MsgcommProcess(Var Message:Tmessage); Message Wm_commnotify;
    { Private declarations }
    public
    { Public declarations }
    end;
    // 线 程 声 明
    TComm=Class(TThread)
    protected
    procedure Execute;override;
    end;
    var
    Form1: TForm1;
    hcom,Post_Event:Thandle;
    lpol:Poverlapped;
    implementation
    {$R *.DFM}
    Procedure TComm.Execute; // 线 程 执 行 过 程
    var
    dwEvtMask:Dword;
    Wait:Boolean;
    Begin
    fillchar(lpol,sizeof(toverlapped),0);
    While True do Begin
    dwEvtMask:=0;
    Wait:=WaitCommEvent(hcom,dwevtmask,lpol); // 等 待 串 行 口事 件;
    if Wait Then Begin
    waitforsingleobject(post_event,infinite); // 等 待 同 步 事件 置 位;
    resetevent(post_event); // 同 步 事 件 复 位;
    PostMessage(Form1.Handle,WM_COMMNOTIFY,0,0);// 发 送 消 息;
    end;
    end;
    end;
    procedure Tform1.comminitialize; // 串 行 口 初 始 化
    var
    lpdcb:Tdcb;
    Begin
    hcom:=createfile('com2',generic_read or generic_write,0,nil,open_existing,
    file_attribute_normal or file_flag_overlapped,0);// 打 开 串行 口
    if hcom=invalid_handle_value then
    else
    setupcomm(hcom,4096,4096); // 设 置 输 入, 输 出 缓 冲区 皆 为4096 字 节
    getcommstate(hcom,lpdcb); // 获 取 串 行 口 当 前 默 认设 置
    lpdcb.baudrate:=2400;
    lpdcb.StopBits:=1;
    lpdcb.ByteSize:=8;
    lpdcb.Parity:=EvenParity; // 偶 校 验
    Setcommstate(hcom,lpdcb);
    setcommMask(hcom,ev_rxchar);
    // 指 定 串 行 口 事 件 为 接 收 到 字 符;
    end;
    Procedure TForm1.MsgcommProcess(Var Message:Tmessage);
    var
    Clear:Boolean;
    Coms:Tcomstat;
    cbNum,ReadNumber,lpErrors:Integer;
    Read_Buffer:array[1..100]of char;
    Begin
    Clear:=Clearcommerror(hcom,lpErrors,@Coms);
    if Clear Then Begin
    cbNum:=Coms.cbInQue;
    ReadFile(hCom,Read_Buffer,cbNum,ReadNumber,lpol);
    // 处 理 接 收 数 据
    SetEvent(Post_Event); // 同 步 事 件 置 位
    end;
    end;
    procedure TForm1.FormCreate(Sender: TObject);
    begin
    comminitialize;
    post_event:=CreateEvent(nil,true,true,nil); // 创 建 同 步事 件;
    Tcomm.Create(False); // 创 建 串 行 口 监 视 线 程;
    end;
    end.
      

  7.   

    //**************Serial Communication Function**************//
      function  OpenComm(CommName:string):THandle;
      procedure SetBaudRate(hComm:THandle; BaudRate:cardinal);
      procedure SetFrameStyle(hComm:THandle; ByteSize:byte; StopBits:byte);
      procedure SetParity(hComm:THandle; Parity:byte; ParityCheck:boolean);
      procedure EnableDtr(hComm:THandle);
      procedure EnableRts(hComm:THandle);
      procedure ReadComm(hComm:THandle;
                         SendStr:string;
                         var recvstr:string;
                         var dwBytesRead:DWORD );
      procedure CloseComm(hComm:THandle);  function  OpenComm(CommName:string):THandle;
      var
        timeout:TCommTimeouts;
      begin
        Result := CreateFile( Pchar(CommName),
                              GENERIC_READ or GENERIC_WRITE,
                              0,
                              nil,
                              OPEN_EXISTING,
                              FILE_ATTRIBUTE_NORMAL,
                              0 );
        if Result = INVALID_HANDLE_VALUE then
        begin
          Raise Exception.Create(CommErrMessage1);
          Exit;
        end;
        if GetFileType( Result ) <> FILE_TYPE_CHAR then
        begin
          CloseHandle(Result);
          Result := INVALID_HANDLE_VALUE;
          Raise Exception.Create(CommErrMessage2);
          Exit;
        end;
        if not SetupComm( Result, 4096, 4096 ) then
        begin
           CloseHandle(Result);
           Result := INVALID_HANDLE_VALUE;
           Raise Exception.Create(CommErrMessage3);
           Exit;
        end;
        PurgeComm( Result, PURGE_TXABORT or PURGE_RXABORT or
                   PURGE_TXCLEAR or PURGE_RXCLEAR );
        timeout.ReadIntervalTimeout := MAXDWORD;
        timeout.ReadTotalTimeoutMultiplier := 0;
        timeout.ReadTotalTimeoutConstant := 0;
        SetCommTimeOuts(Result,timeout);
      end;  procedure SetBaudRate(hComm:THandle; BaudRate:cardinal);
      var
        Dcb: Tdcb;
      begin
        if hComm <=0 then
        begin
          Raise Exception.Create(CommErrMessage4);
          Exit;
        end;
        GetCommState(hComm,Dcb);
        Dcb.BaudRate := BaudRate;
        SetCommState(hComm,Dcb);
      end;  procedure SetFrameStyle(hComm:THandle; ByteSize:byte; StopBits:byte);
      var
        Dcb: Tdcb;
      begin
        if hComm <=0 then
        begin
          Raise Exception.Create(CommErrMessage4);
          Exit;
        end;
        GetCommState(hComm,Dcb);
        Dcb.ByteSize := ByteSize;
        Dcb.StopBits := StopBits;
        SetCommState(hComm,Dcb);
      end;  procedure SetParity(hComm:THandle; Parity:byte; ParityCheck:boolean);
      var
        Dcb: Tdcb;
      begin
        if hComm <=0 then
        begin
          Raise Exception.Create(CommErrMessage4);
          Exit;
        end;
        GetCommState(hComm,Dcb);
        Dcb.Flags := Dcb.Flags and $FFFD;
        if ParityCheck then
          Dcb.Flags := Dcb.Flags or 2;// Enable parity check
        Dcb.Parity := Parity;
        SetCommState(hComm,Dcb);
      end;  procedure EnableDtr(hComm:THandle);
      var
        dcb:Tdcb;
      begin
        if hComm <=0 then
        begin
          Raise Exception.Create(CommErrMessage4);
          Exit;
        end;
        GetCommState(hComm,Dcb);
        dcb.Flags := dcb.Flags and $ffcf;
        dcb.Flags := dcb.Flags or $10;        //enable Dtr
        SetCommState(hComm,Dcb);
      end;  procedure EnableRts(hComm:THandle);
      var
        dcb:Tdcb;
      begin
        if hComm <=0 then
        begin
          Raise Exception.Create(CommErrMessage4);
          Exit;
        end;
        GetCommState(hComm,Dcb);
        dcb.Flags := dcb.Flags and $cfff;
        dcb.Flags := dcb.Flags or $1000;      //enable Rts
        SetCommState(hComm,Dcb);
      end;  procedure ReadComm( hComm:THandle;
                          SendStr:string;
                          var recvstr:string;
                          var dwBytesRead:DWORD );
      var
        dwWhereToStartWriting: DWORD;
        dwNumberOfBytesWritten:DWORD;
        dwNumberOfBytesToWrite:DWORD;
        Inchar: Char; //接收缓冲区
        st,et,internal: cardinal;
        HaveRecieved: Boolean;
      begin
        if hComm <=0 then
        begin
          Raise Exception.Create(CommErrMessage4);
          Exit;
        end;
        PurgeComm( hComm, PURGE_TXABORT or PURGE_RXABORT or
                   PURGE_TXCLEAR or PURGE_RXCLEAR ) ;
        dwWhereToStartWriting := 1;
        dwNumberOfBytesWritten := 0;
        dwNumberOfBytesToWrite := Length(sendstr);    repeat
          WriteFile( hComm,
                     sendstr[dwWhereToStartWriting],
                     dwNumberOfBytesToWrite,
                     dwNumberOfBytesWritten,
                     nil );
          Dec( dwNumberOfBytesToWrite, dwNumberOfBytesWritten );
          Inc( dwWhereToStartWriting, dwNumberOfBytesWritten )
        until (dwNumberOfBytesToWrite <= 0);
        recvstr := '';
        st := GetTickCount;
        HaveRecieved := false;
        dwBytesRead := 0;
        while true do
        begin
          dwNumberOfBytesToWrite := 0;
          readfile(hComm,InChar,1,dwNumberOfBytesToWrite,nil);
          if dwNumberOfBytesToWrite > 0 then
          begin
            recvstr := recvstr + InChar;
            Inc(dwBytesRead);
            st := GetTickCount;
            HaveRecieved := True;
          end
          else
          begin
            et := GetTickCount;
            if HaveRecieved then internal := 500
            else internal := 3000;
            if (et-st) > internal
            then Exit;
          end;
        end;
      end;  procedure CloseComm(hComm:THandle);
      begin
        if (hComm>0) then
          CloseHandle(hComm);
      end;
      

  8.   

    我感觉用Mscomm和SPcomm控件是最好的,
      方便实用,
    简单
        高效
      

  9.   

    http://www.56kc.net/web/commwatch.aspx这个是串口的最好的VCL,用串口不可以直接读写IC卡(居本人了解,可能有错误),最好是利用单片机实现,然后和计算机通讯,实现读写IC卡的功能.不过,并口到是可以直接读写IC卡的.
      

  10.   

    tmscomm就可以  其实用什么都是一样的 谁方便用谁
      

  11.   

    每个IC卡读卡器都附带了DLL文件的,用来读写IC卡