블로그 이미지
fiadot_old

칼퇴근을 위한 게임 서버 개발 방법론에 대한 심도있는 고찰 및 성찰을 위한 블로그!

Rss feed Tistory
Technical Article/펌 2007. 7. 31. 18:38

Windows Console Application 추천 사이트

Turbo C를 사용했던 개발 자라면 gotoxy가 친근할것이다.
Windows Console Application에서도 유사한 기능이 있다는걸 아시는가??

콘솔어플에 키이벤트를 날리려고 삽질하다가
발견한 사이트...

콘솔을 좀더 아름답게~~

Working with Windows Consoles
  • A multi part tutorial demostrating features of Win32 Console Applications or "DOS boxes".
  • Part 1 describes consoles
  • Part 2 naming consoles, obtaining standard handles, moving the cursor, blocks of characters and clearing the screen
  • Part 3 drawing lines, boxes and grids and hiding/modifying the cursor
  • Part 4 colour
  • Part 5 keyboard and mouse events
  • Part 6 console size issues
  • There are some more parts of this tutorial to come



    http://www.adrianxw.dk/SoftwareSite/index.html
,
Technical Article 2007. 7. 25. 23:53

[기술세미나] Matlab을 이용한 OCR(문자인식)을 위한 이미지 프로세싱

저번 창의과제에서 문자인식이 중요한 부분이였다.

인식전에 영상처리 전처리가 필요한데,

단순히 이진화, 라벨링, 분할 정도만 하면 끝인데

C++로 코딩을 하자니 귀찮고 해서..

'물론 나중에는 전부 C++로 다시 코딩했지만 ㅡㅡ;'

Matlab가지고 영상처리를 하면서 정리해놨던 문서다.



<<다운받기>>


 



 

p.s matlab help랑 네이버 opencv카페에서 정보를 많이 구했다.
,
Technical Article 2007. 7. 24. 10:41

VS2005에서 Wizard를 통해 OLEDB Consumer생성시 Stored Procedure Accessor bind 실패 원인 분석

VS2005에서 Wizard를 통해 OLEDB Consumer생성시 Stored Procedure Accessor bind 실패 원인 분석

Visual Studio 6에서는 Insert - new ATL Object - Data Access - Consumer를 통해
Stored Procedure(이하SP)에 대한 Accessor를 자동으로 생성할수 있다.
이를 통해 다음과 같은 코드를 얻게된다.


// dboSBuddyList1.H : Declaration of the CdboSBuddyList1 class

#ifndef __DBOSBUDDYLIST1_H_
#define __DBOSBUDDYLIST1_H_

class CdboSBuddyList1Accessor
{
public:
 LONG m_RETURNVALUE;
 TCHAR m_userid[13];
 BYTE m_usertype;
 TCHAR m_coluserid[13];
 BYTE m_colusertype;
 TCHAR m_colnick[13];
 BYTE m_collev;
 TCHAR m_colcomment[61];

BEGIN_PARAM_MAP(CdboSBuddyList1Accessor)
 SET_PARAM_TYPE(DBPARAMIO_OUTPUT)
 COLUMN_ENTRY(1, m_RETURNVALUE)
 SET_PARAM_TYPE(DBPARAMIO_INPUT)
 COLUMN_ENTRY(2, m_userid)
 COLUMN_ENTRY(3, m_usertype)
END_PARAM_MAP()

BEGIN_COLUMN_MAP(CdboSBuddyList1Accessor)
 COLUMN_ENTRY(1, m_coluserid)
 COLUMN_ENTRY(2, m_colusertype)
 COLUMN_ENTRY(3, m_colnick)
 COLUMN_ENTRY(4, m_collev)
 COLUMN_ENTRY(5, m_colcomment)
END_COLUMN_MAP()

DEFINE_COMMAND(CdboSBuddyList1Accessor, _T("{ ? = CALL dbo.S_BuddyList;1 (?,?) }"))

