手动部署单机单节点

(我的博客即将入驻“云栖社区”,诚邀技术同仁一同入驻。)

之前发布过官方的e2e部署方案,由于环境或是访问权限等各种问题,还是有相当一部分码友无法成功跑起来,故此,本章将来一次纯手动操作的部署。

主要需要的步骤如下:

  1:环境整理

  2:环境部署

  3:源码安装

  4:生成证书文件

  5:orderer节点处理

  6:peer节点处理

  7:channel创建加盟

  8:chaincode安装部署实例化、测试

本次不再分章,一章写完。

环境整理

这一步并非必须,但鉴于docker容器的实际情况,理论上linux内核需要在3.10及以上。有朋友在3.10上跑通过,具体是什么内核版本没详细去确认,为了顺利起见,请首先升级linux内核到4.x,按照CentOS 7. × 系统及内核升级指南最终通过如下命令来查询版本信息:

  1. uname -a

结果应如下图所示:

除了上述操作外,相关依赖包若无强制性要求,可全部升级到最新版,执行如下命令:

  1. yum upgrade

环境部署

Hyperledger Fabric 1.0 从零开始(二)——环境构建(公网)Hyperledger Fabric 1.0 从零开始(三)——环境构建(内网/准离线)两篇文章中,个人感觉已经写的很详尽了,这里就不再赘述,最后给一个我新搭建的环境截图,在写这篇文章的时候,docker和go都有了版本升级,所以我都应用的最新版本,实际版本图如下:

源码安装

截止今日Fabric已经发布了1.1release版,由于时间问题,原本打算整理的版本升级list会延后发布。这里为了顺应需求,也就拿1.1的版本来做部署,具体下载地址hyperledger/fabric v1.1.0

请自行通过上述地址download最新版本到本地,或按照Hyperledger Fabric 1.0 从零开始(四)——Fabric源码及镜像文件处理中的方案进行安装也一样。

源码下载到本地后,上传至/home或/data或其它数据存储(看着顺眼)的目录中,稍后补图看结果。

这里说明下,fabric的安装目录并非一定要在哪哪哪,但在yaml中的工作路径和映射路径一定不能写错,否则会导致fabric中shim的api各种调用失败(原因如下图),所以还是按照官方的习惯部署会妥当点。

根据上述,我选择/home作为根目录,所以我的fabric会安装在/home/docker/github.com/hyperledger/fabric这个路径下,这个路径中的docker目录可以无视,看上图并记住“github.com/hyperledger/fabric”这个才是关键,对于新手来说不要动了,老鸟随意。

最终我的目录结构图如下:

你们会发现这里多了一个aberic的目录,这是我自己新建的项目目录,有javaweb开发经验的朋友应该能明白如何在tomcat的webapp中部署自己的项目,其实也类似,方便我自己管理和维护。

生成证书文件

这一步之前的文章也发过,Hyperledger Fabric 1.0 从零开始(五)——运行测试e2e,但总还是有码友看的不仔细或把这一整章给略过了,群里不时还会有码友问这些操作。

为了确保完整性,这里就再次重复一遍操作,在上述链接章节中提到了三种获取生成证书文件必备的二进制文件方案,我们使用官网提供的离线下载网址,找到我们本章计划操作的1.1的版本信息,可以得到最终的离线下载文件地址,下载该文件到本地。

根据官网的介绍,解压后会得到一个bin文件夹,将其解压至/home/docker/github.com/hyperledger/fabric/aberic目录下。

接下来,我们继续参考Hyperledger Fabric 1.0 从零开始(八)——Fabric多节点集群生产部署中写到的方案来生成必须的证书文件。

这里说下,在本章操作中使用的configtx.yaml是用的1.0版本的,虽然我们是在1.1的环境中进行部署,相对而言,个人感觉1.1的e2e demo把入门门槛进一步拉高了,导致很多人运行起来很费劲,始终无法跑通。与之配套的crypto-config.yaml也采用1.0版本提供的demo。相关文件自行点入下载或copy。

运行二进制文件需要在命令行中指定路径,故此我的路径安排如下图所示:

接下来我们就可以开始生成所需证书文件了,我们执行相关命令需要指定执行文件的路径,故此,为了方便,直接进入aberic项目目录下进行操作,随后执行如下命令生成我们项目所需文件:

  1. ./bin/cryptogen generate --config=./crypto-config.yaml

效果示图如下:

可能各位在执行过程中会报一些没有权限的异常,这些我在Hyperledger Fabric 1.0 从零开始(八)——Fabric多节点集群生产部署已经提到过了,就不赘述了。

