 今回は,エクセルにデータを書き込みます。
前章を見て、データを書き込むプログラムを作ろうとして
DdeAddData関数を使って失敗した人はいませんか。通常
この関数はサーバー側で使います。前回同様クライアントを
作ってクライアント側から書きこみを行います。
また、前章ではブックの名前が固定でしたが今回は
ユーザーが指定できるようにしました。
今回は,エクセルにデータを書き込みます。
前章を見て、データを書き込むプログラムを作ろうとして
DdeAddData関数を使って失敗した人はいませんか。通常
この関数はサーバー側で使います。前回同様クライアントを
作ってクライアント側から書きこみを行います。
また、前章ではブックの名前が固定でしたが今回は
ユーザーが指定できるようにしました。
 メニューの「DDE」「DDE開始」を選択すると
左の図のようなダイアログボックスが出てきてブック名を
聞いてきます。「TEST.XLS」のように拡張子まで指定します。
また、この時すでにエクセルが起動していてブックが開いた状態になっていないと
いけません。
メニューの「DDE」「DDE開始」を選択すると
左の図のようなダイアログボックスが出てきてブック名を
聞いてきます。「TEST.XLS」のように拡張子まで指定します。
また、この時すでにエクセルが起動していてブックが開いた状態になっていないと
いけません。
 メニューの「DDE」「データの書き込み」を選択すると
