인쇄기 Align

'작업 > 설비' 카테고리의 다른 글

파나소닉 A6 모터 설정(리니어, 볼스크류)  (0) 2020.08.12
Dxf File 가공라인 전환  (0) 2020.04.01
Bending 궤적 Simulation  (0) 2019.10.25
UVW Stage 공식 #2  (0) 2019.10.25
UVW Stage 공식 #1  (0) 2019.10.25

OpneCV를 사용하는 MFC Project에서 처리시간 측정을 위한 코드.

double t = cvGetTickCount();
//--------------
//측정하고자 하는 코드.
.
.
.
//--------------
t = cvGetTickCount() - t;
double nLoadingTime_ms = t / ((double)cvGetTickFrequency()*1000.0);
CString strMsg;
strMsg.Format(L"%0.1fms", nLoadingTime_ms);
AfxMessageBox(strMsg);

'작업 > OpenCV' 카테고리의 다른 글

OpenCV Version 정리  (0) 2022.02.24
CvvImage 추가 3.4 까지  (0) 2021.11.09
OpneCV Test(4.1.2, 3.8.4, 3.4.0)  (0) 2019.11.22
OpenCV 컴파일(3.4.0, 3.4.8, 4.1.2)  (0) 2019.11.21
OpenCV 4.x.x 사용 C++ Runtime Library Debug  (0) 2019.11.20

Cuda Thread, Grid, Block 설정 시에 참고하세요.

Grid->Block->Thread와 각 Thread에 위치 정보와 Data 전달 개념을 잡아가야 합니다. 

 

그림 참조 : https://phychai.wordpress.com/2015/05/26/cuda-programming-thread-block-grid/

//=====================================================================================
//Cuda102.cuh
	typedef struct _XYPos_
	{
		int x;
		int y;

		int blockIdx_x;
		int blockDim_x;
		int threadIdx_x;

		int blockIdx_y;
		int blockDim_y;
		int threadIdx_y;
	}XYPos;
	class CudaProc
	{
	public:
		CudaProc(void);
		virtual ~CudaProc(void);
	//----------------------------------------------------------
	public:
		int ProcBlockThread(int nXCnt, int nYCnt, XYPos *pXYList);
	};



