C++ ⇒ VBA 書いて覚えるための初心者自己中記事

C++ ⇒ VBA 勉強の履歴を付けるというかノート代わりに使ってます

Excel VBA データがある行の最終行数を取得したいときに使える便利なUsedRange

Excel VBA で作業するときにちょくちょく必要になってくるのが

「データの最終行」だと思います。

 

[Ctrl + Down ] をしたことにするとか

Excelの最下段(100万行以上とか)に移動してから[Ctrl + Up ]するとかが

良くありますが、これだと列に依存するので汎用性のある機能として

VBAを書けません。

 

なので、現在データを使用しているエリアを四角形の選択範囲のように取得できる

UsedRangeが活用できます。

 

まずは、結果から。

ActiveSheet.UsedRange.Item(ActiveSheet.UsedRange.count).row

 

これで現在のシート上の最終行が取得できます。

分解して確認しましょう。

ActiveSheet.UsedRange.Item(ActiveSheet.UsedRange.count).row

   ①    ②    ③  (    ④      )  ⑤  

ActiveSheet

 現在表示されているアクティブなシートで

UsedRange

 使用されている範囲の

Item(  )

 1つずつのセルを任意で選択(数値で指定)

ActiveSheet.UsedRange.count

 ③で指定するセルは、同じくアクティブシートの使用範囲内で最後のセルを指す数値

row

 ④までで指定したセルの行番号

 

以上。

 

実際に使用する場合は変数に代入したりして使うと思います。何度も使うし長いので。

Dim rowNum as Long

rowNum = ActiveSheet.UsedRange.Item(ActiveSheet.UsedRange.count).row

 

とっても便利!!

 

C++ 初期化子 書いて覚えるための初心者自己中記事

面白いC++のテキストを見ています。

double d1 = 2.3;
double d2(2.3);
double d3{ 2.3 };//これでも出来る
 
std::vector<int> v = { 1,2,3, };
std::vector<int> v2{ 1,2,3, };//これでも出来る
 
int i1 = 7.2;//警告(切り捨てられる)
int i2 = { 7.2 };//エラー
int i3{ 7.2 };//エラー
 
//波カッコ{}で初期化を統一すると楽(=がいらない)
//型を間違えても波カッコならエラーになってくれる

 

波カッコ最強。

 

って思って次のページ見たらauto使いましょう!って出てた。

class testclass {
public:
	testclass(int i, double d) :i{ i }, d{ d } {};//波カッコ最強
	void Show() {std::cout << i << " : " << d << " : " << this << std::endl;}
 
private:
	int i;
	double d;
};
 
int main() {
 
	auto d1 = 2.3;
	auto d2(2.3);
	auto d3 = { 2.3 };
	auto d4{ 2.3 };
 
	std::vector<int> v1 = { 1,2,3, };
	std::vector<int> v2{ 1,2,3, };
 
	auto v3{ v2 };//出来る
 
	testclass test{ 1,2.2 };
	auto c_test{ test };//出来る
 
	test.Show();
	c_test.Show();
 
	std::cout << &test << std::endl;
	std::cout << &c_test << std::endl;
	
 
	system("pause");
}
//output
1 : 2.2 : 00B3FB54
1 : 2.2 : 00B3FB3C
00B3FB54
00B3FB3C

auto凄いなぁ。クラステンプレートのオブジェクトもautoと波カッコで複製出来た。

テスト用のクラスも同じでautoと波カッコで複製出来た。引数付きのコンストラクタ用意してたんだけど複製で引数入れてなかった。

でも複製元で入ってたのがそのまま入ってる。

オブジェクトのアドレス一応確認したけど、別々だ。

 

なんか、autoの場合は = を使ったほうがいいって書いてある。

なんだよ・・。

 

あぁ、今日はWindowsのDirect2Dでコテンパンにされたけど、癒される~

 

ここまで~。

C++ Windows プログラミング⑥ 書いて覚えるための初心者自己中記事

Windowsのグラフィックス アーキテクチャの概要

 

 

アーキテクチャってなんだ?

構造とか構成のことか。

 

Windowsでは数種類のC++/COM APIがある。

Windows グラフィックス API の相関図

 

・グラフィックスデバイスインターフェイス(GDI)

