*References:

가끔 다른 프로세스의 SysListView32를 읽고싶을 때가 있다.
그런데 막상 해보니까 쉬울줄 알았던 일이 잘 안돼서 고생을 좀 하다가.. 검색을 통해 해결했다.
우선 다음과 같은 코드를 생각해보자.
#define WIN32_LEAN_AND_MEAN // compile faster
#include <stdio.h>
#include <locale.h>
#include <windows.h>
#include <commctrl.h>

const int COLS(5), SZBUF(512);
int main(void)
{
	setlocale(LC_ALL, ""); // 한글 출력을 위해 기본 로케일 설정.
	HWND hParent = FindWindow(NULL, L"SW 찾기");
	HWND hListView = FindWindowEx(hParent, NULL, L"SysListView32", NULL);

	int numItems=(int)SendMessage(hListView, LVM_GETITEMCOUNT, 0, 0);

	LVITEM lvi;
	wchar_t subItems[COLS][SZBUF] = {};

	lvi.cchTextMax=SZBUF; // 텍스트 버퍼 사이즈를 설정

	for(int i = 0; i < numItems; i++) {
		for (int j = 0; j < COLS; j++) {
			// j번째 column의 값을 얻는다.
			lvi.iSubItem = j;
			lvi.pszText = subItems[j];
			wcscpy(subItems[j], L"끼야아앙");
			SendMessage(hListView, LVM_GETITEMTEXTW, (WPARAM)i, (LPARAM)&lvi);
			printf("%s%ls", j > 0 ? ";" : "", subItems[j]);
			// column1;column2;column3 형식으로 한 줄씩 출력.
		}
		puts("");
	}

	return 0;
}

완벽해보이...지만 실행해보면?

 C:\>a.exe
 끼야아앙;끼야아앙;끼야아앙;끼야아앙;끼야아앙
 끼야아앙;끼야아앙;끼야아앙;끼야아앙;끼야아앙
 C:\>

실제로 버퍼에 아무것도 쓰이지 않은 것을 확인할 수 있다.
원인이 뭘까 고민해보다가 reference에서 그 답을 찾았다.
요약하자면 "ListView를 가진 프로세스는 a.exe의 메모리에 접근 권한이 없음!" 이라고..
그러므로 일단 ListView를 가진 프로세스에 메모리를 할당하고,
우리는 ReadProcessMemory/WriteProcessMemory를 이용해서 해당 메모리에 접근하면 된다.
덕분에 코드는 더 지저분해졌지만, 어쨌든 돌아는 간다 :D

최종 결과물

#define WIN32_LEAN_AND_MEAN // compile faster
#include <stdio.h>
#include <locale.h>
#include <windows.h>
#include <commctrl.h>

const int COLS(5), SZBUF(512);
int main(void)
{
	setlocale(LC_ALL, ""); // 한글 출력을 위해 기본 로케일 설정.
	HWND hParent = FindWindow(NULL, L"SW 찾기");
	HWND hListView = FindWindowEx(hParent, NULL, L"SysListView32", NULL);

	int numItems=(int)SendMessage(hListView, LVM_GETITEMCOUNT, 0, 0);

	LVITEM lvi, *_lvi = NULL;
	wchar_t subItems[COLS][SZBUF] = {};
	wchar_t *_subItems[COLS] = {};
	unsigned long pid = -1;
	HANDLE process = NULL;
	
	// hWnd로부터 pid를 얻는다.
	GetWindowThreadProcessId(hListView, &pid);
	// 해당 pid를 가진 프로세스에 대해 VM조작 권한을 얻는다.
	process=OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ|
		PROCESS_VM_WRITE|PROCESS_QUERY_INFORMATION, FALSE, pid);

	_lvi=(LVITEM*)VirtualAllocEx(process, NULL, sizeof(LVITEM),
		MEM_COMMIT, PAGE_READWRITE);
	// ListView를 가지고 있는 프로세스에 LVITEM 메모리를 할당한다.

	for (int i = 0; i < COLS; i++) {
		_subItems[i]=(wchar_t*)VirtualAllocEx(process, NULL,
							SZBUF * sizeof(wchar_t),
							MEM_COMMIT,
							PAGE_READWRITE);
		// ListView를 가지고 있는 프로세스에 wchar[] 메모리를 할당한다.
	}

	lvi.cchTextMax=SZBUF; // 텍스트 버퍼 사이즈를 설정

	for(int i = 0; i < numItems; i++) {
		for (int j = 0; j < COLS; j++) {
			// j번째 column의 값을 얻는다.
			lvi.iSubItem = j;
			lvi.pszText = _subItems[j];
			// 반환되는 텍스트는 타겟 프로세스의 wchar[] 버퍼에 써진다.
			WriteProcessMemory(process, _lvi, &lvi, sizeof(LVITEM), NULL);
			// 타겟 프로세스의 LVITEM에 lvi의 설정값을 쓴다(복사).
			SendMessage(hListView, LVM_GETITEMTEXTW, (WPARAM)i, (LPARAM)_lvi);
			ReadProcessMemory(process, _subItems[j], subItems[j], SZBUF, NULL);
			// 타겟 프로세스의 wchar[] 버퍼를 읽는다.
			printf("%s%ls", j > 0 ? ";" : "", subItems[j]);
			// column1;column2;column3 형식으로 한 줄씩 출력.
		}
		puts("");
	}

	// 타겟 프로세스에 할당한 메모리를 해제한다.
	VirtualFreeEx(process, _lvi, 0, MEM_RELEASE);
	for (int j = 0; j < COLS; j++) {
		VirtualFreeEx(process, _subItems[j], 0, MEM_RELEASE);
	}

	return 0;
}