上述命令生成的证书文件在/home/docker/github.com/hyperledger/fabric/aberic/crypto-config目录下,也就是说会自动创建一个crypto-config文件夹,示图如下:

接下来,要根据configtx.yaml来生成创世区块,具体命令及综合截图效果如下:

  1. ./bin/configtxgen -profile TwoOrgsOrdererGenesis -outputBlock ./channel-artifacts/genesis.block

如上图所示,出现了一个小问题,提示没有该文件或文件夹,channel-artifacts是一个文件夹,故此,我们在/home/docker/github.com/hyperledger/fabric/aberic目录下手动创建一个channel-artifacts文件夹,随后再次运行上述命令,,具体命令及综合截图效果如下:

最终会在/home/docker/github.com/hyperledger/fabric/aberic/channel-artifacts目录下创建出我们指定名称的创世区块,ftp结果视图如下:

创世区块是为了orderer启动时用到的,peer在启动后需要创建的channel配置文件在这里也一并生成,执行具体命令和综合结果示图如下:

  1. ./bin/configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/mychannel.tx -channelID mychannel

该命令是生成了一个channelID为mychannel的tx文件(文件名称看各位心情来取),通过该文件,peer可以执行channel的创建工作,后面会提到。

orderer节点处理

单机多节点部署,至少本章采用的共识模式的solo,而非kafka,如果开始考虑kafka做集群的话,相信本章的内容已经不再适合你了,本章偏基础。

首先需要编写一份docker-orderer.yaml文件,源码如下:

  1. version: '2'
  2.  
  3. services:
  4.  
  5. orderer.example.com:
  6. container_name: orderer.example.com
  7. image: hyperledger/fabric-orderer
  8. environment:
  9. - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=aberic_default
  10. # - ORDERER_GENERAL_LOGLEVEL=error
  11. - ORDERER_GENERAL_LOGLEVEL=debug
  12. - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
  13. - ORDERER_GENERAL_LISTENPORT=7050
  14. #- ORDERER_GENERAL_GENESISPROFILE=AntiMothOrdererGenesis
  15. - ORDERER_GENERAL_GENESISMETHOD=file
  16. - ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block
  17. - ORDERER_GENERAL_LOCALMSPID=OrdererMSP
  18. - ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp
  19. #- ORDERER_GENERAL_LEDGERTYPE=ram
  20. #- ORDERER_GENERAL_LEDGERTYPE=file
  21. # enabled TLS
  22. - ORDERER_GENERAL_TLS_ENABLED=false
  23. - ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key
  24. - ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt
  25. - ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]
  26. working_dir: /opt/gopath/src/github.com/hyperledger/fabric
  27. command: orderer
  28. volumes:
  29. - ./channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
  30. - ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp:/var/hyperledger/orderer/msp
  31. - ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/:/var/hyperledger/orderer/tls
  32. networks:
  33. default:
  34. aliases:
  35. - aberic
  36. ports:
  37. - 7050:7050

peer节点处理

