// Unicode
#include <Windows.h>
#include <CommCtrl.h>
#include <sqlext.h>
#include <vector>
#include <string>
#include "resource.h"
#define DRIVER TEXT("Microsoft Text Driver (*.txt; *.csv)")
#define DATABASE TEXT("C:\\tmp")
#define TABLE TEXT("09TOCHIG.CSV")
#define TABLE2 TEXT("09TOCHIG_.CSV")
// 型定義
struct ColInfo { // 列情報
std::wstring strName; // 列名
SQLSMALLINT datatype; // データ型
};
typedef std::vector<ColInfo> VecCI;
// 関数プロトタイプ宣言
INT_PTR CALLBACK MainDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
void OnNmDblClk(HWND hDlg, LPARAM lParam);
void OnInitDialog(HWND hDlg);
void LoadTable(HWND hDlg);
void SaveTable(HWND hDlg);
BOOL CreateTable(void);
BOOL InsertRecord(void);
INT_PTR CALLBACK SubDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
void OnSubInitDialog(HWND hDlg);
void OnOK(HWND hDlg);
// 外部変数構造体
static struct {
HINSTANCE hInstance;
HWND hList; // リストビュー
SQLHENV henv; // 環境ハンドル
SQLHDBC hdbc; // 接続ハンドル
VecCI vecci; // 列情報
int iItem; // 指定された行
} g;
//==============================================================================
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
{
// ODBC環境ハンドルの確保
SQLRETURN rc; // retcode
rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &g.henv);
rc = SQLSetEnvAttr(g.henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0);
g.hInstance = hInstance;
DialogBox(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, MainDlgProc);
SQLFreeHandle(SQL_HANDLE_ENV, g.henv);
return 0;
}
//------------------------------------------------------------------------------
INT_PTR CALLBACK MainDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
INT_PTR nRet = TRUE; // メッセージを処理した
switch (uMsg) {
case WM_NOTIFY:
switch (((LPNMHDR)lParam)->idFrom) {
case IDC_LIST:
switch (((LPNMLISTVIEW)lParam)->hdr.code) {
case NM_DBLCLK:
OnNmDblClk(hDlg, lParam);
break;
}
break;
}
break;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDC_UPDATE:
int nr;
nr = MessageBox(hDlg, L"CSVファイルを更新しますか?", L"確認", MB_OKCANCEL);
if (nr == IDOK) {
SaveTable(hDlg);
MessageBox(hDlg, L"完了しました。", L"報告", MB_OK);
}
break;
case IDCANCEL:
EndDialog(hDlg, IDCANCEL);
break;
}
break;
case WM_INITDIALOG:
OnInitDialog(hDlg);
nRet = TRUE; // SetFocusでフォーカスを設定した場合はFALSE
break;
case WM_CLOSE:
EndDialog(hDlg, 0);
break;
case WM_DESTROY:
SQLDisconnect(g.hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, g.hdbc);
break;
default:
nRet = FALSE; // メッセージを処理しなかった
}
return nRet;
}
//------------------------------------------------------------------------------
void OnNmDblClk(HWND hDlg, LPARAM lParam)
{
LPNMLISTVIEW plv = (LPNMLISTVIEW)lParam;
g.iItem = plv->iItem;
DialogBox(g.hInstance, MAKEINTRESOURCE(IDD_SUB), hDlg, SubDlgProc);
}
//------------------------------------------------------------------------------
void OnInitDialog(HWND hDlg)
{
// リストビュー拡張スタイル
g.hList = GetDlgItem(hDlg, IDC_LIST);
DWORD dwExStyle = ListView_GetExtendedListViewStyle(g.hList);
dwExStyle |= LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES;
ListView_SetExtendedListViewStyle(g.hList, dwExStyle);
// テーブルの読み込み
LoadTable(hDlg);
}
//------------------------------------------------------------------------------
void LoadTable(HWND hDlg)
{
SQLHSTMT hstmt; // 命令ハンドル
SQLSMALLINT col;
SQLSMALLINT n;
SQLSMALLINT datatype;
SQLTCHAR buf[256];
SQLLEN len;
SQLRETURN rc; // retcode
// データベースへの接続
rc = SQLAllocHandle(SQL_HANDLE_DBC, g.henv, &g.hdbc);
rc = SQLDriverConnect(g.hdbc, NULL,
(SQLTCHAR *) TEXT("driver={") DRIVER TEXT("}; dbq=") DATABASE,
SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT);
if (!SQL_SUCCEEDED(rc)) {
return;
}
// 検索
rc = SQLAllocHandle(SQL_HANDLE_STMT, g.hdbc, &hstmt);
rc = SQLExecDirect(hstmt, (SQLTCHAR *) TEXT("select * from ") TABLE, SQL_NTS);
if (!SQL_SUCCEEDED(rc)) {
return;
}
// 列情報
LV_COLUMN lvCol;
lvCol.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvCol.fmt = LVCFMT_LEFT;
lvCol.cx = 100;
rc = SQLNumResultCols(hstmt, &col);
g.vecci.reserve(col);
for (n = 0; n < col; n++) {
rc = SQLDescribeCol(hstmt, n+1, buf, _countof(buf), NULL,
&datatype, NULL, NULL, NULL);
lvCol.pszText = buf;
lvCol.iSubItem = n;
ListView_InsertColumn(g.hList, n, &lvCol);
// 列情報
ColInfo ci;
ci.strName = buf;
ci.datatype = datatype;
g.vecci.push_back(ci);
// Text 12 SQL_VARCHAR
// Byte -6 SQL_TINYINT
}
// 行情報
LV_ITEM lvItem;
lvItem.mask = LVIF_TEXT;
lvItem.iItem = 0;
while (1) {
rc = SQLFetch(hstmt);
if (rc == SQL_NO_DATA) break;
if (rc == SQL_ERROR) break;
for (n = 0; n < col; n++) {
SQLGetData(hstmt, n+1, SQL_C_TCHAR, buf, _countof(buf), &len);
lvItem.pszText = buf;
lvItem.iSubItem = n;
if (n == 0) {
ListView_InsertItem(g.hList, &lvItem);
} else {
ListView_SetItem(g.hList, &lvItem);
}
}
lvItem.iItem++;
}
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}
//------------------------------------------------------------------------------
void SaveTable(HWND hDlg)
{
// テーブルの作成
if (CreateTable() == FALSE) {
MessageBox(hDlg, L"テーブルの作成に失敗しました。", NULL, MB_OK);
return;
}
// レコードの挿入
if (InsertRecord() == FALSE) {
MessageBox(hDlg, L"レコードの挿入に失敗しました。", NULL, MB_OK);
return;
}
// CSVファイルの削除とリネーム
TCHAR szOld[MAX_PATH];
TCHAR szNew[MAX_PATH];
swprintf_s(szOld, L"%s\\%s", DATABASE, TABLE);
swprintf_s(szNew, L"%s\\%s", DATABASE, TABLE2);
BOOL br;
br = DeleteFile(szOld);
br = MoveFile(szNew, szOld);
if (br == FALSE) {
MessageBox(hDlg, L"CSVファイルのリネームに失敗しました。", NULL, MB_OK);
}
}
//------------------------------------------------------------------------------
BOOL CreateTable(void)
{
TCHAR stmttext[512];
SQLHSTMT hstmt; // 命令ハンドル
SQLRETURN rc; // retcode
rc = SQLAllocHandle(SQL_HANDLE_STMT, g.hdbc, &hstmt);
// テーブルの削除
wcscpy_s(stmttext, L"drop table ");
wcscat_s(stmttext, TABLE2);
rc = SQLExecDirect(hstmt, stmttext, SQL_NTS);
// 失敗してもテーブルの作成が成功すれば問題ない
// テーブルの作成
wcscpy_s(stmttext, L"create table ");
wcscat_s(stmttext, TABLE2);
wcscat_s(stmttext, L"(");
VecCI::iterator it = g.vecci.begin();
while (TRUE) {
wcscat_s(stmttext, (*it).strName.c_str());
switch ((*it).datatype) {
case SQL_VARCHAR:
wcscat_s(stmttext, L" Text");
break;
case SQL_TINYINT:
wcscat_s(stmttext, L" Byte");
break;
}
if (++it == g.vecci.end()) {
break;
}
wcscat_s(stmttext, L",");
}
wcscat_s(stmttext, L")");
rc = SQLExecDirect(hstmt, stmttext, SQL_NTS);
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
return SQL_SUCCEEDED(rc);
}
//------------------------------------------------------------------------------
BOOL InsertRecord(void)
{
SQLHSTMT hstmt; // 命令ハンドル
SQLRETURN rc; // retcode
BOOL bRet = TRUE;
rc = SQLAllocHandle(SQL_HANDLE_STMT, g.hdbc, &hstmt);
int nColNum = g.vecci.size();
int nRowNum = ListView_GetItemCount(g.hList);
for (int nRow = 0; nRow < nRowNum; nRow++) {
TCHAR stmttext[512];
wcscpy_s(stmttext, L"insert into ");
wcscat_s(stmttext, TABLE2);
wcscat_s(stmttext, L" values (");
for (int nCol = 0; ; ) {
TCHAR szBuf[256];
ListView_GetItemText(g.hList, nRow, nCol, szBuf, _countof(szBuf));
switch (g.vecci[nCol].datatype) {
case SQL_VARCHAR:
wcscat_s(stmttext, L"'");
wcscat_s(stmttext, szBuf);
wcscat_s(stmttext, L"'");
break;
case SQL_TINYINT:
wcscat_s(stmttext, szBuf);
break;
}
if (nColNum <= ++nCol) {
break;
}
wcscat_s(stmttext, L",");
}
wcscat_s(stmttext, L")");
rc = SQLExecDirect(hstmt, stmttext, SQL_NTS);
if (!SQL_SUCCEEDED(rc)) {
bRet = FALSE;
break;
}
}
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
// トランザクション終了
rc = SQLEndTran(SQL_HANDLE_ENV, g.henv, SQL_COMMIT);
return bRet;
}
//==============================================================================
INT_PTR CALLBACK SubDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
INT_PTR nRet = TRUE; // メッセージを処理した
switch (uMsg) {
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
OnOK(hDlg);
EndDialog(hDlg, IDOK);
break;
case IDCANCEL:
EndDialog(hDlg, IDCANCEL);
break;
}
break;
case WM_INITDIALOG:
OnSubInitDialog(hDlg);
nRet = TRUE; // SetFocusでフォーカスを設定した場合はFALSE
break;
case WM_CLOSE:
EndDialog(hDlg, 0);
break;
default:
nRet = FALSE; // メッセージを処理しなかった
}
return nRet;
}
//------------------------------------------------------------------------------
void OnSubInitDialog(HWND hDlg)
{
int nFieldNum = g.vecci.size();
for (int n = 0; n < nFieldNum; n++) {
int y = 8 + 28 * n;
TCHAR szBuf[256];
ListView_GetItemText(g.hList, g.iItem, n, szBuf, _countof(szBuf));
DWORD dwStyle = (g.vecci[n].datatype == SQL_TINYINT) ? ES_NUMBER : 0;
CreateWindow(L"static", g.vecci[n].strName.c_str(), WS_CHILD | WS_VISIBLE,
8, y, 192, 24, hDlg, (HMENU)IDC_STATIC, g.hInstance, 0);
CreateWindowEx(WS_EX_CLIENTEDGE, L"edit", szBuf,
WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL | dwStyle,
208, y, 192, 24, hDlg, (HMENU)(IDC_FIELD + n), g.hInstance, 0);
}
}
//------------------------------------------------------------------------------
void OnOK(HWND hDlg)
{
int nFieldNum = g.vecci.size();
for (int n = 0; n < nFieldNum; n++) {
TCHAR szBuf[256];
GetDlgItemText(hDlg, IDC_FIELD + n, szBuf, _countof(szBuf));
ListView_SetItemText(g.hList, g.iItem, n, szBuf);
}
}
// resource script
#include <windows.h>
#include "resource.h"
//------------------------------------------------------------------------------
IDD_MAIN DIALOGEX 100, 100, 320, 200
STYLE WS_POPUPWINDOW | WS_MINIMIZEBOX
EXSTYLE WS_EX_APPWINDOW
CAPTION "ListView"
FONT 9, "MS Pゴシック"
BEGIN
CONTROL "",IDC_LIST,"SysListView32",
WS_BORDER | WS_TABSTOP | LVS_REPORT,8,8,304,160
PUSHBUTTON "更新",IDC_UPDATE,212,176,48,16
PUSHBUTTON "終了",IDCANCEL,264,176,48,16
END
//------------------------------------------------------------------------------
IDD_SUB DIALOG 100, 100, 320, 400
STYLE WS_POPUPWINDOW
CAPTION "SubDlg"
FONT 9, "MS Pゴシック"
BEGIN
DEFPUSHBUTTON "OK",IDOK,212,376,48,16
PUSHBUTTON "Cancel",IDCANCEL,264,376,48,16
END