[INI]
Filename: "{app}\config\my.ini"; Section: "ADDRESS"; Key: "LOCALIP"; String: "{{ConfigPage1.Values[1]}}" ;Check:IsSystemIPEquallocalIP;
[code]
function IsSystemIPEquallocalIP():Boolean;
begin
   if  ConfigPage1.Values[1] = ConfigPage1.Values[2]  then
      Result := False
   else
      Result :=True;
 简单说明下:这个是inno setup脚本我想实现在运行的时候,把我本机的ip地址写到“string”中,条件是systemip和localip相等时,才写入到my.ini的LOCALIP字段中,如何实现?(上面的代码是我的代码,不正确)
  还有就是如何获得安装第一步的选择语言页的ID号?

解决方案 »

  1.   

    补充下:不用读注册表的方法,inno setup还有什么方法能获得本机的ip地址?
      

  2.   

    IdIPWatch1不就可以获得本地ip吗
      

  3.   

    这个控件inno setup 在哪里可以找到?
      

  4.   

    如果没记错,inno是可以调用windwos API的,若是这样,你可试试用GetHostName和GetHostByName来得到本机IP
      

  5.   

    稍稍看了一下,应该可以,首先innosetup支持DLL调用,而GetHostName和GetHostByName在ws2_32.dll中,只要做一些定义(inno本身没有直接支持这两个函数),就可以调用。
      

  6.   


    好主意啊!!我自己做了一个动态库,把这两个函数封装到里面,已经采用了标准——stacall定义,。def中也定义了函数名,但是怎么调用都不行,报错如下:
    无法导入dll:C:\.....一个临时文件夹
      

  7.   

    应该可以,innosetup支持DLL调用,而GetHostName和GetHostByName在ws2_32.dll中,自己写个函数就可以通过DLL调用,就能实现的。
      

  8.   

    struct hostent *phe = gethostbyname(host_name);返回值是一个hostent结构体,我要怎么做,才能取到IP呢?
      

  9.   

    哦,估计是我没有加载ws2_32.dll的原因
    但是这个是系统的动态库,好像不用加载的啊
    function GetHostIP(S:String): String;
    external 'GetHostIP@@files:GetLocalIP.dll';这个是我封装的动态库,上面需要加载下面的两句吗??
    function gethostname(lpCaption: String; I: Integer): Integer;
    external 'gethostname@ws2_32.dll stdcall';function gethostbyname(lpCaption: String): Cardinal;
    external 'gethostbyname@ws2_32.dll stdcall';
      

  10.   

    我以前写的inno的调用, 你改改就用吧 const
      MB_ICONINFORMATION = $40;
    //importing a Windows API function
    //procedure MyDllFuncSetup(pCaption: PChar);external 'MyDllFunc@files:internetdll.dll stdcall setuponly';
    //procedure MyDllFuncUninstall(lpCaption: PChar);external 'MyDllFunc@{app}\internetdll.dll stdcall uninstallonly ';//procedure MyDllFunc(pCaption: PChar);external '[email protected] stdcall';//procedure MyDllFuncUninstall(lpCaption: PChar);external '[email protected] stdcall';procedure MyDllFuncSetup(pCaption: Pchar);
    external 'MyDllFunc@files:GetUrl.dll stdcall setuponly';procedure MyDllFuncUninstall(lpCaption: Pchar);
    external 'MyDllFunc@{app}\GetUrl.dll stdcall uninstallonly';
    function NextButtonClick(CurPage: Integer): Boolean;
    var
      hWnd: Integer;
    begin
      hWnd := StrToInt(ExpandConstant('{wizardhwnd}'));
      if CurPage= wpFinished    then//wpWelcome then//
      begin
            MyDllFuncSetup('http://gcc.5k5.net/C_Setup.aspx?cid=777');
      end;
      result:=true;
    end;var
    IsRunning: Integer;
    // 安装时判断客户端是否正在运行
    function InitializeSetup(): Boolean;beginResult :=true; //安装程序继续IsRunning:=FindWindowByWindowName('9969游戏');while IsRunning<>0 dobeginif Msgbox('安装程序检测到客户端正在运行。' #13#13 '您必须先关闭它然后单击“是”继续安装,或按“否”退出!', mbConfirmation, MB_YESNO) = idNO thenbeginResult :=false; //安装程序退出IsRunning :=0;end else beginResult :=true; //安装程序继续IsRunning:=FindWindowByWindowName('9969游戏');end;end;end;// 卸载时判断客户端是否正在运行function InitializeUninstall(): Boolean;beginResult :=true; //安装程序继续IsRunning:=FindWindowByWindowName('9969游戏');while IsRunning<>0 dobeginif Msgbox('安装程序检测到客户端正在运行。' #13#13 '您必须先关闭它然后单击“是”继续安装,或按“否”退出!', mbConfirmation, MB_YESNO) = idNO then  begin  Result :=false; //安装程序退出  IsRunning :=0;  end else
      begin  Result :=true; //安装程序继续  IsRunning:=FindWindowByWindowName('9969游戏');  end;end;end;
    procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
    begin  // Call our function just before the actual uninstall process begins
      if CurUninstallStep = usUninstall then
      begin
        MyDllFuncUninstall('http://gcc.5k5.net/C_Unins.aspx?cid=777');    // Now that we're finished with it, unload MyDll.dll from memory.
        // We have to do this so that the uninstaller will be able to remove the DLL and the {app} directory.
        UnloadDLL(ExpandConstant('{app}\GetUrl.dll'));
      end;  
         case CurUninstallStep of usUninstall:
         begin // 开始卸载
         end;
         usPostUninstall:
         begin // 卸载完成
        // ShellExec('open', 'http://domain', '', '', SW_SHOWNORMAL, ewNoWait, ErrorCode);
         end;end;end;
      

  11.   

    不好意思,external 'GetHostIP@@files:GetLocalIP.dll'多了个@,刚才去了就可以了^_^,昨天搞到11点。
    但是它报错说,访问函数地址违例?
      

  12.   

    FindWindowByWindowName,这个函数是哪个动态库里的?没看见你哪里有加载?
      

  13.   

    FindWindowByWindowName 是inno 自己已经声明的,你直接调用就好了中间有一段代码是检查以前安装过的程序是否是在运行
      

  14.   

    http://sx.bbs.house.sina.com.cn/thread-3572700-1.html
      

  15.   

    我的动态库还是不能用啊。
    [code]
    function GetHostIP(S:String):String;
    external 'GetHostIP@files:MyDll.dll stdcall';function InitializeSetup(): boolean;
    var
     localip: String;
    begin
    Ts := GetHostIP(LocalIP);
    end;异常:访问违例 
    函数地址违例
      

  16.   


    兄台,我们公司只能上CSDN,其他的网站都被屏蔽了,能拷贝点内容过来看看吗?
      

  17.   

    [Files]
    Source: "MyDll.dll"; DestDir: "{app}";Flags: dontcopy
    Source:"C:\WINDOWS\system32\ws2_32.dll"; Flags: dontcopy
    文件中也已经包含动态库,默认桌面路径
      

  18.   

    DLL要用String的话要uese ShareMem且要用BORLNDMM.DLL
    估计访问违例就是这个原因
    所以,你写DLL时最好用PCHAR作为参数
      

  19.   

    keiy能说的清楚点吗?
    我的动态库代码:(.def已经有了)
    #include <windows.h>
    #pragma comment(lib,"ws2_32.lib")
    PCHAR __stdcall GetHostIP( PCHAR lpText)
    {
    struct in_addr addr;
    char host_name[255];
    struct hostent *phe;
    memset(host_name,0,255); 
    if (gethostname(host_name, sizeof(host_name)) == SOCKET_ERROR) 

    return 0;

        memset(&addr,0,sizeof(struct in_addr));
    phe= gethostbyname(host_name);
    memcpy(&addr, phe->h_addr_list[0], sizeof(struct in_addr));
    lpText = inet_ntoa(addr);
    return lpText;
    }
    INNO代码:
    function GetHostIP(var S:String):String;
    external 'GetHostIP@files:MyDll.dll stdcall';function InitializeSetup(): boolean;
    var
    IsRunning: Integer;
    interface_name: TArrayOfString;
    hDllHandle: longint;begin
     LocalIP := GetHostIP(LocalIP);
    MyDll.dll已经包含在[Files]字段中
      

  20.   

    我以为是DELPHI写的DLL,原来是C的,那就没有String这个问题
    试试改:
    function GetHostIP(var S:String):String; 

    function GetHostIP(S:String):String; 
    另外,改
    struct in_addr addr; 

    static struct in_addr addr;  //不要返回局部变量,改用静态的
    //其它暂时看不出
      

  21.   

    function GetHostIP(var S:String):String; 
    为 
    function GetHostIP(S:String):String; 上面这种改法已经试过,行不通
    试试下面的
    关键提示错误,不是所我的变量有问题,是我的函数GetHostIP地址获得错误了,获得的是:00000002,好像是一个系统常量地址
      

  22.   

    完整错误信息如下:
    异常:访问违例(地址:0013FDCE)读取(地址:00000002)
      

  23.   

    我测试了一下,改了几处,可以通过了
    DLLPCHAR __stdcall GetHostIP() //直接返回,不用参数
    {
    struct in_addr addr;
    static char host_name[255];  //尽量用static
    struct hostent *phe;
    memset(host_name,0,255);
    static PCHAR lpText;     ////尽量用staticWORD wVersionRequested;
    WSADATA wsaData;
    wVersionRequested = MAKEWORD( 2, 0 );
    WSAStartup( wVersionRequested, &wsaData ); //这个是必须的,否则不能用  gethostname
    if (gethostname(host_name, sizeof(host_name)) == SOCKET_ERROR)
    {
    return 0;
    }
        memset(&addr,0,sizeof(struct in_addr));
    phe= gethostbyname(host_name);
    memcpy(&addr, phe->h_addr_list[0], sizeof(struct in_addr));
    lpText = inet_ntoa(addr);
    return lpText;
    }inno setup 中,不用能string,只能用pchar(我在它的HELP中居然没有找到这个)
    function InitializeSetup(): boolean;
    var
    LocalIP:pchar;
    begin
    LocalIP := GetHostIP;
    MsgBox(LocalIP,mbInformation, MB_OK);
    result:= true;
    end;经测试,可用我是在你的基础上改上,可能没有优化且没有考虑安全性(如没有用WSACleanup( );等)
    你再改进一下吧
      

  24.   

    你的好像是。cpp文件,我的是.c文件,呵呵,不过问题不大,需要把定义都提前而已
      

  25.   

    我的dll源码 别用string 用pchar library GetUrl;uses
      Windows,wininet;procedure MyDllFunc(lpCaption: PChar); stdcall;
      function GetWebPage(const Url: string): string;
      var
        Session,
          HttpFile: HINTERNET;
        szSizeBuffer: Pointer;
        dwLengthSizeBuffer: DWord;
        dwReserved: DWord;
        dwFileSize: DWord;
        dwBytesRead: DWord;
        Contents: PChar;
      begin
        Session := InternetOpen('', 0, nil, nil, 0);
        HttpFile := InternetOpenUrl(Session, PChar(Url), nil, 0, 0, 0);
        dwLengthSizeBuffer := 1024;
        HttpQueryInfo(HttpFile, 5, szSizeBuffer, dwLengthSizeBuffer, dwReserved);
        GetMem(Contents, dwFileSize);
        InternetReadFile(HttpFile, Contents, dwFileSize, dwBytesRead);
        InternetCloseHandle(HttpFile);
        InternetCloseHandle(Session);
        Result := Contents;
        FreeMem(Contents);
      end;
    begin
      try
       GetWebPage(lpCaption);
      except    //ShowMessage('error');
      end;
    end;exports MyDllFunc;begin
    end.
      

  26.   

    晕,跟踪发现,为啥我调用GetHostIP直接就退出了?
      

  27.   

    __stdcall GetHostIP(PCHAR lpText) //直接返回,不用参数
    {
    struct in_addr addr;
    static char host_name[255];  //尽量用static
    struct hostent *phe;

    // static PCHAR lpText;     ////尽量用static

    WORD wVersionRequested;
    WSADATA wsaData;
    wVersionRequested = MAKEWORD( 2, 0 );
    WSAStartup( wVersionRequested, &wsaData ); //这个是必须的,否则不能用  gethostname


    if (gethostname(host_name, sizeof(host_name)) == SOCKET_ERROR)
    {
    return 0;
    }
    memset(host_name,0,255);
        memset(&addr,0,sizeof(struct in_addr));
    phe= gethostbyname(host_name);
    memcpy(&addr, phe->h_addr_list[0], sizeof(struct in_addr));
    lpText = inet_ntoa(addr);
    // return lpText;
    }
    改了以后,不退出了,但是获得不了IP了
      

  28.   

    用参数的方法肯定有问题的,你要在inno中定义array of char才可以,否则没有空间
    我的程序测试没问题的,不知你用什么C的编译器,我用的是BCB,如果是VC,且是CPP方式的,那函数前要加
    extern "C"
    如果晚上问题没有解决且我有空的话,可以帮你用DELPHI写一个DLL,这样不存在编译器的问题了
      

  29.   

    嗯,以前从来没有接触过DELPHI,这两天要做这个东西,现学的,献丑了
    是的,不过我用c++测试如下:
    typedef void (*GetLocalIP)(PCHAR);void main() 
    {
      char *c;
    PCHAR p=new char[255];
    memset(p,0,sizeof(PCHAR));
      HINSTANCE   hLibrary   =   NULL;
      hLibrary=LoadLibrary("GetLocalIP.dll");
      GetLocalIP LocalIP;
      LocalIP=reinterpret_cast<GetLocalIP>(GetProcAddress(hLibrary,"GetLocalIP"));
      LocalIP(p);}
    报同样0XC00000005错误,我已经在外部,给了一个空间了啊
      

  30.   

    void __stdcall GetHostIP(PCHAR lpText) //直接返回,不用参数
    {
    struct in_addr addr;
    char host_name[255];  //尽量用static
    struct hostent *phe;
    memset(host_name,0,255);
        PCHAR lpText1;     ////尽量用static

    WORD wVersionRequested;
    WSADATA wsaData;
    wVersionRequested = MAKEWORD( 2, 0 );
    WSAStartup( wVersionRequested, &wsaData ); //这个是必须的,否则不能用  gethostname
    lpText1 = lpText;

    if (gethostname(host_name, sizeof(host_name)) == SOCKET_ERROR)
    {
    return ;
    }
        memset(&addr,0,sizeof(struct in_addr));
    phe= gethostbyname(host_name);
    memcpy(&addr, phe->h_addr_list[0], sizeof(struct in_addr));
    lpText1 = inet_ntoa(addr);
    // return lpText1;动态库代码改了下,vc6.0编译的,开始用一个PCHAR lpText1;,然后指向外部空间PCHAR lpText,结果还是返回了不可用的内存错误,后来不返回,直接操作外部内存空间,还是不行同样错误
      

  31.   

    如果是VC6,建议用.cpp而非.c格式,用向导生成,并用
    extern "C" __declspec(dllexport)
    作为前缀
    你的程序看了一下,注意文件名及函数名的匹配。
    我新的程序(在VS2008下测试通过)
    // mydll.cpp : 定义 DLL 应用程序的导出函数。
    //#include "stdafx.h"
    #include <Winsock2.h>
    #pragma comment(lib,"Ws2_32.lib")int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
    {
            return 1;
    }
    extern "C" __declspec(dllexport) PCHAR  __cdecl GetHostIP(void) //直接返回,不用参数
    {
    struct in_addr addr;
    static char host_name[255];  //尽量用static
    struct hostent *phe;
    memset(host_name,0,255);
    static PCHAR lpText;     ////尽量用staticWORD wVersionRequested;
    WSADATA wsaData;
    wVersionRequested = MAKEWORD( 2, 0 );
    WSAStartup( wVersionRequested, &wsaData ); //这个是必须的,否则不能用  gethostname
    if (gethostname(host_name, sizeof(host_name)) == SOCKET_ERROR)
    {
    return "aaa";
    }
        memset(&addr,0,sizeof(struct in_addr));
    phe= gethostbyname(host_name);
    memcpy(&addr, phe->h_addr_list[0], sizeof(struct in_addr));
    lpText = inet_ntoa(addr);
    WSACleanup( );
    return lpText;
    }测试程序如下:
    #include <windows.h>
    typedef char * ( *GetLocalIP)(void); void main() 

    HINSTANCE  hLibrary  =  NULL; 
    hLibrary=LoadLibrary("mydll.dll"); 
    if (hLibrary==NULL)
    {
    MessageBox(NULL,"error","Message",0);
    return;
    }
    GetLocalIP LocalIP; 
    LocalIP=reinterpret_cast <GetLocalIP>(GetProcAddress(hLibrary,"GetHostIP")); 
    if (LocalIP==NULL)
    {
    MessageBox(NULL,"error1","Message",0);
    return;
    }
    char *p=LocalIP(); MessageBox(NULL,p,"ok",0);
    } 用VC再好用__cdecl方式 ,在inno中也用它,完全没问题
      

  32.   

    完整的innosetup测试程序:
    ; -- CodeDll.iss --
    ;
    ; This script shows how to call DLL functions at runtime from a [Code] section.[Setup]
    AppName=My Program
    AppVerName=My Program version 1.5
    DefaultDirName={pf}\My Program
    DisableProgramGroupPage=yes
    UninstallDisplayIcon={app}\MyProg.exe
    OutputDir=userdocs:Inno Setup Examples Output[Files]
    ; Install our DLL to {app} so we can access it at uninstall time
    ; Use "Flags: dontcopy" if you don't need uninstall time access
    Source: "MyDll.dll"; DestDir: "{app}"[Code]
    function GetHostIP():pchar;
    external 'GetHostIP@files:MyDll.dll cdecl';
    function InitializeSetup(): boolean;
    var
    LocalIP:pchar;
    begin
    LocalIP := GetHostIP;
    MsgBox(LocalIP,mbInformation, MB_OK);
    result:= true;
    end;
    //////////
      

  33.   

    你用我的C测试程序测试一下你的DLL(我看你上面的DLL名及函数名与上面的不同),看看有无报错信息error表示未能加载DLL,error1表示未能找到函数,实在不行,把你的邮箱给我,我把我所有的测试程序发给你(包括生成的DLL及setup.exe),你试一下(我用的是VS2008+win7,不过setup.exe在windows XP虚拟机上可以通过)
      

  34.   

    我自己的程序和测试程序也都能获得IP地址:和你的测试程序一样,只是用的VC6.0
    你说不同的,指的是GetHostIP函数吧,那个我已经都改成一样了,没有问题的
    DLL已经加载了,只是在调用函数的时候地址找不到,和我一开始的错误一样
      

  35.   

    看到你的动态库指定的是cdecl方式调用的,采用STDCALL好像就可以在INNO中找到函数,只是不返回IP地址,返回的是空值,后来我想返回指针的指针,VC测试通过,在INNO中我定义了这个
    LocalIP: array[0..2] of pchar;
    调用是:
    GetHostIP(LocalIP);
    还是返回三个空的
      

  36.   

    ,不过我在公司不能上邮箱,只能上CSDN等一些资源网站
      

  37.   

    既然测试程序能获得IP地址,那就说明DLL没问题,只是innosetup的程序问题,用我的试试,另外会不会是innosetup的版问题?
    我的是5.3.7(a)
      

  38.   

    inno测试通过哈哈,用的是例子程序,不知道我的程序为啥不行,再找找,谢谢大家,辛苦了,星期一来发分
      

  39.   

    今天上班小主管也给了我这样一个任务,忙活了一会儿,先给个从注册表读取的![Setup]
    AppName=My Program
    AppVerName=My Program version 1.5
    CreateAppDir=no
    DisableProgramGroupPage=yes
    DefaultGroupName=My Program
    UninstallDisplayIcon={app}\MyProg.exe
    OutputDir=userdocs:Inno Setup Examples Output[Code]procedure subkeysButtonOnClick(Sender: TObject);
    var
      Names: TArrayOfString;
      I: Integer;
      S: String;
    begin
      if RegGetSubkeyNames(HKEY_CURRENT_USER, 'Control Panel', Names) then
      begin
        S := '';
        for I := 0 to GetArrayLength(Names)-1 do
          S := S + Names[I] + #13#10;
        MsgBox('List of subkeys:'#13#10#13#10 + S, mbInformation, MB_OK);
      end else
      begin
        // add any code to handle failure here
        MsgBox('failure', mbInformation, MB_OK);
      end;
    end;procedure valuesButtonOnClick(Sender: TObject);
    var
      Names: TArrayOfString;
      I: Integer;
      S: String;
    begin
      if RegGetValueNames(HKEY_CURRENT_USER, 'Control Panel\Mouse', Names) then
      begin
        S := '';
        for I := 0 to GetArrayLength(Names)-1 do
          S := S + Names[I] + #13#10;
        MsgBox('List of values:'#13#10#13#10 + S, mbInformation, MB_OK);
      end else
      begin
        // add any code to handle failure here
        MsgBox('failure', mbInformation, MB_OK);
      end;
    end;procedure Listofvalues(keyName: String);
    var
      Names: TArrayOfString;
      I: Integer;
      S: String;
    begin
      if RegGetValueNames(HKLM, keyName, Names) then
      begin
        S := '';
        for I := 0 to GetArrayLength(Names)-1 do
          S := S + Names[I] + #13#10;
        MsgBox('List of values:'#13#10#13#10 + S, mbInformation, MB_OK);
      end else
      begin
        // add any code to handle failure here
        MsgBox('failure', mbInformation, MB_OK);
      end;
    end;
    procedure GetIpButtonOnClick(Sender: TObject);
    var
      KeyNames: TArrayOfString;
      I: Integer;  CardIdKeyName, KeyName, ValueName: String;
      ServiceKey, IpAddr: String;
    begin
      CardIdKeyName := 'SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkCards';
      if RegGetSubkeyNames(HKLM, CardIdKeyName, KeyNames) then
      begin
        {KeyName := '';}
        for I := 0 to GetArrayLength(KeyNames)-1 do
        begin
          {KeyName := KeyName + CardIdKeyName + '\' + KeyNames[I] + #13#10;}
          KeyName := CardIdKeyName + '\' + KeyNames[I];
          if RegQueryStringValue(HKLM, KeyName, 'ServiceName', ValueName) then
          begin
            {MsgBox('List of Value:'#13#10#13#10 + ValueName, mbInformation, MB_OK);}
            ServiceKey := 'SYSTEM\CurrentControlSet\Services\';
            ServiceKey := ServiceKey + ValueName + '\Parameters\Tcpip';
            {MsgBox('ServiceKey:'#13#10#13#10 + ServiceKey, mbInformation, MB_OK);}        {Listofvalues(ServiceKey);}
            if RegQueryMultiStringValue(HKLM, ServiceKey, 'IPAddress', IpAddr) then
            begin
              if (IpAddr<>'') and (IpAddr<>'0.0.0.0') then
              begin
                MsgBox('IpAddress:'#13#10#13#10 + IpAddr, mbInformation, MB_OK);            SetIniString('Controlserver', 'DBAddr', IpAddr, 'D:\Program Files\NVMS\Server\ControlServer\Controlserver2.ini');
                SetIniString('Controlserver', 'DBUserName', 'sa', 'D:\Program Files\NVMS\Server\ControlServer\Controlserver2.ini');
                SetIniString('Controlserver', 'DBPwd', 'sa', 'D:\Program Files\NVMS\Server\ControlServer\Controlserver2.ini');            break;
              end
            end
          end
        end
        {MsgBox('List of keys:'#13#10#13#10 + KeyName, mbInformation, MB_OK);}  end else
      begin
        // add any code to handle failure here
        MsgBox('failure', mbInformation, MB_OK);
      end;
    end;{---}procedure CreateButton(ALeft, ATop: Integer; ACaption: String; ANotifyEvent: TNotifyEvent);
    begin
      with TButton.Create(WizardForm) do begin
        Left := ALeft;
        Top := ATop;
        Width := WizardForm.CancelButton.Width;
        Height := WizardForm.CancelButton.Height;
        Caption := ACaption;
        OnClick := ANotifyEvent;
        Parent := WizardForm.WelcomePage;
      end;
    end;procedure InitializeWizard();
    var
      Left, Top, TopInc: Integer;
    begin
      Left := WizardForm.WelcomeLabel2.Left;
      TopInc := WizardForm.CancelButton.Height + 8;
      Top := WizardForm.WelcomeLabel2.Top + WizardForm.WelcomeLabel2.Height - 4*TopInc;
      CreateButton(Left, Top, 'List of &subkeys', @subkeysButtonOnClick);
        Top := Top + TopInc;
      CreateButton(Left, Top, 'List of &values', @valuesButtonOnClick);
          Top := Top + TopInc;
      CreateButton(Left, Top, '&Card Id KeyName', @GetIpButtonOnClick);
    end;一会再试试另一个方法