//=====================================================================================
//Cuda102.cu
__global__ 
void XYPosCheck(int nXCnt, int nYCnt, XYPos *pXYList)
{
	//1) 2차원 배열 접근 형태의 tidX와 tidY를 구한다.
	int tidX = blockIdx.x * blockDim.x + threadIdx.x;
	int tidY = blockIdx.y * blockDim.y + threadIdx.y;

	//2) tidX와 tidY는 16의 배수형태로 Thread가 할당되어 주어진 Memory보다 많게 된다.
	//  Count X와 Count Y의 범위 내에서만 메모리에 접근하여 Data를 체워준다.
	if (tidX < nXCnt && tidY < nYCnt)
	{
		pXYList[tidX + (nXCnt * tidY)].x = tidX;
		pXYList[tidX + (nXCnt * tidY)].y = tidY;

		pXYList[tidX + (nXCnt * tidY)].blockIdx_x = blockIdx.x;
		pXYList[tidX + (nXCnt * tidY)].blockDim_x = blockDim.x;
		pXYList[tidX + (nXCnt * tidY)].threadIdx_x = threadIdx.x;

		pXYList[tidX + (nXCnt * tidY)].blockIdx_y= blockIdx.y;
		pXYList[tidX + (nXCnt * tidY)].blockDim_y= blockDim.y;
		pXYList[tidX + (nXCnt * tidY)].threadIdx_y = threadIdx.y;
	
		float fAsphericZ_mm = K_Aspheric(12.3, (float)tidX, (float)tidY);
	}
}
__host__
int CudaProc::ProcBlockThread(int nXCnt, int nYCnt, XYPos *pXYList)
{
	int nCnt_X = nXCnt;
	int nCnt_Y = nYCnt;

	//1)처리를 위한 data 생성.
	int nThreadCnt = (nCnt_X*nCnt_Y);
	int nRetMemsize = nThreadCnt * sizeof(XYPos);

	XYPos  *C_pRet_XY = nullptr;
	cudaMalloc((void**)&C_pRet_XY, nRetMemsize);

	//2) Cudat Thread, Block 할당.

	dim3 threads(16, 16);

	int nGridCntX = nCnt_X / threads.x + (nCnt_X % threads.x > 0 ? 1 : 0);
	int nGridCntY = nCnt_Y / threads.y + (nCnt_Y % threads.y > 0 ? 1 : 0);
	dim3 grid(nGridCntX, nGridCntY);
	//a) 기본 Thread Count는 16*16의 크기로 256개를 잡는다.
	//b) grid는 입력된 X Data의 X성분을 16개의 X성분 Thread로 나누어 준다.
	//c) grid는 입력된 Y Data의 Y성분을 16개의 Y성분 Thread로 나누어 준다.
	//d) 나눈 나머지가 발생하면 Grid항목 1(thread 16개)을 추가 한다.
	//(XYPosCheck()안에서 tidX와 tidY의 법위가 넘는것은 Thread수의 배수로 증가 해서이다.)

	//3) Data 처리
	XYPosCheck << < grid, threads >> > (nXCnt, nYCnt, C_pRet_XY);

	//4) 결과 Data 전달.
	cudaMemcpy((void*)pXYList, (void*)C_pRet_XY, nRetMemsize, cudaMemcpyDeviceToHost);

	//5) 생성 메모리 처리.
	cudaFree(C_pRet_XY);
	return 1;
}
//=====================================================================================
//CudaTestDlg.cpp
void CCudaTestDlg::OnBnClickedBtCudaTest()
{
	CudaProc HWAccGPU;
	int nXCnt = 210;
	int nYCnt = 260;

	XYPos *pXYList= new XYPos[nXCnt * nYCnt];
	//Cuda Object
	HWAccGPU.ProcBlockThread(nXCnt, nYCnt, pXYList);

	for (int iy = 0; iy < nXCnt * nYCnt; iy++)
	{
		TRACE(L"==.....>>>>>>%d) X:%d, Y:%d\r\n", iy, pXYList[iy].x, pXYList[iy].y);
		TRACE(L"==.....            X) %d, %d, %d\r\n", 
        		pXYList[iy].blockIdx_x, pXYList[iy].blockDim_x, pXYList[iy].threadIdx_x);
		TRACE(L"==.....            Y) %d, %d, %d\r\n", 
        		pXYList[iy].blockIdx_y, pXYList[iy].blockDim_y, pXYList[iy].threadIdx_y);
	}

	delete[] pXYList;
}
//=====================================================================================
//결과

==.....>>>>>>0) X:0, Y:0
==.....            X) 0, 16, 0
==.....            Y) 0, 16, 0
==.....>>>>>>1) X:1, Y:0
==.....            X) 0, 16, 1
==.....            Y) 0, 16, 0
==.....>>>>>>2) X:2, Y:0
==.....            X) 0, 16, 2
==.....            Y) 0, 16, 0
==.....>>>>>>3) X:3, Y:0
==.....            X) 0, 16, 3
==.....            Y) 0, 16, 0
==.....>>>>>>4) X:4, Y:0
==.....            X) 0, 16, 4
==.....            Y) 0, 16, 0
==.....>>>>>>5) X:5, Y:0
==.....            X) 0, 16, 5
==.....            Y) 0, 16, 0
==.....>>>>>>6) X:6, Y:0
==.....            X) 0, 16, 6
==.....            Y) 0, 16, 0


...

== .....>>>>>>54594) X:204, Y : 259
== .....               X) 12, 16, 12
== .....               Y) 16, 16, 3
== .....>>>>>>54595) X:205, Y : 259
== .....               X) 12, 16, 13
== .....               Y) 16, 16, 3
== .....>>>>>>54596) X:206, Y : 259
== .....               X) 12, 16, 14
== .....              Y) 16, 16, 3
== .....>>>>>>54597) X:207, Y : 259
== .....              X) 12, 16, 15
== .....              Y) 16, 16, 3
== .....>>>>>>54598) X:208, Y : 259
== .....              X) 13, 16, 0
== .....              Y) 16, 16, 3
== .....>>>>>>54599) X:209, Y : 259
== .....              X) 13, 16, 1
== .....              Y) 16, 16, 3

1) 입력 Data는 54600개이고, X 210, Y 260개 Data라고 보면 된다.

2) XYPosCheck() 함수 안에서 tidX, tidY의  접근 인자들을 정상적으로 Memory에 표기하여 돌려보내준다.

3) X와 Y Data크기가 tidX, tidY와 같은 크기로 설정하여 적용하면 의미 없는 Thread는 없어지지만 원하는 속도가 나오기 힘들다.(2의 배수로 Threa Block이 할당된다.)

 