 // You may wish to call this function if you are inserting a record and wish to
 // initialize all the fields, if you are not going to explicitly set all of them.
 void ClearRecord()
 {
  memset(this, 0, sizeof(*this));
 }
};

class CdboSBuddyList1 : public CCommand<CAccessor<CdboSBuddyList1Accessor> >
{
public:
 HRESULT Open()
 {
  HRESULT  hr;

  hr = OpenDataSource();
  if (FAILED(hr))
   return hr;

  return OpenRowset();
 }
 HRESULT OpenDataSource()
 {
  HRESULT  hr;
  CDataSource db;
  CDBPropSet dbinit(DBPROPSET_DBINIT);

  dbinit.AddProperty(DBPROP_AUTH_PASSWORD, OLESTR("wing_access"));
  dbinit.AddProperty(DBPROP_AUTH_USERID, OLESTR("xxxxx"));
  dbinit.AddProperty(DBPROP_INIT_CATALOG, OLESTR("xxxxx"));
  dbinit.AddProperty(DBPROP_INIT_DATASOURCE, OLESTR("xx.xx.xx.xx"));
  dbinit.AddProperty(DBPROP_INIT_LCID, (long)1042);
  dbinit.AddProperty(DBPROP_INIT_PROMPT, (short)4);
  hr = db.Open(_T("SQLOLEDB.1"), &dbinit);
  if (FAILED(hr))
   return hr;

  return m_session.Open(db);
 }
 HRESULT OpenRowset()
 {
  return CCommand<CAccessor<CdboSBuddyList1Accessor> >::Open(m_session);
 }
 CSession m_session;
};

#endif // __DBOSBUDDYLIST1_H_


이를 사용 하는 방법은

#include "dboSBuddyList1.H"
#define DB_STRING_FIELD_COPY(dest, src)  _tcsncpy(dest, src, sizeof(dest))


void CDBTT2Dlg::OnButton1()
{
 // TODO: Add your control notification handler code here
 
 CdboSBuddyList1 rs;
 HRESULT hr;

 DB_STRING_FIELD_COPY(rs.m_userid,  _T("lovydayz"));
 rs.m_usertype = 0;

 hr = rs.Open();

 hr = rs.MoveFirst();

 rs.Close();

}



이런식이다. 아이디와 타입을 SP의 인자로 넘기고 레코드셋을 받아오는 SP이다.


VS2005에서는 추가-클래스-ATL OLEDB 소비자 를 통해서 생성하는데
SP에 대해서는  insert, delete, update옵션이 적용되지 않으면 Accessor인지, Table인지
설정하는 옵션이 disable되고 파일을 생성해준다.


class CS_BuddyListAccessor
{
public:

 // 다음 마법사 생성 데이터 멤버에는  열 맵의 해당
 // 필드에 대한 상태 값이 들어 있습니다. 이 값을
 // 사용하여 데이터베이스에서반환하는 NULL 값을
 // 보유하거나 컴파일러에서 오류를 반환할 때
 // 오류 정보를 보유할 수 있습니다. 이러한 필드 사용에
 // 대한 자세한 내용은 Visual C++ 설명서의
 //  "마법사 생성 접근자"에서 "필드 상태 데이터 멤버"를 참조하십시오.
 // 참고: 데이터를 설정/삽입하기 전에 이들 필드를 초기화해야 합니다.

 DBSTATUS m_dwuserid1Status;
 DBSTATUS m_dwusertype1Status;
 DBSTATUS m_dwnickStatus;
 DBSTATUS m_dwlevStatus;
 DBSTATUS m_dwcommentStatus;

 // 다음 마법사 생성 데이터 멤버에는 열 맵의 해당 필드에 대한
 // 길이 값이 들어 있습니다.
 // 참고: 가변 길이 열의 경우 데이터를 설정/삽입하기 전에
 //       이러한 필드를 초기화해야 합니다.