Windowsにもともと実装されていたグラフィックスインターフェイス

16ビットのWindows用に開発され32ビット・64ビットに移植された。

 

・GDI+

GDIの後継(詳細はちょっと意味わからない)

 

Direct3D

3Dグラフィックスをサポート

 

続きを読む

C++ Windows プログラミング⑤ 書いて覚えるための初心者自己中記事

COM  オブジェクトの有効期間を管理する。

 

全てのCOMインターフェイスは、インターフェイスIUnknownを直接・間接的問わず継承する必要がある。

なぜならこのインターフェイスIUnknownはCOMオブジェクトがサポートしなければならない基本機能を提供しているから。

その基本機能が3つあって、

QueryInterface

AddRef

Release

だ。

QueryInterfaceメソッドがあると、実行時にプログラムがオブジェクトの機能をクエリ出来るようになる。

クエリって検索的な意味でいいのかな。

AddRefとReleaseはこれから勉強するオブジェクトの有効期間の管理に使用する。

 

続きを読む

C++ Windows プログラミング④ 書いて覚えるための初心者自己中記事

COMオブジェクトの作成

 

COMオブジェクトを作成する方法は2つある。

  • オブジェクトを実装するモジュールによって、そのオブジェクトのインスタンスを作成するために設計された関数を提供する。
  • COM によって CoCreateInstance という汎用作成関数を提供する。

1つ目の日本語が頭に入ってこない。

なんか、COMの話に入ってからずっとそうなんだけど、視点がどこにあるのかわからない。

 

なるほど、

// 実際の Windows 関数ではない 

HRESULT CreateShape(IDrawable** ppShape);

この関数に基づき、新しい Shape オブジェクトを以下のように作成できます。

 
 
IDrawable *pShape;

HRESULT hr = CreateShape(&pShape);
if (SUCCEEDED(hr))
{
    // Shape オブジェクトを使用する
}
else
{
    // エラーが発生する
}

IDrawable型のポインタをCreateShape関数に渡すときに、ポインタのアドレスを渡してポインタの参照先を書き換えるのか。なぜならCreateShape関数の戻り値はすでにHRESULTで使われているから。

 これが一番目の方法なのか。

 

二番目の方法。CoCreateInstance関数。

 一般的なオブジェクト作成方法と書いてある。こっちが一般的に使われるのかな。

えー、2つのCOMオブジェクトが同じインターフェイスを実装出来て、

1つのオブジェクトが複数のインターフェイスを実装できる。というのが重要。

続きを読む

C++ Windows プログラミング③ 書いて覚えるための初心者自己中記事

前回Windowsデベロッパーセンターの初心者用ページについていけなくなった件。

とりあえず、ぼんやりと理解できたから先に進む。

あ、前回わからなかったのを貼ってから進む。

 

#ifndef UNICODE
#define UNICODE
#endif 
 
#include <windows.h>
 