Thread Block Test
dim3 threads(64, 64); //==>>오동작
dim3 threads(32, 32); //==>>느려짐
dim3 threads(16, 16); //==>>보통
dim3 threads(8, 8); //==>>미미하게 빨라짐
dim3 threads(4, 4); //==>>느려짐

'작업 > Cuda' 카테고리의 다른 글

NVIDIA Cuda Cores 참고  (0) 2022.02.24
기존 Project Cuda Link時 오류  (1) 2020.05.06
CPU-GPU 속도 Test  (0) 2019.12.03
VS2017 - NVIDIA Cuda 연결  (0) 2019.12.03

uafxcwd.lib  error LNK2005

Link 추가 연결

 

'작업 > Cuda' 카테고리의 다른 글

NVIDIA Cuda Cores 참고  (0) 2022.02.24
Cuda Block Thread 설정.  (0) 2020.05.26
CPU-GPU 속도 Test  (0) 2019.12.03
VS2017 - NVIDIA Cuda 연결  (0) 2019.12.03

Dwg File은 CAD 전용이라 File Format이 Open 되어있지 않다.

Dxf는 설계 파일 표준 Format이라 String Type으로  Format이 Open 되어 있다.

 

1) Layer 분리 가능
2) Dxf File의 Entity 묶기 불가.(풀어줘야 해석 가능)-좌표 변환오류가 발생한다.

 

 

 

 

'작업 > 설비' 카테고리의 다른 글

파나소닉 A6 모터 설정(리니어, 볼스크류)  (0) 2020.08.12
인쇄기 Align동작 영상  (0) 2020.07.17
Bending 궤적 Simulation  (0) 2019.10.25
UVW Stage 공식 #2  (0) 2019.10.25
UVW Stage 공식 #1  (0) 2019.10.25

병렬 Process를 적용 하자.

 

a) for문 구성을 간단하게 Multi Thread와 같은 형태로 변환해준다.(병렬 프로그래밍)

- 8Thread CPU에서 4개를 사용할 경우에 속도 향상이 가장 좋아 4개로 기준 한다.(여러가지 요건에 의해 바뀔 수 있음)

b) 임의로 분리 수를 조절 할 수 있다.

c) 아주 간단하게 반복문의 정보 처리를 빠르게 할 수 있다.

 

* Window 자원요소등에 접근해야 할 경우 주의를 요한다.(로컬 변수 형태로 Object를 관리해줘야 한다)

 (직접 작성 코드에 대한 병렬화에 매우 좋은 효과를 기대 할 수 있다)

* GPU가 아닌 CPU자원을 사용하는 것이다 *^^;;

 

1) 설정.

Open MP를 사용하기 위한 설정

 

 

2) 기본 코드

		int nThAllCht =  OMP_TH_CNT;//(4)// omp_get_num_threads();
		omp_set_num_threads(nThAllCht);
#pragma omp parallel//윈도우즈용 비주얼 스튜디오는 알아서 컴파일 해준다.
		{
            //이하 코드는 For문을 각 Thread에게 공통적으로 분배 해주는 역할을 한다.
            // 1003개의 Data를 4개의 Thread가 처리 한다면.
            //1번 250개, 2번 250개, 3번 250개, 4번 250 + 3(나머지)를 처리 한다.
			int nListCnt = nReadFileCnt;//for문을 돌릴 총 수
			int nThCnt = omp_get_max_threads();
			int nThNum = omp_get_thread_num();

			int nJump = nListCnt / nThCnt;
			int nJumpN = nListCnt % nThCnt;

			int nStartIndex = (nThNum*nJump);
			int nTailAddCnt = 0;
			if (nThCnt == (nThNum + 1))//nThNum이 Zero Index임으로.
				nTailAddCnt = nJumpN;

			for (int iF = nStartIndex; iF < (nStartIndex + nJump + nTailAddCnt); iF++)
			//for (int iF = 0; iF < nReadFileCnt; iF++)//원본 For문
			{
            ...//반복 수행 코드.
            }
  #pragma omp barrier //모든 Thread가 여기에 도착 하도록 기다린다.
		}

1) 파일명에 특수(%)등이 포함된 문자열을 TRACE로 찍으면 에러가 난다.

 - File명에는 "%"문자가 들어갈 수 있다.(오류메시지가 안나고 그냥 죽는다).