 DBLENGTH m_dwuserid1Length;
 DBLENGTH m_dwusertype1Length;
 DBLENGTH m_dwnickLength;
 DBLENGTH m_dwlevLength;
 DBLENGTH m_dwcommentLength;


 TCHAR m_userid1[13];
 BYTE m_usertype1;
 TCHAR m_nick[13];
 BYTE m_lev;
 TCHAR m_comment[61];

 // 인자들은 리턴되는 레코드셋보다 상단에 있어야 한다!!! - 이근호 070724
 LONG m_RETURN_VALUE;
 TCHAR m_userid[13];
 BYTE m_usertype;


 void GetRowsetProperties(CDBPropSet* pPropSet)
 {
  pPropSet->AddProperty(DBPROP_CANFETCHBACKWARDS, true, DBPROPOPTIONS_OPTIONAL);
  pPropSet->AddProperty(DBPROP_CANSCROLLBACKWARDS, true, DBPROPOPTIONS_OPTIONAL);
  pPropSet->AddProperty(DBPROP_UPDATABILITY, DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_INSERT | DBPROPVAL_UP_DELETE);
 }

 HRESULT OpenDataSource()
 {
  CDataSource _db;
  HRESULT hr;
// #error Security Issue: The connection string may contain a password
// 아래 연결 문자열에 일반 텍스트 암호 및/또는
// 다른 중요한 정보가 포함되어 있을 수 있습니다.
// 보안 관련 문제가 있는지 연결 문자열을 검토한 후에 #error을(를) 제거하십시오.
// 다른 형식으로 암호를 저장하거나 다른 사용자 인증을 사용하십시오.
  hr = _db.OpenFromInitializationString(L"Provider=SQLOLEDB.1;Password=xxxxx;Persist Security Info=True;User ID=xxxxx;Initial Catalog=xxxx;Data Source=xx.xx.xx.xx;Use Procedure for Prepare=1;Auto Translate=True;Packet Size=4096;Workstation ID=LEEGUNHO;Use Encryption for Data=False;Tag with column collation when possible=False");
  if (FAILED(hr))
  {
#ifdef _DEBUG
   AtlTraceErrorRecords(hr);
#endif
   return hr;
  }
  return m_session.Open(_db);
 }

 void CloseDataSource()
 {
  m_session.Close();
 }

 operator const CSession&()
 {
  return m_session;
 }

 CSession m_session;

 // 일부 공급자와 관련된 몇몇 문제점을 해결하기 위해 아래 코드에서는
 // 공급자가 보고하는 것과 다른 순서로 열을 바인딩할 수 있습니다.

 BEGIN_COLUMN_MAP(CS_BuddyListAccessor)
  COLUMN_ENTRY_LENGTH_STATUS(1, m_userid1, m_dwuserid1Length, m_dwuserid1Status)
  COLUMN_ENTRY_LENGTH_STATUS(2, m_usertype1, m_dwusertype1Length, m_dwusertype1Status)
  COLUMN_ENTRY_LENGTH_STATUS(3, m_nick, m_dwnickLength, m_dwnickStatus)
  COLUMN_ENTRY_LENGTH_STATUS(4, m_lev, m_dwlevLength, m_dwlevStatus)
  COLUMN_ENTRY_LENGTH_STATUS(5, m_comment, m_dwcommentLength, m_dwcommentStatus)
 END_COLUMN_MAP()

 BEGIN_PARAM_MAP(CS_BuddyListAccessor)
  SET_PARAM_TYPE(DBPARAMIO_OUTPUT)
  COLUMN_ENTRY(1, m_RETURN_VALUE)
  SET_PARAM_TYPE(DBPARAMIO_INPUT)
  COLUMN_ENTRY(2, m_userid)
//  SET_PARAM_TYPE(DBPARAMIO_INPUT)
  COLUMN_ENTRY(3, m_usertype)
 END_PARAM_MAP()