template <class DERIVED_TYPE>//ウィンドウに関することをまとめたクラステンプレート/抽象クラスなので継承して使う
class BaseWindow
{
public:
	static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)//staticなメンバのウィンドウプロシージャ DispatchMessageはここにメッセージを渡す
	{
		DERIVED_TYPE *pThis = NULL;
 
		if (uMsg == WM_NCCREATE)
		{
			CREATESTRUCT* pCreate = (CREATESTRUCT*)lParam;
			pThis = (DERIVED_TYPE*)pCreate->lpCreateParams;
			SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);//作成したウィンドウにこのクラス自体が関連付けられる?
 
			pThis->m_hwnd = hwnd;//メンバ変数m_hwndに作成したウィンドウのハンドルを登録
		}
		else
		{
			pThis = (DERIVED_TYPE*)GetWindowLongPtr(hwnd, GWLP_USERDATA);//ウィンドウ作成済みのメッセージも場合は関連付けられた自身を呼び出す。(メンバ関数が使えるということ?)
		}
		if (pThis)
		{
			return pThis->HandleMessage(uMsg, wParam, lParam);//メッセージごとの処理はHandleMessageで行う
		}
		else
		{
			return DefWindowProc(hwnd, uMsg, wParam, lParam);
		}
	}
 
	BaseWindow() : m_hwnd(NULL) { }//コンストラクタ/メンバ変数m_hwndの初期化
 
	BOOL Create(//ウィンドウの作成を行うメンバ関数/m_hwndにハンドルが入ったかどうかをboolで返す
		PCWSTR lpWindowName,
		DWORD dwStyle,
		DWORD dwExStyle = 0,
		int x = CW_USEDEFAULT,
		int y = CW_USEDEFAULT,
		int nWidth = CW_USEDEFAULT,
		int nHeight = CW_USEDEFAULT,
		HWND hWndParent = 0,
		HMENU hMenu = 0
	)
	{
		WNDCLASS wc = { 0 };
 
		wc.lpfnWndProc = DERIVED_TYPE::WindowProc;
		wc.hInstance = GetModuleHandle(NULL);
		wc.lpszClassName = ClassName();
 
		RegisterClass(&wc);
 
		m_hwnd = CreateWindowEx(
			dwExStyle, ClassName(), lpWindowName, dwStyle, x, y,
			nWidth, nHeight, hWndParent, hMenu, GetModuleHandle(NULL), this
		);
 
		return (m_hwnd ? TRUE : FALSE);
	}
 
	HWND Window() const { return m_hwnd; }//m_hwndに入っているウィンドウハンドルを取得するメンバ関数
 
protected:
 
	virtual PCWSTR  ClassName() const = 0;//派生クラスで指定するための純粋仮想関数
	virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) = 0;//派生クラスで指定するための純粋仮想関数
 
	HWND m_hwnd;//作成したウィンドウのハンドルを保持するメンバ変数
};
 
class MainWindow : public BaseWindow<MainWindow>//派生クラスでごとにウィンドウを作れる
{
public:
	PCWSTR  ClassName() const { return L"Sample Window Class"; }//ウィンドウクラスの名前の設定
	LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);//ウィンドウプロシージャに来たメッセージはここに送られてくるのでこっちで処理する
};
 
 
 
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
	MainWindow win;//抽象クラステンプレート?というのか? の派生クラスを用意して実体化
 
	if (!win.Create(L"Learn to Program Windows", WS_OVERLAPPEDWINDOW))//メンバ関数Createでウィンドウ作成
	{
		return 0;
	}
 
	ShowWindow(win.Window(), nCmdShow);//ShowWindow関数の第一引数に必要なウィンドウハンドルはメンバ関数Windowで取得できる
 
	// メッセージ ループを実行する
 
	MSG msg = {};
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
 
	return 0;
 
 
}
 
LRESULT MainWindow::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)//ウィンドウプロシージャから渡されたメッセージの処理はここで行う
{
	switch (uMsg)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
 
	case WM_PAINT:
	{
		PAINTSTRUCT ps;
		HDC hdc = BeginPaint(m_hwnd, &ps);
		FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
		EndPaint(m_hwnd, &ps);
	}
	return 0;
 
	default:
		return DefWindowProc(m_hwnd, uMsg, wParam, lParam);
	}
	return TRUE;
}
 

 

 よし、Windowsデベロッパーセンターの初心者ページ、解説文でこれは単純って書かなくてもいいじゃん・・。難しいよ・・。

 

続きを読む

C++ Windows プログラミング② 書いて覚えるための初心者自己中記事

ウィンドウを作成する

 

ウィンドウクラスを作成する。

C++のクラスとは違う。

ウィンドウクラスには複数のウィンドウが共通して実行する一連の動作が定義される。

共通しない部分(各ウィンドウ固有のデータ)はインスタンスデータと呼ばれる。

 

ウィンドウクラスは実行時にシステムに登録される。

登録するにはまず、WNDCLASSという構造体に情報を入れていくらしい。

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
const wchar_t CLASS_NAME[] = L"Sample Window Class";
 
WNDCLASS wc = {};
 
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;

3つのメンバにいれてる。

lpfnWndProc     

ウィンドウプロシージャと呼ばれるアプリケーション定義関数へのポインタ。

ウィンドウ動作の大部分がこのプロシージャで定義されるらしい。

ウィンドウプロシージャそのものは後で解説入るそう。

とりあえず、ウィンドウプロシージャへのポインタ。

 

続きを読む