2) CTime Obj는 1970년 이전 설정시 DebugMessage가 뜬다.

   int nYYYY = 1970;

 - CTime cTimeX(nYYYY, nMM, nDD, 0, 0, 0);//Debug Message가 출력되며 죽는다.

여러 군대 찾아도 정보가 미흡하여,  사용 가능하게 정리하였습니다.

 - XLEzAutomation이나 ExcelLib의 기능에 원하는 기능 구현이 없고 수정 추가에도 어려움이 있어서...

 - 잘 활용하시기 바랍니다.

 

Excel 컨트롤 클래스 만들기.

(필요할 때마다 하나씩 추가 하자~~~~)

구현 기능

1 파일 열기,

2 파일 닫기,

3 다른이름 저장,

4 값 일기,

5 값 쓰기,

6 이미지 저장하기(클립보드, 절대 경로 Link, Link를 이용한 포함시키기)

7 Sheet Active 시키기.

 

미구현 기능

8 차트 만들기.

9 Sheet이름 바꾸기.

10 범용 알고리즘 콜하기.

 

추가된 Excel File들은 복사하여 다른 프로젝트에 Link를 걸고 그대로 사용 가능하다.

(MFC에서 Excel 컨트롤 하기(1)을 매 프로젝트에 추가할 필요는 없다)

#include "CApplication.h"//
#include "CWorkbook.h"//
#include "CWorkbooks.h"//

#include "CWorksheet.h"//
#include "CWorksheets.h"//


#include "CChart.h"//
#include "CCharts.h"//

#include "CBorder.h"//
#include "CBorders.h"//

#include "CPicture.h"//
#include "CPictures.h"//

#include "CRange.h"//
#include "CFont0.h"//

#include "CShapes.h"
#include "CShape.h"

 

 

구현 해더 파일.(ExcelCtrl.h)

#pragma once

#include "CApplication.h"//
#include "CWorkbook.h"//
#include "CWorkbooks.h"//

#include "CWorksheet.h"//
#include "CWorksheets.h"//


#include "CChart.h"//
#include "CCharts.h"//

#include "CBorder.h"//
#include "CBorders.h"//

#include "CPicture.h"//
#include "CPictures.h"//

#include "CRange.h"//
#include "CFont0.h"//

#include "CShapes.h"
#include "CShape.h"

static CString ColToColLetter(int colIndex)
{
	int div = colIndex;
	CString colLetter;// = String.Empty;
	int mod = 0;

	while (div > 0)
	{
		mod = (div - 1) % 26;
		colLetter = (char)(65 + mod) + colLetter;
		div = (int)((div - mod) / 26);
	}
	return colLetter;
}
static int ColLetterToColIndex(CString columnLetter)
{
	columnLetter = columnLetter.MakeUpper();
	int sum = 0;

	for (int i = 0; i < columnLetter.GetLength(); i++)
	{
		sum *= 26;
		sum += (columnLetter[i] - L'A' + 1);
	}
	return sum;
}

class CExcelCtrl
{
public:
	CExcelCtrl();
	~CExcelCtrl();

private:
	// spreadsheet variables
	CApplication	m_app;
	CWorkbook		m_book;
	CWorkbooks		m_books;


	CWorksheets		m_worksheets;


	COleVariant		m_covTrue;
	COleVariant		m_covFalse;
	COleVariant		m_covOptional;

	CString			m_strOpenFile;


private:
	void CloseWorkbook();
public:
	//1) File 열고 닫기.
	bool OpenFile(CString strFilePath);
	bool CloseFile();
	bool SaveFile();
	bool SaveAsFile(CString newFullPath);
	//2) Data 읽고 쓰기.
	CString GetValue(int nSheet, CString strCellPos);//CellPos :"A1", "O21"
	void SetValue(int nSheet, CString strCellPos, CString strNewValue);
	//3) Image 삽입.
	void SetPasteClipboard(int nSheet, CString strCellPos, double fViewSizeW = 0.0, double fViewSizeH = 0.0);//클립 보드의 이미지 삽입
	void SetPasteFileLink(int nSheet, CString strCellPos, CString strImgPath, double fViewSizeW = 0.0, double fViewSizeH = 0.0);//주어진 이미지 절대 경로를 삽입.(경로만)
	void SetFileLinkAndAdd(int nSheet, CString strCellPos, CString strImgPath, int orgW, int orgH, double fViewSizeW = 0.0, double fViewSizeH = 0.0);//경로의 파일을 삽입.(Excel File에 첨부)

