[译]问题追踪器
By robot-v1.0
本文链接 https://www.kyfws.com/applications/issue-tracker-zh/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 18 分钟阅读 - 8942 个词 阅读量 0[译]问题追踪器
原文地址:https://www.codeproject.com/Articles/796647/Issue-Tracker
原文作者:Ștefan-Mihai MOGA
译文由本站 robot-v1.0 翻译
前言
Did you spot any bugs today? Than this tool might save some of your time
您今天发现任何错误了吗?比这个工具可以节省您一些时间
- 下载项目文件-992.7 KB(Download project files - 992.7 KB) 注意:必须在启动应用程序之前运行MySQL脚本!(Notes: the MySQL script must be run before the application is launched!)
介绍(Introduction)
最近我发现一个很棒的(Recently I found a great) 错误跟踪工具(Bug Tracking Tool) .但是,在将其用于生产模式之前,我发现它缺少一些东西,例如:(. But, before I use that one in production mode, I found that there are a few things missing from it like:)
- 能够发送通知电子邮件(如果找到解决方案)(ability to send notification e-mails (if a solution was found))
- 附加文件(任何类型)的功能,例如屏幕截图等.(ability to attach files (of any kind), such as screenshots, etc.)
- 记录错误之间的交互(依赖关系)的能力(ability to log the interaction between bugs (dependencies))
- 作为基于Windows的独立二进制应用程序开发(developed as a standalone Windows-based binary application) 一个非常好的替代方法是(A really good alternative would be the) 待办事项清单(ToDoList) 和(and) BugReporter(BugReporter) 我的一些任务项目;但是我需要一个更具扩展性的分布式解决方案…(projects for some of my tasks; but I needed a more scalable, distributed solution …)
使用软件(Using the Software)
您是否运行MySQL脚本进行数据库创建?然后是时候建立您与数据库的第一个连接了.您必须输入对数据库的服务器名称,数据库名称,用户名和密码访问权限,如下所示:(请确保您具有适当的权利来申请(Did you run the MySQL script for database creation? Then it is time to establish your first connection to the database. You have to enter the Server name, Database name, username and password access to database, as you can see below: (please make sure you have the proper rights to apply) INSERT
,(,) UPDATE
和(and) DELETE
问题跟踪工具的数据库表上的语句)(statements on the Issue Tracker’s database tables))
每次"问题跟踪工具"应用程序启动时,它都会使用来检查当前登录的用户.(Every time the Issue Tracker application starts, it checks for the current logged in user, using the) GetUserNameEx
功能(然后(function (and then with) GetUserName
函数(如果第一个失败),则将其添加到数据库(如果尚不存在).我假设使用此软件的计算机在使用Active Directory身份验证的专用网络上,大多数软件公司就是这种情况.(function if the first one fails) and adds it to the database if it is not there already. I assume that the computers using this software are on a private network using Active Directory authentication, which is the case for most software companies.)
接下来,您应该使用(Next, you should choose your settings using the)**设定…(Settings…)**问题追踪器系统菜单中的选项:(option from Issue Tracker’s system menu:)
现在,您可以使用问题跟踪器应用程序了.(And now you are ready to use the Issue Tracker application.)
- 要添加新的错误,请单击"新建",填写信息,然后单击"插入";要取消操作,请单击"取消"按钮.(to add a new bug click New, fill in the information, then click Insert; to abort the operation hit the Cancel button.)
- 要修改错误的数据,请从顶部列表中选择它,单击"更改",更新信息,然后单击"更新".要取消操作,请单击"取消"按钮.(to modify the data of a bug select it from the top list, click Change, update the information, than click Update; to abort the operation hit the Cancel button.)
- 要将错误信息保存到HTML文档中,请从顶部列表中选择它,单击"另存为…",然后选择一个文件名,然后单击"确定".(to save the bug’s information into a HTML document, select it from the top list, click Save as …, then choose a file name, and hit OK.)
- 要打印错误的信息,请从顶部列表中选择它,单击"打印…",然后选择您的打印机,然后单击"确定".(to print the bug’s information, select it from the top list, click Print …, than select your printer, and hit OK.)
- 要按特定字段搜索数据库,请从顶部列表中取消选择问题,填写搜索条件,然后点击搜索.(to search the database by specific fields, unselect the issues from the top list, fill in the search criteria, and than hit Search.)
实施(The implementation)
Issue Tracker应用程序在设计时考虑了三层抽象(以便可以轻松扩展此软件):(The Issue Tracker application has been designed with three layers of abstraction in mind (so that this software can be easily extended):)
-
MFC/应用程序层-提供典型Windows应用程序的基本功能;这层实现到(the MFC/application layer - provides the basic functions of a typical Windows application; this layer it is implemented into the)
CIssueTrackerApp
,(,)CIssueTrackerDlg
,(,)CUserConfigurationDlg
,(,)CFileAttachementsDlg
,(,)CConnectionSettingsDlg
和(and)CSmtpConfigurationDlg
类;(classes;) -
对象/数据操作层-提供特定功能以插入/删除/搜索用户,问题及其关联的文件和注释;它被实现到(the object/data manipulation layer - provides specific functions to insert / delete / search for users, issues, and for its associated files and notes; it is implemented into the)
CIssueUserItem
,(,)CIssueUserList
,(,)CIssueFileItem
,(,)CIssueFileList
,(,)CIssueNoteItem
,(,)CIssueNoteList
,(,)CIssueDataItem
和(and)CIssueDataListcode
类;(classes;) -
ODBC数据库访问层-提供包装功能,以通过ODBC API访问数据库;它被实现到(the ODBC database access layer - provides wrapper functions for database access through ODBC API; it is implemented into the)
CDatabaseConnector
和(and)CDatabaseRecordset
类.(classes.) 关于MFC/应用程序层中的类,实际上没有什么要说的:(There is not really much to be said about the classes from the MFC/application layer:) -
的(the)
CIssueTrackerDlg
类是应用程序的主要接口;(class is the main interface of the application;) -
的(the)
CUserConfigurationDlg
类实现用户配置对话框;(class implements the user configuration dialog;) -
的(the)
CFileAttachementsDlg
类允许用户对错误附加的文件执行基本操作;(class allows the user to perform basic operations on the files attached on a bug;) -
的(the)
CConnectionSettingsDlg
类允许用户建立与数据库的连接;(class allows the user to set-up the connection to database;) -
的(the)
CSmtpConfigurationDlg
类允许用户建立与SMTP服务器的连接.(class allows the user to set-up the connection to SMTP server.) 的(The)CIssueUserItem
类是围绕(class is a wrapper around the)IssueUser
表,它具有以下成员函数:(table and it has the following member functions:) -
UINT GetID()
-返回用户的ID;(- returns the ID of an user;) -
SetID( UINT uintID )
-设置用户的ID;(- sets the ID of an user;) -
CString GetFullName()
-返回用户的全名;(- returns the full name of an user;) -
void SetFullName( CString lpszFullName )
-设置用户的全名;(- sets the full name of an user;) -
CString GetEmailAddr()
-返回用户的电子邮件地址;(- returns the e-mail address of an user;) -
void SetEmailAddr( CString lpszEmailAddr )
-设置用户的电子邮件地址;(- sets the e-mail address of an user;) -
GetNotification()
-退货(- returns)TRUE
用户是否希望通过电子邮件进行通知,以及(if a user wants notification through e-mail, and)FALSE
除此以外;(otherwise;) -
void SetNotification( UINT uintNotification )
-为用户启用/禁用电子邮件通知;(- enables/disables e-mail notification for an user;) -
void CopyDataFrom( CIssueUserItem * pIssueUser )
-复制相同类型的另一个对象的数据.(- makes a copy of the data of another object of the same type.) 的(The)CIssueUserList
类是一个数组(class is an array of)CIssueUserItem
对象,它具有以下成员函数:(objects and it has the following member functions:) -
int GetSize()
-返回当前可用的用户数;(- returns the count of the users currently available;) -
CIssueUserItem * GetItemAt( int nItemIndex )
-从中返回用户(- returns the user from)nItemIndex
数组中的位置;(position in array;) -
void SetItemAt( int nItemIndex, CIssueUserItem * pIssueUser )
-将新用户设置为(- sets a new user to)nItemIndex
数组中的位置;(position in array;) -
void RemoveAllItems()
-删除存储在数组中的所有用户;(- deletes all users stored in array;) -
BOOL LoadAllItems()
-从数据库加载所有用户;(- load all users from database;) -
BOOL InsertItem( CIssueUserItem * pIssueUser )
-将一个新用户插入数组以及数据库中;(- inserts one new user into array, and also into the database;) -
BOOL UpdateItem( CIssueUserItem * pIssueUser )
-从阵列更新用户的数据,并更新到数据库;(- updates the data of an user from array, and also into the database;) -
BOOL DeleteItem( CIssueUserItem * pIssueUser )
-从数组以及数据库中删除用户;(- deletes an user from array, and also from the database;) -
CIssueUserItem * SearchItem( UINT uintID, BOOL bUseDatabase )
-根据其ID在阵列/数据库中搜索用户;(- search for an user into array/database, based on his/her ID;) -
CIssueUserItem * SearchItem( CString lpszFullName, BOOL bUseDatabase )
-根据用户的全名在阵列/数据库中搜索用户;(- search for an user into array/database, based on his/her full name;) -
CIssueUserItem * SearchAddr( CString lpszEmailAddr, BOOL bUseDatabase )
-根据用户的电子邮件地址在阵列/数据库中搜索该用户;(- search for an user into array/database, based on his/her e-mail address;) -
UINT GetUserLoggedID()
-返回当前登录用户的ID;(- returns the ID of the currently logged in user;) -
void SetUserLoggedID( UINT uintID )
-设置当前登录用户的ID;(- sets the ID of the currently logged in user;) -
CString GetUserLoggedName()
-返回当前登录用户的全名;(- returns the full name of the currently logged in user;) -
void SetUserLoggedName( CString lpszName )
-设置当前登录用户的全名;(- sets the full name of the currently logged in user;) -
CString GetUserLoggedEmailAddr()
-返回当前登录用户的电子邮件地址;(- returns the e-mail address of the currently logged in user;) -
void SetUserLoggedEmailAddr( CString lpszEmailAddr )
-设置当前登录用户的电子邮件地址;(- sets the e-mail address of the currently logged in user;) -
BOOL ValidateCurrentUserLogged()
-如果当前登录的用户不在数据库中,则将其添加到数据库中.(- adds the currently logged in user to the database if its not there.) 的(The)CIssueFileItem
类是围绕(class is a wrapper around the)IssueFile
表,它具有以下成员函数:(table and it has the following member functions:) -
UINT GetID()
-返回文件的ID;(- returns the ID of the file;) -
void SetID( UINT uintID )
-设置文件的ID;(- sets the ID of the file;) -
UINT GetIssueID()
-返回与文件关联的问题的ID;(- returns the ID of an issue associated with the file;) -
void SetIssueID( UINT uintIssueID )
-设置与文件关联的问题的ID;(- sets the ID of an issue associated with the file;) -
CIssueUserItem * GetAuthor()
-返回文件的作者;(- returns the author of the file;) -
void SetAuthor( CIssueUserItem * itemAuthor )
-设置文件的作者;(- sets the author of the file;) -
CString GetFileName()
-返回文件名;(- returns the name of the file;) -
void SetFileName( CString lpszFileName )
-设置文件名;(- sets the name of the file;) -
UINT GetFileSize()
-返回文件的大小(以字节为单位);(- returns the size in bytes of the file;) -
void SetFileSize( UINT uintFileSize )
-设置文件的大小(以字节为单位);(- sets the size in bytes of the file;) -
CTime GetModified()
-返回文件的日期/时间;(- returns the date/time of the file;) -
void SetModified( CTime timeModified )
-设置文件的日期/时间;(- sets the date/time of the file;) -
CLongBinary * GetContent()
-获取文件的内容;(- gets the content of the file;) -
void SetContent( CLongBinary * byteContent )
-设置文件的内容;(- set the content of the file;) -
void CopyDataFrom( CIssueFileItem* pIssueFile )
-复制相同类型的另一个对象的数据.(- makes a copy of the data of another object of the same type.) 的(The)CIssueFileList
类是一个数组(class is an array of)CIssueFileItem
对象,它具有以下成员函数:(objects and it has the following member functions:) -
int GetSize()
-返回当前可用于发布的文件的数量;(- returns the count of the files currently available for an issue;) -
CIssueFileItem * GetItemAt( int nItemIndex )
-从中返回文件(- returns the file from)nItemIndex
数组中的位置;(position in array;) -
void SetItemAt( int nItemIndex, CIssueFileItem * pIssueFile )
-将新文件设置为(- sets a new file to)nItemIndex
数组中的位置;(position in array;) -
void RemoveAllItems()
-删除存储在数组中的所有文件;(- deletes all files stored in array;) -
BOOL LoadAllItems( UINT uintIssueID, CIssueUserList * listIssueUser )
-从与问题相关的数据库中加载所有文件;(- load all files from database associated to an issue;) -
BOOL InsertItem( CIssueFileItem * pIssueFile )
-将一个新文件插入数组以及数据库中;(- inserts one new file into array, and also into the database;) -
BOOL UpdateItem( CIssueFileItem * pIssueFile )
-从数组更新文件的数据,并更新到数据库;(- updates the data of a file from array, and also into the database;) -
BOOL DeleteItem( CIssueFileItem * pIssueFile )
-从数组以及数据库中删除文件;(- deletes a file from array, and also from the database;) -
CIssueFileItem * SearchItem( UINT uintID, CIssueUserList * listIssueUser, BOOL bUseDatabase )
-根据文件ID在阵列/数据库中搜索文件.(- search for a file into array/database, based on its ID.) 的(The)CIssueNoteItem
类是围绕(class is a wrapper around the)IssueNote
表,它具有以下成员函数:(table and it has the following member functions:) -
UINT GetID()
-返回笔记的ID;(- returns the ID of the note;) -
void SetID( UINT uintID )
-设置注释的ID;(- sets the ID of the note;) -
UINT GetIssueID()
-返回与注释相关的问题的ID;(- returns the ID of an issue associated with the note;) -
void SetIssueID( UINT uintIssueID )
-设置与注释相关的问题的ID;(- sets the ID of an issue associated with the note;) -
CIssueUserItem * GetAuthor()
-返回注释的作者;(- returns the author of the note;) -
void SetAuthor( CIssueUserItem * itemAuthor )
-设置注释的作者;(- sets the author of the note;) -
UINT GetFileSize()
-返回注释的大小(以字节为单位);(- returns the size in bytes of the note;) -
void SetFileSize( UINT uintFileSize )
-设置注释的字节大小;(- sets the size in bytes of the note;) -
CTime GetModified()
-返回注释的日期/时间;(- returns the date/time of the note;) -
void SetModified( CTime timeModified )
-设置注释的日期/时间;(- sets the date/time of the note;) -
CLongBinary * GetContent()
-获取注释的内容;(- gets the content of the note;) -
void SetContent( CLongBinary * byteContent )
-设置注释的内容;(- set the content of the note;) -
void CopyDataFrom( CIssueNoteItem* pIssueNote )
-复制相同类型的另一个对象的数据.(- makes a copy of the data of another object of the same type.) 的(The)CIssueNoteList
类是一个数组(class is an array of)CIssueNoteItem
对象,它具有以下成员函数:(objects and it has the following member functions:) -
int GetSize()
-返回当前可用于发行的注释的数量;(- returns the count of the notes currently available for an issue;) -
CIssueNoteItem * GetItemAt( int nItemIndex )
-从返回票据(- returns the note from)nItemIndex
数组中的位置;(position in array;) -
void SetItemAt( int nItemIndex, CIssueNoteItem * pIssueNote )
-为(- sets a new note to)nItemIndex
数组中的位置;(position in array;) -
void RemoveAllItems()
-删除存储在数组中的所有注释;(- deletes all notes stored in array;) -
BOOL LoadAllItems( UINT uintIssueID, CIssueUserList * listIssueUser )
-从数据库中加载与问题相关的所有注释;(- load all notes from database associated to an issue;) -
BOOL InsertItem( CIssueNoteItem * pIssueNote )
-在数组中以及数据库中插入一个新注释;(- inserts one new note into array, and also into the database;) -
BOOL UpdateItem( CIssueNoteItem * pIssueNote )
-从数组更新注释数据,并更新到数据库;(- updates the data of a note from array, and also into the database;) -
BOOL DeleteItem( CIssueNoteItem * pIssueNote )
-从数组以及数据库中删除注释;(- deletes a note from array, and also from the database;) -
CIssueNoteItem * SearchItem( UINT uintID, CIssueUserList * listIssueUser, BOOL bUseDatabase )
-根据其ID在数组/数据库中搜索注释.(- search for a note into array/database, based on its ID.) 的(The)CIssueDataItem
类是围绕(class is a wrapper around the)IssueData
表,它具有以下成员函数:(table and it has the following member functions:) -
UINT GetID()
-返回问题的ID;(- returns the ID of an issue;) -
void SetID( UINT uintID )
-设置问题的ID;(- sets the ID of an issue;) -
CString GetTitle()
-返回问题的标题;(- returns the title of an issue;) -
void SetTitle( CString lpszTitle )
-设置问题的标题;(- sets the title of an issue;) -
CString GetProduct()
-返回产生问题的产品;(- returns the product where the issue was generated;) -
void SetProduct( CString lpszProduct )
-设置产生问题的产品;(- sets the product where the issue was generated;) -
CString GetComponent()
-返回产生问题的组件;(- returns the component where the issue was generated;) -
void SetComponent( CString lpszComponent )
-设置产生问题的组件;(- sets the component where the issue was generated;) -
CString GetVersion()
-返回生成问题的软件版本;(- returns the version of software witch generated the issue;) -
void SetVersion( CString lpszVersion )
-设置生成问题的软件版本;(- sets the version of software witch generated the issue;) -
CString GetPlatform()
-返回产生问题的软件平台;(- returns the platform of software where the issue was generated;) -
void SetPlatform( CString lpszPlatform )
-设置产生问题的软件平台;(- sets the platform of software where the issue was generated;) -
UINT GetStatus()
-设置问题的状态;(- sets the status of the issue;) -
void SetStatus( UINT uintStatus )
-返回问题状态;(- returns the status of the issue;) -
UINT GetImportance()
-返回问题的优先级;(- returns the priority of the issue;) -
void SetImportance( UINT uintImportance )
-确定问题的优先级;(- sets the priority of the issue;) -
CString GetMilestone()
-返回问题的截止日期;(- returns the deadline of the issue;) -
void SetMilestone( CString lpszMilestone )
-确定问题的截止日期;(- sets the deadline of the issue;) -
CIssueUserItem * GetReporter()
-返回报告此问题的用户;(- returns the user who reported this issue;) -
SetReporter( CIssueUserItem * itemReporter )
-设置报告此问题的用户;(- sets the user who reported this issue;) -
CIssueUserItem * GetResolver()
-返回应为该问题找到修复程序的软件开发人员;(- returns the software developer who should find a fix for this issue;) -
void SetResolver( CIssueUserItem * itemResolver )
-设置应为该问题找到修复程序的软件开发人员;(- sets the software developer who should find a fix for this issue;) -
CIssueUserItem * GetConfirmer()
-返回质量检查联系人,该联系人将确认此问题的解决方法;(- returns the QA contact who would confirm the fix for this issue;) -
void SetConfirmer( CIssueUserItem * itemConfirmer )
-设置质量检查联系人,以确认该问题的解决方法;(- sets the QA contact who would confirm the fix for this issue;) -
CString GetDependencies()
-返回这个巫婆所依赖的问题的ID;(- returns the IDs of the issues on witch this one depends;) -
void SetDependencies( CString lpszDependencies )
-设置这个人所依赖的问题的ID;(- sets the IDs of the issues on witch this one depends;) -
CString GetBlocksIssues()
-返回此问题阻止的问题的ID;(- returns the IDs of the issues blocked by this issue;) -
void SetBlocksIssues( CString lpszBlocksIssues )
-设置被此问题阻止的问题的ID;(- sets the IDs of the issues blocked by this issue;) -
CString GetDistribution()
-返回通知电子邮件的电子邮件地址的抄送列表;(- returns the CC list of e-mail addresses of the notification e-mail;) -
void SetDistribution( CString lpszDistribution )
-设置通知电子邮件的电子邮件地址的抄送列表;(- sets the CC list of e-mail addresses of the notification e-mail;) -
CTime GetModified()
-返回上次修改此问题的日期/时间;(- returns the date/time when this issue was last modified;) -
void SetModified( CTime timeModified )
-设置上次修改此问题的日期/时间;(- sets the date/time when this issue was last modified;) -
void CopyDataFrom( CIssueDataItem* pIssueData )
-复制相同类型的另一个对象的数据.(- makes a copy of the data of another object of the same type.) 的(The)CIssueDataList
类是一个数组(class is an array of)CIssueDataItem
对象,它具有以下成员函数:(objects and it has the following member functions:) -
int GetSize()
-返回当前可用问题的数量;(- returns the count of the issues currently available;) -
CIssueDataItem * GetItemAt( int nItemIndex )
-返回问题来自(- returns the issue from)nItemIndex
数组中的位置;(position in array;) -
void SetItemAt( int nItemIndex, CIssueDataItem * pIssueData )
-将新问题(- sets a new issue to)nItemIndex
数组中的位置;(position in array;) -
void RemoveAllItems()
-删除存储在数组中的所有问题;(- deletes all issues stored in array;) -
BOOL LoadAllItems( BOOL bRefreshUsers, BOOL bLoadAllFiles, BOOL bLoadAllNotes, BOOL bFindRelations )
-从数据库加载所有问题;(- load all issues from database;) -
BOOL InsertItem( CIssueDataItem * pIssueData )
-将一个新问题插入数组以及数据库中;(- inserts one new issue into array, and also into the database;) -
BOOL UpdateItem( CIssueDataItem * pIssueData )
-将问题的数据从阵列更新到数据库中;(- updates the data of an issue from array, and also into the database;) -
BOOL DeleteItem( CIssueDataItem * pIssueData )
-从数组以及数据库中删除问题;(- deletes an issue from array, and also from the database;) -
CIssueNoteItem * SearchItem( UINT uintID, BOOL bUseDatabase )
-根据其ID将问题搜索到阵列/数据库中;(- search for an issue into array/database, based on its ID;) -
BOOL SearchEngine( CIssueDataItem * pIssueData, BOOL bRefreshUsers, BOOL bLoadAllFiles, BOOL bLoadAllNotes, BOOL bFindRelations )
-搜索与在中指定的字段匹配的所有问题(- search for all issues that matches the fields specified in)pIssueData
;(;) -
BOOL FindRelation( UINT uintID, CString &lpszBlocks )
-搜索此问题阻止的所有问题的ID.(- search for all IDs of the issues that this issue blocks.) 的(The)CDatabaseConnector
类是通过ODBC驱动程序访问数据库的基本资源,它具有以下成员函数:(class is the basic resource to access our database through ODBC driver and it has the following member functions:) -
void AllocConnectorHandle()
-为数据库连接分配新的句柄;(- allocates a new handle for a database connection;) -
void FreeConnectorHandle()
-释放之前为数据库连接分配的句柄;(- frees the handle allocated before for a database connection;) -
BOOL DriverConnect( LPCTSTR lpszInputConnection )
-创建与数据库的新ODBC连接;(- creates a new ODBC connection to the database;) -
BOOL OpenConnection()
-打开与数据库的新ODBC连接;(- opens a new ODBC connection to the database;) -
void CloseConnection()
-关闭当前与数据库的ODBC连接;(- close the current ODBC connection to the database;) -
BOOL ExecuteStatement( LPCTSTR lpszStatement )
-执行一条SQL语句(例如(- executes an SQL statement (such an)INSERT
,(,)UPDATE
,(,)DELETE
);();) -
void SetLoginTimeout( const long nLoginTimeout )
-设置建立与数据库的连接的超时;(- sets the timeout for establishing a connection to the database;) -
long GetLoginTimeout()
-返回建立与数据库的连接的超时;(- returns the timeout for establishing a connection to the database;) -
BOOL IsDatabaseOpened()
-退货(- returns)TRUE
如果与数据库建立了连接,并且(if a connection to the database was established, and)FALSE
除此以外;(otherwise;) -
long GetRowsAffected()
-返回受最近执行的SQL查询影响的行数;(- returns the number of the rows affected by the last SQL interrogation executed;) -
DATABASE_TYPE GetDatabaseType()
-返回当前连接的数据库类型(例如SQL SERVER,ORACLE,MYSQL等);(- returns the database type of the current connection (e.g. SQL SERVER, ORACLE, MYSQL etc.);) -
void SetDatabaseType( DATABASE_TYPE uintDatabaseType )
-设置新连接的数据库类型.(- sets the database type for a new connection.) 的(The)CDatabaseRecordset
类利用由提供的连接(class makes use of the connection provided by)CDatabaseConnector
它具有以下成员函数:(and it has the following member functions:) -
void AllocRecordsetHandle()
-为SQL语句分配新的句柄;(- allocates a new handle for an SQL statement;) -
void FreeRecordsetHandle()
-释放之前为SQL语句分配的句柄;(- frees the handle allocated before for an SQL statement;) -
BOOL OpenRecordset( LPCTSTR lpszStatement )
-执行SQL查询并获取行数据集;(- executes an SQL interrogation and fetch the row set of data;) -
void CloseRecordset()
-关闭由先前的SQL查询创建的数据行集;(- close the row set of data created by the previous SQL interrogation;) -
void GetFieldValue( WORD nFieldIndex, LONG nFieldType, DWORD nFieldSize, void* pDataBuffer )
-从中获取值(- fetches a value from the)nFieldIndex
列,类型(column, of type)nFieldType
,并将其存储到(, and it stores to)pDataBuffer
的大小由(of size given by)nFieldSize
;(;) -
void GetColumnAttr( WORD nColumnIndex, LPTSTR lpszColumnName, WORD nBufferLength, WORD &nColumnType, ULONG &nColumnSize, WORD &nColumnScale, BOOL &bNullable )
-从当前行数据集中获取列的属性;(- gets the attributes of a column from the current row set of data;) -
void SeekFirstRecord()
-将光标移动到当前行数据集的第一条记录;(- moves the cursor to the first record of the current row set of data;) -
void SeekLastRecord()
-将光标移动到当前行数据集的最后一条记录;(- moves the cursor to the last record of the current row set of data;) -
void SeekPrevRecord()
-将光标移动到当前行数据集的上一条记录;(- moves the cursor to the previous record of the current row set of data;) -
void SeekNextRecord()
-将光标移动到当前行数据集的下一条记录;(- moves the cursor to the next record of the current row set of data;) -
long GetNumResultRows()
-返回受最近执行的SQL查询影响的行数;(- returns the number of the rows affected by the last SQL interrogation executed;) -
long GetNumResultCols()
-返回当前行数据集中的列数;(- returns the number of columns in the current row set of data;) -
void SetQueryTimeout( const long nQueryTimeout )
-设置SQL查询的超时;(- sets the timeout for a SQL interrogation;) -
long GetQueryTimeout()
-返回为SQL查询选择的超时;(- returns the timeout selected for a SQL interrogation;) -
BOOL IsRecordsetOpened()
-退货(- returns)TRUE
如果有一组数据可用,并且(if a row set of data is available, and)FALSE
除此以外;(otherwise;) -
BOOL IsRecordsetBOF()
-退货(- returns)TRUE
如果光标到达数据行集的开头,并且(if the cursor reached the begin of row set of data, and)FALSE
除此以外;(otherwise;) -
BOOL IsRecordsetEOF()
-退货(- returns)TRUE
如果光标到达数据行集的末尾,并且(if the cursor reached the end of row set of data, and)FALSE
除此以外.(otherwise.)
兴趣点(Points of interest)
众所周知,Windows可以轻松访问其注册表数据库.因此,问题跟踪器应用程序很好地利用了它来存储数据库访问设置.但是我只是无法以纯文本形式存储访问密码.因此,我查看了Microsoft密码库,并决定为此目的实现两个辅助函数:(It is well known that Windows provides an easy access to its Registry database. So the Issue Tracker application makes a good use of it to store the database access settings. But I just could not store the access password in plain text. So I looked at the Microsoft Cryptography Library and I decided to implement two helper functions for this purpose:) GetRegistryPassword
和(and) SetRegistryPassword
.(.)
/// Returns a decrypted password read from Windows Registry, using Crypto API calls
BOOL GetRegistryPassword( LPCTSTR lpszCryptoKey, LPCTSTR lpszSection, LPCTSTR lpszEntry, LPTSTR lpszValue, LPCTSTR lpszDefault )
{
if ( !lpszSection || !lpszEntry || !lpszValue )
return FALSE;
if ( !USE_CRYPTO_METHODS )
{
return ( _tcscpy( lpszValue, AfxGetApp()->GetProfileString( lpszSection, lpszEntry, lpszDefault ) ) != NULL);
}
if ( !lpszCryptoKey )
lpszCryptoKey = AfxGetAppName();
LPBYTE lpcbPassword = (LPBYTE) lpszCryptoKey;
const DWORD dwPasswordLen = (DWORD) ( sizeof(TCHAR) * _tcslen( lpszCryptoKey ) );
BYTE lpcbDataValue[PASSWORD_MAXLENGTH];
DWORD dwHowManyBytes = 0;
LPBYTE lpcbTempBuffer = NULL;
BOOL bDecryptionDone = FALSE;
HCRYPTPROV hCryptoProvider = NULL;
HCRYPTHASH hCryptoHash = NULL;
HCRYPTKEY hCryptoKey = NULL;
if ( AfxGetApp()->GetProfileBinary( lpszSection, lpszEntry, (LPBYTE *)&lpcbTempBuffer, (UINT *)&dwHowManyBytes ) )
{
if ( dwHowManyBytes != 0)
{
ZeroMemory( lpcbDataValue, sizeof( lpcbDataValue ) );
CopyMemory( lpcbDataValue, lpcbTempBuffer, dwHowManyBytes );
if ( CryptAcquireContext( &hCryptoProvider, NULL, NULL, PROV_RSA_FULL, 0 ) )
{
if ( CryptCreateHash( hCryptoProvider, CALG_MD5, NULL, 0, &hCryptoHash ) )
{
if ( CryptHashData( hCryptoHash, lpcbPassword, dwPasswordLen, 0 ) )
{
if ( CryptDeriveKey( hCryptoProvider, CALG_RC4, hCryptoHash, CRYPT_EXPORTABLE, &hCryptoKey ) )
{
if ( CryptDecrypt( hCryptoKey, NULL, TRUE, 0, lpcbDataValue, &dwHowManyBytes ) )
{
bDecryptionDone = TRUE;
_tcscpy( lpszValue, (LPTSTR) lpcbDataValue );
}
else
{
DisplayLastError( _T("CryptDecrypt: ") );
}
VERIFY( CryptDestroyKey( hCryptoKey ) );
}
else
{
DisplayLastError( _T("CryptDeriveKey: ") );
}
}
else
{
DisplayLastError( _T("CryptHashData: ") );
}
VERIFY( CryptDestroyHash( hCryptoHash ) );
}
else
{
DisplayLastError( _T("CryptCreateHash: ") );
}
VERIFY( CryptReleaseContext( hCryptoProvider, 0 ) );
}
else
{
DisplayLastError( _T("CryptAcquireContext: ") );
}
}
}
else
{
if ( !dwHowManyBytes )
{
_tcscpy( lpszValue, lpszDefault );
bDecryptionDone = TRUE;
}
}
if ( lpcbTempBuffer != NULL )
delete lpcbTempBuffer;
return bDecryptionDone;
}
和(and)
/// Writes an encrypted password to Windows Registry, using Crypto API calls
BOOL SetRegistryPassword( LPCTSTR lpszCryptoKey, LPCTSTR lpszSection, LPCTSTR lpszEntry, LPTSTR lpszValue )
{
if ( !lpszSection || !lpszEntry || !lpszValue )
return FALSE;
if ( !USE_CRYPTO_METHODS )
{
return AfxGetApp()->WriteProfileString( lpszSection, lpszEntry, lpszValue );
}
if ( !lpszCryptoKey )
lpszCryptoKey = AfxGetAppName();
LPBYTE lpcbPassword = (LPBYTE) lpszCryptoKey;
const DWORD dwPasswordLen = (DWORD)( sizeof( TCHAR ) * _tcslen( lpszCryptoKey ) );
BYTE lpcbDataValue[PASSWORD_MAXLENGTH];
const DWORD dwDataValueLen = PASSWORD_MAXLENGTH;
DWORD dwHowManyBytes = dwDataValueLen;
BOOL bEncryptionDone = FALSE;
HCRYPTPROV hCryptoProvider = NULL;
HCRYPTHASH hCryptoHash = NULL;
HCRYPTKEY hCryptoKey = NULL;
ZeroMemory( lpcbDataValue, sizeof( lpcbDataValue ) );
CopyMemory( lpcbDataValue, lpszValue, dwDataValueLen );
if ( CryptAcquireContext( &hCryptoProvider, NULL, NULL, PROV_RSA_FULL, 0 ) )
{
if ( CryptCreateHash( hCryptoProvider, CALG_MD5, NULL, 0, &hCryptoHash ) )
{
if ( CryptHashData( hCryptoHash, lpcbPassword, dwPasswordLen, 0 ) )
{
if ( CryptDeriveKey( hCryptoProvider, CALG_RC4, hCryptoHash, CRYPT_EXPORTABLE, &hCryptoKey ) )
{
if ( CryptEncrypt( hCryptoKey, NULL, TRUE, 0, lpcbDataValue, &dwHowManyBytes, dwDataValueLen ) )
{
bEncryptionDone = AfxGetApp()->WriteProfileBinary( lpszSection, lpszEntry, lpcbDataValue, (UINT)dwHowManyBytes );
}
else
{
DisplayLastError( _T("CryptEncrypt: ") );
}
VERIFY( CryptDestroyKey( hCryptoKey ) );
}
else
{
DisplayLastError( _T("CryptDeriveKey: ") );
}
}
else
{
DisplayLastError( _T("CryptHashData: ") );
}
VERIFY( CryptDestroyHash( hCryptoHash ) );
}
else
{
DisplayLastError( _T("CryptCreateHash: ") );
}
VERIFY( CryptReleaseContext( hCryptoProvider, 0 ) );
}
else
{
DisplayLastError( _T("CryptAcquireContext: ") );
}
return bEncryptionDone;
}
其他敏感数据使用MySQL的存储(仅存储到数据库中)(Other sensitive data are stored (only into the database) using MySQL’s) AES_ENCRYPT
和(and) AES_DECRYPT
功能.您可以找到有关此主题的更多信息(functions. You can found more information on this subject) 这里(here) .(.)
而且,如果您想针对MS SQL Server或Oracle数据库运行该应用程序,则需要从(And if you would like to run this application against either MS SQL Server or Oracle databases, then you need to adapt the SQL statements from the)**IssueTrackerExt.cpp(IssueTrackerExt.cpp)**文件.(file.)
最后的话(Final words)
问题跟踪程序应用程序使用了许多已在"代码项目"上发布的组件.非常感谢:(Issue Tracker application uses many components that have been published on The Code Project. Many thanks to:)
- PJ诺特为他(PJ Naughter for his) CPJNSMTPConnection(CPJNSMTPConnection) 类(class)
- 本`汉森(Ben Hanson)(Ben Hanson for his) CFilterEdit(CFilterEdit) 类(class)
- 多米尼克`赖克(Dominik Reichl)(Dominik Reichl for his) CSecureEdit(CSecureEdit) 类(class)
- 保罗`迪拉斯(Paul DiLascia)(Paul DiLascia for his) CModuleVersion(CModuleVersion) 类(class)
- 蒂姆`麦克科(Tim McColl)(Tim McColl for his) CReadOnlyComboBox(CReadOnlyComboBox) 类(class)
- 丹
马登(Dan Madden)(*Dan Madden for his*) [CTokenEx(*CTokenEx*)](http://www.codeproject.com/Articles/264/String-Tokenizer-Class-CTokenEx) 类(*class*) 为了重新编译此Visual C ++ .NET 2005项目,您应该考虑下载(*In order to recompile this Visual C++ .NET 2005 project, you should consider downloading the*)
boost::regex` 来自的图书馆(library from) Boost的官方页面(Boost’s Official Page) ,因为我使用它来读取电子邮件地址和问题的依存关系列表.(, since I’m using it to read e-mail addresses and issue’s dependencies list.)
PJ诺特的(The PJ Naughter’s) CPJNSMTPConnection
上课还要求(class also requires the) OpenSSL专案(OpenSSL Project) .一个不错的选择是从以下位置下载OpenSSL Project的Windows二进制文件:(. A good choice would be to download the Windows binaries of the OpenSSL Project from) 闪亮的灯光制作(Shining Light Productions) 页.(page.)
虽然此工具最初仅供我个人使用,但现在是一个"社区"项目,因此,如果您发现它有用,并希望为增强功能或错误修复提供建议,请在下面发布.(Whilst this tool was originally intended for my personal use only, it is now a ‘community’ project, so if you find it useful and want to make suggestions for enhancements or bug fixes, then post below.)
历史(History)
- 1.00版(2014年7月13日)-初始版本.(version 1.00 (July 13th, 2014) - Initial release.)
许可
本文以及所有相关的源代码和文件均已获得The Code Project Open License (CPOL)的许可。
SQL HTML C++ WinXP Vista Win2K Visual-Studio MFC Win32 ODBC 新闻 翻译