有了orderer启动文件,我们还需要docker-peer.yaml启动文件,orderer和peer的启动yaml文件名称随意看心情,源码如下:

  1. version: '2'
  2.  
  3. services:
  4.  
  5. couchdb:
  6. container_name: couchdb
  7. image: hyperledger/fabric-couchdb
  8. # Comment/Uncomment the port mapping if you want to hide/expose the CouchDB service,
  9. # for example map it to utilize Fauxton User Interface in dev environments.
  10. ports:
  11. - "5984:5984"
  12.  
  13. ca:
  14. container_name: ca
  15. image: hyperledger/fabric-ca
  16. environment:
  17. - FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server
  18. - FABRIC_CA_SERVER_CA_NAME=ca
  19. - FABRIC_CA_SERVER_TLS_ENABLED=false
  20. - FABRIC_CA_SERVER_TLS_CERTFILE=/etc/hyperledger/fabric-ca-server-config/ca.org1.example.com-cert.pem
  21. - FABRIC_CA_SERVER_TLS_KEYFILE=/etc/hyperledger/fabric-ca-server-config/95e05e630b6fd2f16b6367823c3a1295cc86e96431dd87b1376bea1d6120eb90_sk
  22. ports:
  23. - "7054:7054"
  24. command: sh -c 'fabric-ca-server start --ca.certfile /etc/hyperledger/fabric-ca-server-config/ca.org1.example.com-cert.pem --ca.keyfile /etc/hyperledger/fabric-ca-server-config/95e05e630b6fd2f16b6367823c3a1295cc86e96431dd87b1376bea1d6120eb90_sk -b admin:adminpw -d'
  25. volumes:
  26. - ./crypto-config/peerOrganizations/org1.example.com/ca/:/etc/hyperledger/fabric-ca-server-config
  27.  
  28. peer0.org1.example.com:
  29. container_name: peer0.org1.example.com
  30. image: hyperledger/fabric-peer
  31. environment:
  32. - CORE_LEDGER_STATE_STATEDATABASE=CouchDB
  33. - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb:5984
  34.  
  35. - CORE_PEER_ID=peer0.org1.example.com
  36. - CORE_PEER_NETWORKID=aberic
  37. - CORE_PEER_ADDRESS=peer0.org1.example.com:7051
  38. - CORE_PEER_CHAINCODELISTENADDRESS=peer0.org1.example.com:7052
  39. - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.example.com:7051
  40. - CORE_PEER_LOCALMSPID=Org1MSP
  41.  
  42. - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
  43. # the following setting starts chaincode containers on the same
  44. # bridge network as the peers
  45. # https://docs.docker.com/compose/networking/
  46. - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=aberic
  47. # - CORE_LOGGING_LEVEL=ERROR
  48. - CORE_LOGGING_LEVEL=DEBUG
  49. - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=aberic_default
  50. - CORE_PEER_GOSSIP_SKIPHANDSHAKE=true
  51. - CORE_PEER_GOSSIP_USELEADERELECTION=true
  52. - CORE_PEER_GOSSIP_ORGLEADER=false
  53. - CORE_PEER_PROFILE_ENABLED=false
  54. - CORE_PEER_TLS_ENABLED=false
  55. - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt
  56. - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key
  57. - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt
  58. volumes:
  59. - /var/run/:/host/var/run/
  60. - ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp:/etc/hyperledger/fabric/msp
  61. - ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls:/etc/hyperledger/fabric/tls
  62. working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
  63. command: peer node start
  64. ports:
  65. - 7051:7051
  66. - 7052:7052
  67. - 7053:7053
  68. depends_on:
  69. - couchdb
  70. networks:
  71. default:
  72. aliases:
  73. - aberic
  74.  
  75. cli:
  76. container_name: cli
  77. image: hyperledger/fabric-tools
  78. tty: true
  79. environment:
  80. - GOPATH=/opt/gopath
  81. - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
  82. # - CORE_LOGGING_LEVEL=ERROR
  83. - CORE_LOGGING_LEVEL=DEBUG
  84. - CORE_PEER_ID=cli
  85. - CORE_PEER_ADDRESS=peer0.org1.example.com:7051
  86. - CORE_PEER_LOCALMSPID=Org1MSP
  87. - CORE_PEER_TLS_ENABLED=false
  88. - CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt
  89. - CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key
  90. - CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
  91. - CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
  92. working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
  93. volumes:
  94. - /var/run/:/host/var/run/
  95. - ./chaincode/go/:/opt/gopath/src/github.com/hyperledger/fabric/aberic/chaincode/go
  96. - ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
  97. - ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
  98. depends_on:
  99. - peer0.org1.example.com

peer的这份启动文件是目前所写的最全文件,里面有cli客户端、couchdb插件以及ca插件。

有几个地方需要注意修改下,首先是ca部分有两处,一处是FABRIC_CA_SERVER_TLS_KEYFILE,另一处是command中最后一部分,这两处的_sk文件名称需要替换成之前生成的证书文件名称,其实这里的主要目的是加载ca并生成ca用户。

这个peer启动文件启动的是peer0.org1.example.com节点,所以对应的ca证书文件在peer0.org1.example.com下可以找到,具体路径是/home/docker/github.com/hyperledger/fabric/aberic/crypto-config/peerOrganizations/org1.example.com/ca

目标视图如下:

最后将docker-peer.yaml中两处的d8785a9dbc94f677d3e1e6aeb3a6222ee6579fe751204ac1b70094e1d3f0fe06_sk替换成95e05e630b6fd2f16b6367823c3a1295cc86e96431dd87b1376bea1d6120eb90_sk即可。

切记这里的替换是替换各位自己生成的,我在这只是一个demo说明,以免到时无法跑通!!!

在cli客户端配置中我们指定了智能合约的部署路径,故此,我们在aberic目录下创建与之对应的chaincode文件夹,并在该文件夹下创建go文件夹,表示合约目录下以go语言为基础的合约目录。