	void SetActiveSheet(int nSheet);
};

 

구현 소스파일(ExcelCtrl.cpp)

#include "stdafx.h"
#include "ExcelCtrl.h"
#define rmm     23
CExcelCtrl::CExcelCtrl():
	m_app(nullptr),
	m_book(nullptr),
	m_books(nullptr),
	m_covTrue((short)TRUE),
	m_covFalse((short)TRUE),
	m_covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR)

{
	try
	{
		OleUninitialize(); //프로젝트 내 다른  COM이 초기화해 놓은 것을 죽여 놓으
		DWORD dwOleVer;

		dwOleVer = CoBuildVersion();

		// check the OLE library version
		if (rmm != HIWORD(dwOleVer))
		{
			MessageBox(NULL, _T("Incorrect version of OLE libraries."), L"Failed", MB_OK | MB_ICONSTOP);
			return;
		}

		// could also check for minor version, but this application is
		// not sensitive to the minor version of OLE

		// initialize OLE, fail application if we can't get OLE to init.
		if (FAILED(OleInitialize(NULL)))
		{
			MessageBox(NULL, _T("Cannot initialize OLE."), L"Failed", MB_OK | MB_ICONSTOP);
			return;
		}

		if (!m_app.CreateDispatch(L"Excel.Application"))
		{
			AfxMessageBox(L"Could not start Excel.");
			return;
		}
		m_app.put_DisplayAlerts(VARIANT_FALSE);
		m_app.put_UserControl(FALSE);
	}
	catch (CMemoryException* e)
	{
		CMemoryException* ep = e;
		AfxMessageBox(L"CMemoryException Could not clean up workbook.");
	}
	catch (CFileException* e)
	{
		CFileException* pe = e;
		AfxMessageBox(L"CFileException Could not clean up workbook.");
	}
	catch (CException* e)
	{
		CException* pe = e;
		AfxMessageBox(L"CException Could not clean up workbook.");
	}
}
CExcelCtrl::~CExcelCtrl()
{
	CloseFile();
	OleUninitialize();
	OleInitialize(NULL);  //프로젝트 내 다른 COM을 위한 센스
}
bool CExcelCtrl::OpenFile(CString strFilePath)
{
	m_strOpenFile.Format(L"%s", strFilePath);
	// close already-opened workbook
	CloseWorkbook();
	bool retV = false;
	try
	{
		// Get Workbooks collection.
		LPDISPATCH lpDisp;
		lpDisp = m_app.get_Workbooks();  // Get an IDispatch pointer
		ASSERT(lpDisp);
		m_books.AttachDispatch(lpDisp);  // Attach the IDispatch pointer to the books object.

		// open the document

		lpDisp = m_books.Open(m_strOpenFile.GetBuffer(m_strOpenFile.GetLength()),
			m_covOptional, m_covOptional, m_covOptional, m_covOptional,
			m_covOptional, m_covOptional, m_covOptional, m_covOptional,
			m_covOptional, m_covOptional, m_covOptional, m_covOptional,
			m_covOptional, m_covOptional);

		ASSERT(lpDisp);

		//Set CWorkbook to use lpDisp, the IDispatch* of the actual workbook.
		m_book.AttachDispatch(lpDisp);
		//WorkSheets Link.
		m_worksheets = m_book.get_Sheets();

		retV = true;
	}
	catch (CMemoryException* e)
	{
		CMemoryException* ep = e;
		AfxMessageBox(L"CMemoryException Could not clean up workbook.");
	}
	catch (CFileException* e)
	{
		CFileException* pe = e;
		AfxMessageBox(L"CFileException Could not clean up workbook.");
	}
	catch (CException* e)
	{
		CException* pe = e;
		AfxMessageBox(L"CException Could not clean up workbook.");
	}
	return retV;
}