 DEFINE_COMMAND_EX(CS_BuddyListAccessor, L"{ ? = CALL dbo.S_BuddyList;1 (?,?) }")

};

class CS_BuddyList : public CCommand<CAccessor<CS_BuddyListAccessor> >
{
public:
 HRESULT OpenAll()
 {
  HRESULT hr;
  hr = OpenDataSource();
  if (FAILED(hr))
   return hr;
  __if_exists(GetRowsetProperties)
  {
   CDBPropSet propset(DBPROPSET_ROWSET);
   __if_exists(HasBookmark)
   {
    if( HasBookmark() )
     propset.AddProperty(DBPROP_IRowsetLocate, true);
   }
   GetRowsetProperties(&propset);
   return OpenRowset(&propset);
  }
  __if_not_exists(GetRowsetProperties)
  {
   __if_exists(HasBookmark)
   {
    if( HasBookmark() )
    {
     CDBPropSet propset(DBPROPSET_ROWSET);
     propset.AddProperty(DBPROP_IRowsetLocate, true);
     return OpenRowset(&propset);
    }
   }
  }
  return OpenRowset();
 }

 HRESULT OpenRowset(DBPROPSET *pPropSet = NULL)
 {
  HRESULT hr = Open(m_session, NULL, pPropSet);
#ifdef _DEBUG
  if(FAILED(hr))
   AtlTraceErrorRecords(hr);
#endif
  return hr;
 }

 void CloseAll()
 {
  Close();
  ReleaseCommand();
  CloseDataSource();
 }
};


 

이와 같이 생성된 코드를 테스트 해보면 결과값을 얻어오지 못함을 알수 있다.

Bind부분에서 ATLASSERT(m_pAccessor != NULL) 에서 걸린다.


왜 바인딩을 못하는것인가??

Wizard page를 통해 생성한 코드가 제대로 실행이 안된다는것은 말이 안된다는 가정하에
문제에 접근해 보았다. ATL코드를 죽 훑어보며 DynamicAccssor를 사용하니 문제없이 되었다.
그렇다면 문제는 ATL코드 자체에 있거나 생성한 코드에 있다는 2가지 결론에 도달할수 있었다.

VS6에서 생성한 코드와 비교하며 매크로의 차이, 멤버변수의 차이, 메소드의 차이 등에 대해서
비교를 해보았다.
DEFINE_COMMAND가 DEFINE_COMMAND_EX로 변경되고 CALL시에 SP이름뒤에 ;가 붙는다는것 이외에는 별 문제가 없었다. 결국 binding시의 변수 순서에 문제가 있는것으로 생각하고,
몇번의 삽질을 통해 SP의 인자로 들어가는 멤버변수는 결과 레코드셋이 담기는 변수들 위에
위치해야 된다는 결과를 얻게 되었다.

거의 3일동안 삽질하다가 오늘도 안되면 그냥 DynamicAccessor를 이용해서 돌아가려고 했는데,
다행히 문제가 해결됐다 ^^;

,
Technical Article 2007. 7. 14. 15:29

VS2005에 추가된 키워드 for each

STL을 사용하다 전체 노드에 대해 모두 어떠한 함수를 적용해야 할때

for_each란 generic algorithm을 사용하게 된다.

그런데 이 부분이 좀 문제가 있는게 함수를 쓰던지 클래스를 새로 생성해서

operator()를 구현해줘야 한다.

심플하게 끝내자고 해놓은 것이 복잡도만 높이고 있는 형국이다.

이를 타계하기 위해서는 2가지 방법이 있다.

첫번째는 for_each에 대해 적용될 함수셋을 구현해놓는방법.

http://levites.pe.kr/tt/index.php?pl=20 

여기에 잘나와있던데 좀 불편하다.

두번째는 Visual Studio 2005에 추가된 키워드인 for each를 사용하는 방법이다.