最终效果截图如下:

如上图,我把官方demo中的chaincode_example02示例也一并上传到go目录下,稍后会以该合约为基础进行测试。

接下来将编写好的docker-orderer.yaml和docker-peer.yaml文件上传至aberic目录下,最终结果示图如下:

运行如下命令启动orderer和peer,按照顺序应该先启动排序服务,命令及综合视图如下:

  1. docker-compose -f docker-orderer.yaml up -d
  1. docker-compose -f docker-peer.yaml up -d

上图有点问题,可能是ssh的问题,导致peer启动的命令被后续命令覆盖。

当然,运行到此步可能有码友提示需要启动镜像,这个我就不赘述了,直接参考Hyperledger Fabric 1.0 从零开始(四)——Fabric源码及镜像文件处理,所需镜像截图如下:

在启动完成后,我们执行如下命令查看容器是否都已启动,具体结果视图如下:

可以看到所有的容器都已经成功启动,接下来就是channel和chaincode的操作了。

channel创建加盟

对peer的操作基本都需要依赖客户端完成,这里我们没有用sdk,但安装了tools镜像,即cli客户端,可以通过如下命令进入客户端进行channel的相关操作:

  1. docker exec -it cli bash

随后执行如下命令创建一个channel:

  1. peer channel create -o orderer.example.com: -c mychannel -t -f ./channel-artifacts/mychannel.tx

请注意,这个channel的创建并非随意,而是之前创建过一个mychannel.tx文件,在创建该文件的时候就已经指定了channelID是mychannel,这里不能随意看心情了。

随后执行ls即可查看已经创建的mychannel.block文件。

最终执行效果视图如下:

创建完channel后,我们需要通过mychannel.block文件来加入该channel,以便后续可以安装实例化并测试智能合约。

具体命令和视图结果如下:

  1. peer channel join -b mychannel.block

至此,我们已经完成了channel的创建并成功加入了该channel。

chaincode安装部署实例化、测试

在之前我们上传了官方的chaincode demo到go目录下,合约目录为/home/docker/github.com/hyperledger/fabric/aberic/chaincode/go/chaincode_example02,这个目录也是我们即将安装的智能合约路径。

首先安装智能合约,具体命令和执行结果如下所示:

  1. peer chaincode install -n mychannel -p github.com/hyperledger/fabric/aberic/chaincode/go/chaincode_example02 -v 1.0

安装完成后需要进行实例化chaincode,执行如下命令并有如下视图:

  1. peer chaincode instantiate -o orderer.example.com: -C mychannel -n mychannel -c '{"Args":["init","A","10","B","10"]}' -P "OR ('Org1MSP.member')" -v 1.0

上图有些问题,但最终执行是成功的。

我们看合约提供的方法中有个query方法,需要传入一个参数,我们执行一次查询看看实例化时候的结果是否传入,如下命令和视图:

  1. peer chaincode query -C mychannel -n mychannel -c '{"Args":["query","A"]}'

我们查到A有10快钱,符合初始化init时候的传参,继续执行如下命令查询B的,视图也如下:

  1. peer chaincode query -C mychannel -n mychannel -c '{"Args":["query","B"]}'

可以看到B也有10快钱。

我们根据合约内容,让A给B转5快钱,执行如下命令并附视图(包括最终再次查询A和B资金的结果):

  1. peer chaincode invoke -C mychannel -n mychannel -c '{"Args":["invoke", "A", "B", "5"]}'

我们可以看到合约已经运行无误,A成功给B转让了5快钱。

至此,先暂时告一段落,多节点部署也是在这个基础上进行的,由于章节太长,下次开接续部分的章节来完善这一块内容,且时间确实比较忙,如果能把这个跑通,后面再部署新节点就肯定能跑通了,最终开一个新节点的视图如下:

