C++ Builder 10.2 Tokyo > Excel 2016 + OLE > .xlsxファイルを開いてセルから値を読込み、TMemoに表示 (クリップボード経由)

```txt:動作環境
RAD Studio 10.2 Tokyo Update 3
Excel 2016
```

### 処理概要

- Excelファイル(.xlsx)を開く
- セルD2の文字(`4`)をString型として取得する
- TMemoに表示する

### 実装

```Unit1.h
//---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE で管理されるコンポーネント
	TButton *Button1;
	TMemo *Memo1;
	void __fastcall Button1Click(TObject *Sender);
private:	// ユーザー宣言
public:		// ユーザー宣言
	__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
```

```Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include <System.Win.ComObj.hpp>  // EXCEL処理用
#include <ClipBrd.hpp>
#include "Unit1.h"

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------


static const String kFile_import = L"Book_200121_1317.xlsx";
//static const String kFile_export = L"Modified_200121_1331.xlsx";

__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	// Excel使用
	Variant ExcelApp = CreateOleObject("Excel.Application");

	// .exeフォルダにあるEXCELファイルのパス
	String curDir = ExtractFileDir(Application->ExeName);
	WideString srcfile = curDir + L"\\" + kFile_import;  // WideStringでないとOleFunctions("Open")はエラーになる

	try {
        Variant xls_books;
        Variant xls_abook;
		Variant book_csv; // データ読込み用csv
		Variant sheet_csv; // データ読込み用csv
		Variant xls_sheets;
		Variant xls_asheet;

		try {
			// 0. Excel初期処理
			ExcelApp.OlePropertySet("Visible", true); // Excel表示
			ExcelApp.OlePropertySet("DisplayAlerts", false); // No dialog for overwrite
			ExcelApp.OlePropertySet("ScreenUpdating", true); // 更新あり
			xls_books = ExcelApp.OlePropertyGet("Workbooks");

			// 1. ファイルオープンとシート選択
			xls_abook = xls_books.OleFunction("Open", srcfile);
			xls_abook.OlePropertyGet("Sheets", 1).OleProcedure("Select");
			xls_asheet = xls_abook.OlePropertyGet("ActiveSheet");

			// 2. D2セル選択してクリップボードへ
			Variant wrkRange = xls_asheet.OlePropertyGet("Range", WideString("D2"));
			wrkRange.OleProcedure("Copy");

			// 処理待ち
			Application->ProcessMessages();
			Sleep(300); // msec

			// 3. クリップボードからの取得
			String astr = Clipboard()->AsText;

			Memo1->Lines->Add(astr);  // 確認用出力

			// 4. Excel終了
			ExcelApp.Exec(Procedure("Quit"));
		} __finally {
			xls_asheet = Unassigned();
			xls_abook = Unassigned();
			xls_books = Unassigned();
		}
	}
	__finally
	{
		ExcelApp = Unassigned();
	}
}
//---------------------------------------------------------------------------
```

### 使用EXCELファイル例

下記は`Book_200121_1317.xlsx`ファイルの中身。
セルD2を読む。

![2020-01-21_15h40_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32870/17b3341d-9e04-288c-9cdb-bd0d367d945c.png)


### 実行

[Button1]を押下するとExcelが起動してファイルを開き、TMemoに以下のように4を追記する。

![2020-01-21_15h38_25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32870/4849b7c4-a31c-f3a4-5ec8-fa1721e8638c.png)

### 備考

クリップボード読取りの前に300msecの待ちを入れた。これがないとエラーになる。
OLEのメソッドで直接読む方法はあるような気はする。


### 関連

- [C++ Builder XE4 > Excel 2016 + OLE > csvファイルを読込んで、コピーし、xlsxファイルにペーストして、別名保存](https://qiita.com/7of9/items/5f6e87df2deef0990d8b)


### 補足 > CR, LF

`String astr = Clipboard()->AsText;`にて取得した文字列にはCR, LFが後ろに付随する。
その後ろに文字列を結合する場合は、CR, LFを除去した上で結合すること (PasteSpecialにて二行になるため）。

### 備考 > クリップボードの読込み

クリップボードへのコピーと読込み処理。このあたりを短時間で実行するとエラーになりやすい。
待ち時間が必要。
300msecでもときどきエラーが出るようだ。


### 処理の問題

クリップボード経由だと、クリップボードの処理が重い。タイミングによってはエラーになる。
下記に実装している、`getCellValue()`と`setCellValue()`を使った処理に変更するほうが良い。

- [C++ Builder XE4 > Excel処理 > 1つめのシートを選択する (シート名は任意)](https://qiita.com/7of9/items/ff3a43911d3797da3dd2)