bool CExcelCtrl::CloseFile()
{
	bool retV = false;
	CloseWorkbook();
	try
	{
		m_app.Quit();
		m_app.ReleaseDispatch();
		retV = true;
	}
	catch (CMemoryException* e)
	{
		CMemoryException* ep = e;
		AfxMessageBox(L"CMemoryException Could not clean up workbook.");
	}
	catch (CFileException* e)
	{
		CFileException* pe = e;
		AfxMessageBox(L"CFileException Could not clean up workbook.");
	}
	catch (CException* e)
	{
		CException* pe = e;
		AfxMessageBox(L"CException Could not clean up workbook.");
	}
	return retV;
}
bool CExcelCtrl::SaveFile()
{
	bool retV = false;
	if (m_app == nullptr || m_books == nullptr || m_book == nullptr)
		return retV;
	try
	{
		m_book.Save();
		retV = true;
	}
	catch (CMemoryException* e)
	{
		CMemoryException* ep = e;
		AfxMessageBox(L"CMemoryException Could not clean up workbook.");
	}
	catch (CFileException* e)
	{
		CFileException* pe = e;
		AfxMessageBox(L"CFileException Could not clean up workbook.");
	}
	catch (CException* e)
	{
		CException* pe = e;
		AfxMessageBox(L"CException Could not clean up workbook.");
	}

	return retV;
}
bool CExcelCtrl::SaveAsFile(CString newFullPath)
{
	bool retV = false;
	if (m_app == nullptr || m_books == nullptr || m_book == nullptr)
		return false;
	try
	{
		//51 = xlOpenXMLWorkbook(without macro's in 2007-2016, xlsx)
		//52 = xlOpenXMLWorkbookMacroEnabled(with or without macro's in 2007-2016, xlsm)
		//50 = xlExcel12(Excel Binary Workbook in 2007 - 2016 with or without macro's,xlsb)
		//56 = xlExcel8(97 - 2003 format in Excel 2007 - 2016, xls)
		int nPos  = newFullPath.ReverseFind(L'.');
		CString strExeName;
		strExeName.Format(L"%s", newFullPath.Mid(nPos+1));
		//strExeName.MakeUpper();
		long nFileCode = 51;
		if (strExeName.CompareNoCase(L"xlsm") == 0)
			nFileCode = 52;

		m_book.SaveAs(
			COleVariant(newFullPath.GetBuffer(newFullPath.GetLength())),
			COleVariant(nFileCode),//file format
			m_covOptional,//COleVariant(_T(""), // password
			m_covOptional,//COleVariant(_T(""), VT_BSTR), //readonly
			m_covOptional,//covFalse, 
	  //createbackup
			m_covOptional,//covFalse, 
	  //accessmode
			1,
			m_covOptional,//COleVariant((long) 1),  
			m_covOptional,
			m_covOptional,
			m_covOptional, m_covOptional);

		retV = true;
	}
	catch (CMemoryException* e)
	{
		CMemoryException* ep = e;
		AfxMessageBox(L"CMemoryException Could not clean up workbook.");
	}
	catch (CFileException* e)
	{
		CFileException* pe = e;
		AfxMessageBox(L"CFileException Could not clean up workbook.");
	}
	catch (CException* e)
	{
		CException* pe = e;
		AfxMessageBox(L"CException Could not clean up workbook.");
	}
	return retV;
}
void CExcelCtrl::CloseWorkbook()
{
	try
	{
		m_worksheets.ReleaseDispatch();
		// close already-opened workbook
		m_book.ReleaseDispatch();
		m_books.Close();
		m_books.ReleaseDispatch();
	}
	catch (CMemoryException* e)
	{
		CMemoryException* ep = e;
		AfxMessageBox(L"CMemoryException Could not clean up workbook.");
	}
	catch (CFileException* e)
	{
		CFileException* pe = e;
		AfxMessageBox(L"CFileException Could not clean up workbook.");
	}
	catch (CException* e)
	{
		CException* pe = e;
		AfxMessageBox(L"CException Could not clean up workbook.");
	}
}