class CBroadCast
{
public:
 CBroadCast(CPacket &refSendPkt) : m_refSendPkt(refSendPkt), m_nSendCnt(0)
 {
 
 }

 void operator()(CFiaSession* pNode)
 {
  pNode->SendPacket(m_refSendPkt);
  m_nSendCnt++;
 }


 CPacket &m_refSendPkt;
 int  m_nSendCnt;
};


 

int  CRoom::BroadCasting( CFiaSession *pSession, CPacket &refSendPkt)
{
..
CBroadCast bc(refSendPkt);
bc += for_each(m_vecUser.begin(), m_vecUser.end(), bc);
..
}


이런 형태로 STL for_each를 사용 했다면,

 int nCnt = 0;
 for each(CFiaSession* it in m_vecUser)
 {
  it->SendPacket(refSendPkt);
  nCnt +=1;
 }

2005에서는 이렇게 for each를 사용하면 된다.


일반적으로 iterator를 이용해서 순회하면서 for each의 형태로 구성 해서 사용했다.

하지만, OS종속적이며 퍼포먼스를 지향하는 서버 어플리케이션에서

OS호환성은 고려대상의 범위에서 벗어나기에, for each로 구현을 했다.


지은이햄의 테스트 결과로 "for_each보다 for each가 퍼포먼스 면에서도 우수했다"고 한다. ^^

코드면에서도 깔끔하고 성능도 나으니 안쓸이유가 없네..

,
Technical Article 2007. 7. 9. 11:53

NateON dispatch Interface를 통한 친구상태 체크하기