HyperLedger Fabric 1.1 手动部署单机单节点的更多相关文章

  1. 手动部署一个单节点kubernetes

    目录 简要说明 安装环境说明 部署 生成相关证书 证书类型说明 安装cfssl证书生成工具 生成CA证书 生成Kubernetes master节点使用的证书 生成kubectl证书 生成kube-p ...

  2. HyperLedger Fabric 1.4 单机单节点部署(10.2)

    单机单节点指在一台电脑上部署一个排序(Orderer)服务.一个组织(Org1),一个节点(Peer,属于Org1),然后运行官方案例中的example02智能合约例子,实现转财交易和查询功能.单机单 ...

  3. ETCD:单机单节点

    原文地址:Setting up local clusters 设置单节点集群 对于测试环境与开发环境,最快速与简单的方式是配置一个本地集群.对于生产环境,参考集群部分. 本地单节点集群 启动一个集群 ...

  4. Dubbo入门到精通学习笔记(九):简易版支付系统介绍、部署(单节点)

    文章目录 部署(单节点) 一.前期准备 二.对部署环境进行规划 创建数据库 调整公共配置文件 应用部署前期准备 部署服务 部署 Web 应用 部署定时任务 一. 工程结构 第三方支付系统架构 pay- ...

  5. 记录一个奇葩的问题:k8s集群中master节点上部署一个单节点的nacos,导致master节点状态不在线

    情况详细描述; k8s集群,一台master,两台worker 在master节点上部署一个单节点的nacos,导致master节点状态不在线(不论是否修改nacos的默认端口号都会导致master节 ...

  6. (三)Hyperledger Fabric 1.1安装部署-chaincode测试

    环境搭建完毕,需要的工具和镜像安装完毕,就可以进行chaincode测试了,接下来参考官方教程运行first-network. 进入first-netwok: cd first-network fir ...

  7. (一)Hyperledger Fabric 1.1安装部署-基础环境搭建

    在学习和开发hyperledger fabric的时候遇到了一些坑,现将自己的一些总结和心得整理如下,以期对大家有所帮助.本次使用的宿主机环境:ubuntu,版本:Ubuntu 16.04.3 LTS ...

  8. (二)Hyperledger Fabric 1.1安装部署-Fabric Samples

    Hyperledger Fabric Samples是官方推荐的First Network,对于熟悉fabric和测试基础环境很有好处. Fabric Samples源码下载:使用git下载源码,进入 ...

  9. ubuntu18.04使用kubeadm部署k8s单节点

    实验目的: 体验kubeadm部署k8s服务,全流程体验! 实验环境: ubuntu18.04 联网在线部署 kubeadm 01.系统检查 节点主机名唯一,建议写入/etc/hosts 禁止swap ...

随机推荐

  1. hdu 2048 递推&&错排

    直接贴出递推公式: cnt[n]=(i-1)*(cnt[n-1]+cnt[n-2]); 数组保存的是失败的种数 AC代码: #include<cstdio> const int maxn= ...

  2. nyoj 取石子(七) 环形博弈

    手推前几个可以知道规律:n>2时是P态,n<=2时是N态. 注意:石子拿去后,剩下的石子是分散的. AC代码 #include <cstdio> #include <cm ...

  3. CEPH s3 java sdk PUT对象并在同一个PUT请求中同时设置ACL为 Public

    java: http://docs.aws.amazon.com/zh_cn/AmazonS3/latest/dev/acl-using-java-sdk.html tring bucketName ...

  4. 放大倍数超5万倍的Memcached DDoS反射攻击,怎么破?

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 作者:腾讯游戏云 背景:Memcached攻击创造DDoS攻击流量纪录 近日,利用Memcached服务器实施反射DDoS攻击的事件呈大幅上 ...

  5. IIS部署web,字体404的问题

    今天在部署测试环境的时候,遇到字体无法访问的情况,如下图 其实,字体是存在的.路径也没有错.因为点超链接是可以看到的. 所以,怀疑是服务器不识别该字体.经过网上查找.找到了配置IIS的方法.让服务器可 ...

  6. 最新的Android版本和API Level的对应关系表

    在项目开发过程中,经常会用到API Level和Android平台版本的对照,来进行一些方法的调用,现在就把对照表贴出来,供开发人员参考,并且方便自己查阅. Platform Version API ...

  7. dojo表格内容居左、居中和居右

    1.常规表格内容居左.居中和居右 style="text-align:left;" style="text-align:center;" style=" ...

  8. VxWorks镜像简介

    VxWorks镜像可分为三类:   可加载型VxWorks镜像:存储在开发机上,运行在板上RAM中   基于ROM的VxWorks镜像:存储在板上ROM,运行在板上RAM中   ROM驻留的VxWor ...

  9. Windows 7 Visual Studio 2008配置OpenGL开发环境

    Windows 7 Visual Studio 2008配置OpenGL开发环境 glut下载地址: http://www.opengl.org/resources/libraries/glut/gl ...

  10. 把连续动态bmp转换为avi

    把动态bmp24转换为avi BYTE tmp_buf[1024*768*4]; //生成avi void BMPtoAVI(CString szAVIName, CString strBmpDir) ...