CString CExcelCtrl::GetValue(int nSheet, CString strCellPos)
{
	if (nSheet < 1 || m_app == nullptr)
		return CString(L"");
	
	CString szValue;
	try
	{
		// sheet 생성, 연결 (1번 시트)
		CWorksheet sheet;
		sheet = m_worksheets.get_Item(COleVariant((short)nSheet));
		sheet.Activate();
		// range 생성, 연결
		CRange range;
		range.AttachDispatch(sheet.get_Cells(), true);

		range = sheet.get_Range(COleVariant(strCellPos.GetBuffer(strCellPos.GetAllocLength())), m_covOptional);
		range.Select();
		//------------------------------------------------------
		COleVariant vargValue = range.get_Value2();
		switch (vargValue.vt)
		{
		case VT_UI1:
		{
			unsigned char nChr = vargValue.bVal;
			//szValue = nChr;
			szValue.Format(L"%d", nChr);// = nChr;
		}
		break;
		case VT_I4:
		{
			long nVal = vargValue.lVal;
			szValue.Format(L"%i", nVal);
		}
		break;
		case VT_R4:
		{
			float fVal = vargValue.fltVal;
			szValue.Format(L"%f", fVal);
		}
		break;
		case VT_R8:
		{
			double dVal = vargValue.dblVal;
			szValue.Format(L"%f", dVal);
		}
		break;
		case VT_BSTR:
		{
			BSTR b = vargValue.bstrVal;
			szValue = b;
		}
		break;
		case VT_BYREF | VT_UI1:
		{
			//Not tested
			unsigned char* pChr = vargValue.pbVal;
			//					szValue = *pChr;
			szValue.Format(L"%f", *pChr);
		}
		break;
		case VT_BYREF | VT_BSTR:
		{
			//Not tested
			BSTR* pb = vargValue.pbstrVal;
			szValue = *pb;
		}
		case 0:
		{
			//Empty
			szValue = _T("");
		}

		break;
		}
		//------------------------------------------------------
		range.ReleaseDispatch();
		sheet.ReleaseDispatch();
	}
	catch (CMemoryException* e)
	{
		CMemoryException* ep = e;
		AfxMessageBox(L"CMemoryException Could not clean up workbook.");
	}
	catch (CFileException* e)
	{
		CFileException* pe = e;
		AfxMessageBox(L"CFileException Could not clean up workbook.");
	}
	catch (CException* e)
	{
		CException* pe = e;
		AfxMessageBox(L"CException Could not clean up workbook.");
	}
	return szValue;
}
void CExcelCtrl::SetValue(int nSheet, CString strCellPos, CString strNewValue)
{
	if (nSheet < 1 || m_app == nullptr)
		return;

	try
	{
		// sheet 생성, 연결 (1번 시트)
		CWorksheet sheet;
		sheet = m_worksheets.get_Item(COleVariant((short)nSheet));
		sheet.Activate();
		// range 생성, 연결
		CRange range;
		range.AttachDispatch(sheet.get_Cells(), true);

		range = sheet.get_Range(COleVariant(strCellPos.GetBuffer(strCellPos.GetAllocLength())), m_covOptional);
		range.Select();
		//------------------------------------------------------
		//Data 쓰기.
		range.put_Value2(COleVariant(strNewValue));
		//------------------------------------------------------
		range.ReleaseDispatch();
		sheet.ReleaseDispatch();
	}
	catch (CMemoryException* e)
	{
		CMemoryException* ep = e;
		AfxMessageBox(L"CMemoryException Could not clean up workbook.");
	}
	catch (CFileException* e)
	{
		CFileException* pe = e;
		AfxMessageBox(L"CFileException Could not clean up workbook.");
	}
	catch (CException* e)
	{
		CException* pe = e;
		AfxMessageBox(L"CException Could not clean up workbook.");
	}
}