#import "progid:NateOn.NateMessengerApi.1" no_namespace
void CAutoTestDlg::OnBnClickedButton1()
{
 // TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.

//  uuid(A02AC169-B150-43DE-8BD4-109B9DE6B34B),
//
//  INateOnApiAtx
//
//  dispinterface INateMessengerApi
//
//  [id(0x0000000c), helpstring("method GetMyId")]
//  BSTR GetMyId();
 
 INateMessengerApiPtr m_pNate;

 m_pNate = INateMessengerApiPtr(__uuidof(NateMessengerApi));

 BSTR pID = m_pNate->GetMyId();

 TCHAR szFinal[255];
 // direct conversion from BSTR to LPCTSTR only works
 // in Unicode
 _stprintf(szFinal, _T("%s"), (LPCTSTR)pID);
 AfxMessageBox(szFinal);

 CString str;

VARIANT_BOOL bOnline = m_pNate->IsBuddyOnline("dlsdoㅌㅌㅌ@nate.com");
 if ( VARIANT_TRUE  == bOnline )
  str.Format(L"true");
 else
  str.Format(L"false");

 AfxMessageBox(str);


COM 공부하다가 뻘짓 -_-;;;

OLE View로 타입라이브러리 보다가 '참 많은 놈들이 COM으로 짰구나' 생각하다

아니 네이트~~ 이러면서 그냥 테스트 해본거..

물론 ATL은 필수!
,
Technical Article/펌 2007. 7. 1. 00:38

CxImage 메소드 요약

- Cximage api에 대해 잘 정리해 놓은것 퍼옴.^^
http://katalog.egloos.com/tb/2626276


출처 : http://hogwarts.tistory.com/tag/CxImage 

,
Technical Article/펌 2007. 6. 12. 09:08

MFC 헤더와 라이브러리 설명 (The Foundation Classes Headers and Libraries)

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력해주세요.

Technical Article 2007. 5. 12. 00:18

[기술세미나] How to use OLEDB using ATL

invalid-file

ATL을 이용해서 OLEDB를 쉽고 편하게 사용하는 방법에 관한 기술세미나



기술공유에 대한 의지보다 발표 능력 향상과 내가 보유한 기술에 대한 정리의 목적이 더 크다.

나눔으로써 얻게되는게 많다는 말이 와닿는 ... ^^


2002년인가 2003년부터 OLEDB에 관심을 갖기시작해서

인터페이스를 접하고 msdn보면서 하나하나 구축해보다

ATL로 사용하면서 그 편의성을 확실히 깨닿고 나서

시간이 지나서 더 까먹기 전에

기초만이라도 정리해놓자는 생각으로 만든 PPT...


아무래도 중고급 기술은 빠져있어서

많은 사람들에게 도움이 될지는 모르겠지만

어쨌든

OLEDB + ATL의 조합은 환상적 +_+


,
Hardware 2007. 5. 5. 11:11

jINa 완성기념 스샷~

학교에서 3월 30일날 발표하고 그때 찍어둔 사진들이

보고서 작성하면서 발견되서 이렇게 올려본다.

Home Robot
Free moveable robot
Avoiding wall and other things.
Detecting gas leak in your home
To give a person warning of the gas leak.

뭐 이런 구질구질한 수식어는 집어치우고

다양한 각도에서 찍은 동영상...에서 캡쳐한것들 ^^;

01234567891011


한 3달동안 띄엄띄엄 작업하면서 가장 크게 느낀점은...

HW는 아무나 하는게 아니구나 -_-;; 으하하

멤버쉽의 많은 사람들이 도와줬다.

민걸이햄, 성하햄, 깡, 완회씨.. 외에도

모두모두 캄사~ (__)


사용자 삽입 이미지

허접하게 나마 OrCAD로 만든 schematic도 첨부해본다..

,
Technical Article 2007. 4. 13. 14:44

유영창님 세미나에서 들었던것...

(1) 엔지니어는 "충신"이 아닌 "간신"이 되어라..

(여기서 충신이란 리더가 원하는 방향에 대해 안된다고만 얘기를 하는 사람이고, 간신은 안된다는 걸 알지만 리더가 원하는 바를 알고그에 대해 조언을 해 줄수 있는 사람을 뜻합니다.)

(2) 팀장이 악랄(?)할 수록 그 프로젝트는 성공한다..

- 팀장이 사람이 좋으면 프로젝트 중에는 편할지 몰라도 그 프로젝트는 성공할 수 없습니다.

(3) 모르는 것에 대해 솔직해 져라..

- 회사에서 자신이 모르는 분야에 대해서 최선을 다해 보겠다고 얘기하면, 관리자는 그것이 될것이라는 확신을 가지고 일을 진행하게 됩니다. 따라서 모르는 것은 모른다고 얘기하는것이 관리자의 판단 미스를 줄일수 있는 바른 방법이겠죠.....

(4) 요즘은 know how 가 아니라 know who 나 know where 입니다.

- 그만큼 우리가 접할수 있는 지식의 양이 많아 졌다는 것이겠죠... 또 인맥이 가장 큰 재산이라는...^^;;

(5) 능력있는 사람이 바쁘다..

- 바쁜 사람은 바쁘지만 그 일을 해냅니다.. 사람들은 해낸다는 믿음이 있는 능력있는 사람에게만 일을 맡기기 원합니다.. 회사에서 한사람이 바쁘다면 그 사람이 능력 있는 사람 입니다..

(6) 개발자는 항상 바쁘다..

- 안 바쁜 개발자 없죠?? ^^;;;

(7) 문서는 자신보다 남을 위해서 써라.

(8) 제품을 개발할때 필요한 설계서 중 가장 먼저 나와야 할 것이 사용자 메뉴얼이다...

- 왜 그럴까요???

(9) 프로젝트의 진행에는 Visual 이 중요하다..

(10) Don't worry !!

- 프로젝트가 2년 짜리면 사람들은 2년동안 걱정하고(잘하려고..), 프로젝트가 6개월 짜리면 사람들은 6개월 만큼 걱정한다... 고로 차이가 없다.. -_-;;;

,
TOTAL TODAY