左のようなダイアログボックスが出てきます。
これに、セルとデータを記入して「OK」ボタンを押すと
データが記入されます。シートは指定できません。
メニューの「DDE」「データの書き込み」を選択すると
左のようなダイアログボックスが出てきます。
これに、セルとデータを記入して「OK」ボタンを押すと
データが記入されます。シートは指定できません。
では、データを書き込むにはどうしたらよいのでしょうか。
これは、前回使ったDdeClientTransaction関数を使います。
第1引数に書きこみたいデータを指定します。
第2引数はデータのバイト数です。第6引数を
XTYP_POKEにします。これだけでOKです。
では、プログラムを見てみることにします。
メニュー項目が増えました。ダイアログボックスも ブック名取得用と、セル書き込み用のものが増えました。// dde02.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "終了(&X)", IDM_END END POPUP "DDE(&D)" BEGIN MENUITEM "DDE開始(&S)", IDM_START MENUITEM "DDE終了(&E)", IDM_STOP MENUITEM "データの取得(&G)", IDM_GETDATA MENUITEM "データの書きこみ(&S)", IDM_SETDATA END END ///////////////////////////////////////////////////////////////////////////// // // Dialog // MYDLG DIALOG DISCARDABLE 0, 0, 119, 63 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "DDE利用のデータ取得" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,7,42,50,14 PUSHBUTTON "キャンセル",IDCANCEL,61,42,50,14 LTEXT "取得したいデータ",IDC_STATIC,7,7,51,8 EDITTEXT IDC_EDIT1,32,19,24,12,ES_AUTOHSCROLL LTEXT "R",IDC_STATIC,18,19,8,8 LTEXT "C",IDC_STATIC,62,19,8,8 EDITTEXT IDC_EDIT2,76,19,24,12,ES_AUTOHSCROLL END MYDLG2 DIALOG DISCARDABLE 0, 0, 119, 79 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "データの書きこみ" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,7,58,50,14 PUSHBUTTON "キャンセル",IDCANCEL,63,58,50,14 LTEXT "R",IDC_STATIC,7,7,8,8 EDITTEXT IDC_EDIT1,17,7,21,12,ES_AUTOHSCROLL LTEXT "C",IDC_STATIC,62,7,8,8 EDITTEXT IDC_EDIT2,75,7,21,12,ES_AUTOHSCROLL LTEXT "書きこむデータ",IDC_STATIC,7,23,45,8 EDITTEXT IDC_EDIT3,7,35,96,14,ES_AUTOHSCROLL END GetXLS DIALOG DISCARDABLE 0, 0, 125, 65 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "ブック名" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,7,42,50,14 PUSHBUTTON "キャンセル",IDCANCEL,67,41,50,14 EDITTEXT IDC_EDIT1,7,20,110,15,ES_AUTOHSCROLL LTEXT "操作したいブック名",IDC_STATIC,7,7,56,8 END
前回と比べて書き込み用の関数などが少し増えました。// dde02.cpp #ifndef STRICT #define STRICT #endif #include <windows.h> #include <windowsx.h> #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); HDDEDATA CALLBACK DdemlCallback(UINT, UINT, HCONV, HSZ, HSZ, HDDEDATA, DWORD, DWORD); LRESULT CALLBACK MyDlgProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyDlgProc2(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK GetXLSProc(HWND, UINT, WPARAM, LPARAM); BOOL InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); HINSTANCE hInst; HWND hParent; int DDE_Start(HWND); int DDE_END(HWND); int DDE_GetData(HWND); int DDE_SetData(HWND); char szClassName[] = "dde02"; //ウィンドウクラス DWORD ddeInst; HSZ hszService; HSZ hszTopic; HCONV hConv; char szXLSName[64];//エクセルのブック名 char szBuf[64];//セル char szData[256];//書きこむデータ
このへんはいつもと同じです。int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; if (!InitApp(hCurInst)) return FALSE; if (!InitInstance(hCurInst, nCmdShow)) return FALSE; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } //ウィンドウ・クラスの登録 BOOL InitApp(HINSTANCE hInst) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; //プロシージャ名 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst; //インスタンス wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = "MYMENU"; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); return (RegisterClassEx(&wc)); } //ウィンドウの生成 BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; hInst = hInstance; hWnd = CreateWindow(szClassName, "猫でもわかるDDE",//タイトルバーにこの名前が表示されます WS_OVERLAPPEDWINDOW, //ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 CW_USEDEFAULT, //幅 CW_USEDEFAULT, //高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInstance, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); hParent = hWnd; return TRUE; }
IDM_SETDATAの処理が増えただけです。//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; switch (msg) { case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_START: if (!hConv) DDE_Start(hWnd); else MessageBox(hWnd, "すでに開始されています", "OK", MB_OK); break; case IDM_GETDATA: DDE_GetData(hWnd); break; case IDM_SETDATA: DDE_SetData(hWnd); break; case IDM_STOP: DDE_END(hWnd); break; } break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { DestroyWindow(hWnd); } break; case WM_DESTROY: DDE_END(hWnd); if(DdeUninitialize(ddeInst) != 0) MessageBox(hWnd, "正常にDDE終了", "ok", MB_OK); PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }
ブック名をたずねるダイアログボックスを出すようにしました。int DDE_Start(HWND hWnd) { if(DdeInitialize(&ddeInst, DdemlCallback, APPCMD_CLIENTONLY, 0) != DMLERR_NO_ERROR) { MessageBox(hWnd, "DdeInitialize失敗です", "Error", MB_OK); return -1; }else { MessageBox(hWnd, "初期化成功です", "OK", MB_OK); } if (DialogBox(hInst, "GetXLS", hWnd, (DLGPROC)GetXLSProc) == IDCANCEL) { MessageBox(hWnd, "キャンセルされました", "OK", MB_OK); return -2; } hszService = DdeCreateStringHandle(ddeInst, "Excel.exe", CP_WINANSI); hszTopic = DdeCreateStringHandle(ddeInst, szXLSName, CP_WINANSI); hConv = DdeConnect(ddeInst, hszService, hszTopic, NULL); if (DdeGetLastError(ddeInst) != DMLERR_NO_ERROR) { MessageBox(hWnd, "サーバーに接続失敗", "ok", MB_OK); return -1; } return 0; }
これは、前回と同じです。int DDE_END(HWND hWnd) { if (hConv) { if(DdeFreeStringHandle(ddeInst, hszService) == 0) MessageBox(hWnd, "DdeFreeStringHandle失敗", "Error", MB_OK); if(DdeFreeStringHandle(ddeInst, hszTopic) == 0) MessageBox(hWnd, "DdeFreeStringHandle失敗", "Error", MB_OK); if(DdeDisconnect(hConv) != 0) MessageBox(hWnd, "DdeDisconnect成功", "OK", MB_OK); hConv = 0; } else { MessageBox(hWnd, "終了すべきDDEがありません", "OK", MB_OK); return -1; } return 0; }
セルのデータを取得する関数です。これは、前回と同じです。int DDE_GetData(HWND hWnd) { HDDEDATA hRet; HSZ hszMyTopic; if (!hConv) { MessageBox(hWnd, "DDE開始されていません", "OK", MB_OK); return -1; } DialogBox(hInst, "MYDLG", hWnd, (DLGPROC)MyDlgProc); hszMyTopic = DdeCreateStringHandle(ddeInst, szBuf, CP_WINANSI); hRet = DdeClientTransaction( NULL, 0, hConv, hszMyTopic, CF_TEXT, XTYP_REQUEST, 30000, NULL); if (!hRet && DdeGetLastError(ddeInst) != DMLERR_NO_ERROR) { MessageBox(hWnd, "失敗です", "OK", MB_OK); return -2; } else if (hRet) { DdeGetData(hRet, (LPBYTE)szBuf, sizeof(szBuf), 0); DdeFreeStringHandle(ddeInst, hszMyTopic); DdeFreeDataHandle(hRet); MessageBox(hWnd, szBuf, "DATA", MB_OK); } return 0; }
取得するセルの名前を指定するダイアログボックスのプロシージャです。 これは、前回と同じです。LRESULT CALLBACK MyDlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { char szRC[64]; switch (msg) { case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: strcpy(szBuf, "R"); Edit_GetText(GetDlgItem(hDlg, IDC_EDIT1), szRC, sizeof(szRC)); strcat(szBuf, szRC); Edit_GetText(GetDlgItem(hDlg, IDC_EDIT2), szRC, sizeof(szRC)); strcat(szBuf, "C"); strcat(szBuf, szRC); EndDialog(hDlg, IDOK); return TRUE; case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE; } break; } return FALSE; }
DDEコールバック関数です。今回のプログラムでも呼ばれることはありません。HDDEDATA CALLBACK DdemlCallback(UINT uType, UINT uFmt, HCONV hconv, HSZ hsz1, HSZ hsz2, HDDEDATA hdata, DWORD dwData1, DWORD dwData2) { MessageBox(NULL, "DDEコールバック関数が呼ばれました", "DDECALLBACK", MB_OK); return (HDDEDATA)NULL; }
セルにデータを書き込む関数です。DdeClientTransaction関数の引数の説明を コメントにしてあるので参照して下さい。データサイズは文字列の長さ+1に して下さい。(最後のヌル文字を含めるため)int DDE_SetData(HWND hWnd) { HDDEDATA hRet; HSZ hszMyTopic; if (!hConv) { MessageBox(hWnd, "DDE開始されていません", "OK", MB_OK); return -1; } DialogBox(hInst, "MYDLG2", hWnd, (DLGPROC)MyDlgProc2); hszMyTopic = DdeCreateStringHandle(ddeInst, szBuf, CP_WINANSI); hRet = DdeClientTransaction( (LPBYTE)szData, //クライアントデータ strlen(szData) + 1 , //データサイズ hConv, //通信ハンドル hszMyTopic, //データ項目 CF_TEXT, //クリップボードフォーマット XTYP_POKE, //トランザクションタイプ 10000, // 最大待ち時間 TIMEOUT_ASYNCで非同期となる NULL); // トランザクションの結果 if (!hRet && DdeGetLastError(ddeInst) != DMLERR_NO_ERROR) { MessageBox(hWnd, "失敗です", "OK", MB_OK); return -2; } else if (hRet) { DdeFreeStringHandle(ddeInst, hszMyTopic); DdeFreeDataHandle(hRet); } return 0; }
データ書きこみ用のダイアログボックスのプロシージャです。LRESULT CALLBACK MyDlgProc2(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { char szRC[64]; switch (msg) { case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: strcpy(szBuf, "R"); Edit_GetText(GetDlgItem(hDlg, IDC_EDIT1), szRC, sizeof(szRC)); strcat(szBuf, szRC); Edit_GetText(GetDlgItem(hDlg, IDC_EDIT2), szRC, sizeof(szRC)); strcat(szBuf, "C"); strcat(szBuf, szRC); Edit_GetText(GetDlgItem(hDlg, IDC_EDIT3), szData, sizeof(szData)); EndDialog(hDlg, IDOK); return TRUE; case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE; } return FALSE; } return FALSE; }
ブック名取得用のダイアログボックスのプロシージャです。LRESULT CALLBACK GetXLSProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { switch (msg) { case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: Edit_GetText(GetDlgItem(hDlg, IDC_EDIT1), szXLSName, sizeof(szXLSName)); EndDialog(hDlg, IDOK); return TRUE; case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE; } return FALSE; } return FALSE; }
今回は簡単でした。データを書きこむ際、計算式(=R1C1*R2C2など)を書きこむと いろいろ面白いことが出来ます。
Update 26/Oct/1998 By Y.Kumei