void CExcelCtrl::SetActiveSheet(int nSheet)
{
	if (nSheet < 1 || m_app == nullptr)
		return;
	CWorksheet sheet;
	sheet = m_worksheets.get_Item(COleVariant((short)nSheet));
	sheet.Activate();
}
void CExcelCtrl::SetPasteClipboard(int nSheet, CString strCellPos,  double fViewSizeW , double fViewSizeH)
{
	if (nSheet < 1 || m_app == nullptr)
		return;
	CWorksheet sheet;
	CRange range;
	CPicture pic;
	CPictures pics;
	//CBorder border;

	sheet = m_worksheets.get_Item(COleVariant((short)nSheet));
	pics = sheet.Pictures(m_covOptional);
	sheet.Activate();
	// insert first picture and put a border on it
	range = sheet.get_Range(COleVariant(strCellPos.GetBuffer(strCellPos.GetAllocLength())), m_covOptional);
	range.Select();

	
	//링크 집어넣기
	//pic = pics.Insert(strLoadImgPath.GetBuffer(strLoadImgPath.GetLength()), covOptional);
	//붙여넣기
	sheet.Activate();
	pic = pics.Paste(m_covOptional);

	VARIANT varL = range.get_Left();
	VARIANT varT = range.get_Top();
	VARIANT varW = range.get_Width();
	VARIANT varH = range.get_Height();

	double l = varL.dblVal + 2.0;
	double t = varT.dblVal + 2.0;
	double w = varW.dblVal;
	double h = varH.dblVal;
	//Sheet 에서 위치 지정.
	pic.put_Left(l);
	pic.put_Top(t);
	pic.put_Locked(FALSE);
	//크기 지정.
	if (fViewSizeW > 0.0 )//&& fViewSizeH > 0.0)
	{
		pic.put_Width(fViewSizeW);
		//pic.put_Height(fViewSizeW);
	}
	pic.put_Visible(TRUE);

	
	//VARIANT Replace;
	//pic.Select(Replace);
	//m_book.Save();
	pic.ReleaseDispatch();
	pics.ReleaseDispatch();
	range.ReleaseDispatch();
	sheet.ReleaseDispatch();
}
void CExcelCtrl::SetPasteFileLink(int nSheet, CString strCellPos, CString strImgPath, double fViewSizeW, double fViewSizeH)
{
	if (nSheet < 1 || m_app == nullptr || strImgPath.GetLength()<3)
		return;
	CWorksheet sheet;
	CRange range;
	CPicture pic;
	CPictures pics;
	//CBorder border;

	sheet = m_worksheets.get_Item(COleVariant((short)nSheet));
	sheet.Activate();

	pics = sheet.Pictures(m_covOptional);
	// insert first picture and put a border on it
	// 링크 집어넣기
	range = sheet.get_Range(COleVariant(strCellPos.GetBuffer(strCellPos.GetAllocLength())), m_covOptional);
	range.Select();
	VARIANT varL = range.get_Left();
	VARIANT varT = range.get_Top();
	VARIANT varW = range.get_Width();
	VARIANT varH = range.get_Height();

	double l = varL.dblVal + 2.0;
	double t = varT.dblVal + 2.0;
	double w = varW.dblVal;
	double h = varH.dblVal;

	sheet.Activate();
	pic = pics.Insert(strImgPath.GetBuffer(strImgPath.GetLength()), m_covOptional);
	//붙여넣기
	//range = sheet.get_Range(COleVariant(strCellPos.GetBuffer(strCellPos.GetAllocLength())), m_covOptional);
	//range.Select();
	//pic = pics.Paste(m_covOptional);


	//Sheet 에서 위치 지정.
	pic.put_Left(l);
	pic.put_Top(t);

	//크기 지정.
	if (fViewSizeW > 0.0)//&& fViewSizeH > 0.0)
	{
		pic.put_Width(fViewSizeW);
		//pic.put_Height(fViewSizeW);
	}

	pic.ReleaseDispatch();
	pics.ReleaseDispatch();


	//m_book.Save();
	range.ReleaseDispatch();
	sheet.ReleaseDispatch();
}

void CExcelCtrl::SetFileLinkAndAdd(int nSheet, CString strCellPos, CString strImgPath, int orgW, int orgH, double fViewSizeW, double fViewSizeH)
{
	if (nSheet < 1 || m_app == nullptr || strImgPath.GetLength() < 3)
		return;
	CWorksheet sheet;
	CRange range;
	CPicture pic;
	CPictures pics;
	//CBorder border;

	sheet = m_worksheets.get_Item(COleVariant((short)nSheet));
	sheet.Activate();
	range = sheet.get_Range(COleVariant(strCellPos.GetBuffer(strCellPos.GetAllocLength())), m_covOptional);
	range.Select();
	VARIANT varL = range.get_Left();
	VARIANT varT = range.get_Top();
	VARIANT varW = range.get_Width();
	VARIANT varH = range.get_Height();

	double l = varL.dblVal + 2.0;
	double t = varT.dblVal + 2.0;
	double w = varW.dblVal;
	double h = varH.dblVal;

	CShapes  objShapes;
	CShape   objShape;
	objShapes = sheet.get_Shapes();
	objShape = objShapes.AddPicture(strImgPath, // Filename
		(long)0,    // LinkToFile
		(long)-1,	// SaveWithDocument
		(float)l,	// Left
		(float)t,   // Top
		(float)orgW,  // Width
		(float)orgH); // Height

	if (fViewSizeW > 0.0 && fViewSizeH > 0.0)
	{
		objShape.put_Width((float)fViewSizeW);
		objShape.put_Height((float)fViewSizeH);
	}
	if (objShapes.m_lpDispatch)
		objShapes.ReleaseDispatch();
	if (objShape.m_lpDispatch)
		objShape.ReleaseDispatch();

	range.ReleaseDispatch();
	sheet.ReleaseDispatch();
}

+ Recent posts