기본적으로 .net과 C# 기반이면서,

  1. 하나의 인스턴스만을 허용하고
  2. (추가)실행시 포커스를 가져가지 않는 어플리케이션 개발!
    창이 위로 뜨거나 작업표시줄이 번쩍거려서는 곤란하다.

메신저나 팝업 알림창 뭐 이런 용도로 필요할 듯하다. 내 경우 선거방송과 관련해서 백그라운드로 데이터를 업데이트해주는 유틸을 개발하기 위해 필요했다. 백그라운드로 뜬다지만 UI를 없앨 수는 없고, 번쩍대지 않고 뒤에 조용히 떠있으면 되는 그런 유틸이다.

이것은 쉬워 보이지만 막상 해보면 어렵다.
1의 single-instance app이란 것은 여러 가지 솔루션들이 나와 있고 그 중에 명령줄인수를 받을 수 있는 것으로는 visual basic으로부터 WindowsFormsApplicationBase를 가져다 쓰는 방법이 가장 쉽다.
코드프로젝트에 설명이 잘 돼있으면서 데모프로젝트까지 제공하고 있는 포스트가 있다.
http://www.codeproject.com/KB/cs/CSSIApp.aspx

2의포커스를 훔쳐가지 않기, 즉 "without activation" 이것도 쉽다.
Form의 ShowWithoutActivation 속성을 true로 설정하면 된다. read-only이기 때문에 다음과 같이 재정의하면 된다.

  protected override bool ShowWithoutActivation
  {
   get { return true; }
  }

그러나, 실제로 해보면 작동하지 않는다.
ShowWithoutActivation은 분명히 true로 설정되어 있음을 form 생성 후에도 확인할 수 있지만, 매번 실행시마다 창은 작업중이던 다른 창 위로 뜨고 포커스도 빼앗겼다.
어쩌다 창이 위로 뜨지 않는 경우도 생겼지만, 어쨌든 태스크바는 대화를 원하는 메신저 창처럼 마구 번쩍인다.

두 개의 서로 다른 문제에 대해서 각각 솔루션들은 넘쳐나지만 둘 다를 해결해주는 방법은 없었다. 시계는 어느새 11시 30분을 넘기고... 이제는 포기하고 싶은 마음 생길 때 쯤에 울리는 전화벨 소리~ 는 아니고 뭔가를 보았다.

그것은 visual basic 응용 프로그램 모델 개요라는 MSDN 아티클을 보고 있을 때였다. 내용은 이런 것이었다.
Visual Basic 응용 프로그램 모델을 사용하면 단일 인스턴스 응용 프로그램을 쉽게 만들 수 있습니다. 단일 인스턴스 응용 프로그램은 응용 프로그램 인스턴스를 한 번에 하나씩만 실행할 수 있다는 점에서 일반 응용 프로그램과 다릅니다. 단일 인스턴스 응용 프로그램에서 다른 인스턴스를 추가로 시작하려고 하면 원래 실행 중이던 인스턴스는 StartupNextInstance 이벤트를 통해 다른 시작이 시도되었다는 알림을 받게 됩니다. 이 알림에는 후속 인스턴스의 명령줄 인수가 포함됩니다. 그러면 응용 프로그램의 후속 인스턴스는 초기화가 실행되기 전에 닫힙니다.

단일 인스턴스 응용 프로그램은 시작될 때 자신이 응용 프로그램의 첫 번째 인스턴스인지 후속 인스턴스인지 확인합니다.

  • 첫 번째 인스턴스이면 정상적으로 시작됩니다.

  • 첫 번째 인스턴스가 실행되고 있는 동안 응용 프로그램을 시작하려는 시도가 이루어지면 그때마다 결과 동작은 매우 달라집니다. 후속 시도는 첫 번째 인스턴스에 명령줄 인수에 대해 알린 다음 즉시 종료됩니다. 첫 번째 인스턴스는 StartupNextInstance 이벤트를 처리하여 후속 인스턴스의 명령줄 인수가 무엇인지 확인한 다음 계속 실행됩니다.

    이 다이어그램은 후속 인스턴스에서 첫 번째 인스턴스에 신호하는 방법을 보여 줍니다.

StartupNextInstance 이벤트를 처리하여 단일 인스턴스 응용 프로그램이 동작하는 방식을 제어할 수 있습니다. 예를 들어, Microsoft Outlook은 일반적으로 단일 인스턴스 응용 프로그램으로 실행됩니다. Outlook이 실행되고 있을 때 Outlook을 다시 시작하려고 하면 포커스가 원래 인스턴스로 변경되고 다른 인스턴스는 열리지 않습니다.

음... 그런 것인가.
첫번째 인스턴스는 Startup, 그 다음부터는 StartupNextInstance 이벤트가 발생한다.
음 그래 StartupNextInstance... (이미 의식이 혼미한 상태)
전에는 기본 형식의 메서드를 더블클릭하면 자동으로 오버라이드가 됐던 것 같은데 왜 안 되는거야...
visual studio의 개체 브라우저를 하염없이 클릭만 하고 있다가...

헉!

"응용프로그램 인스턴스를 포그라운드로 가져와야 하는지"

저 구절이 눈에 번쩍 하고 띄었다.
그렇다... 이거 한 줄만 StartupNextInstance 이벤트 핸들러에 추가하면 된다.
eventArgs.BringToForeground = false;

원래부터 WindowsFormsApplicationBase에서는 지원하고 있었던 거였다. 이렇게 허무할 데가... 오늘 검색한 페이지만 해도 수백 개는 될텐데 ㅜㅜ
그렇지만 어쨌든 오늘 내로 해결해서 다행이라고 생각하는 양고였습니다.

OpenCV에서 예외 처리

개발과 트러블슈팅 2010. 4. 20. 18:54 Posted by 양고
다음과 같이 하면 된다:

  try
  {
   cvCopy( iObj, correspond );    // 예외의 소지가 있는 부분
  }
  catch(cv::Exception& e)
  {
   cout << e.err;
  }

좀비 콘솔 창

개발과 트러블슈팅 2010. 4. 9. 09:32 Posted by 양고
요즘 콘솔 어플리케이션 디버그하다 보면 콘솔 창이 죽지 않고 좀비로 남는 경우가 발생한다. 무슨 짓을 해도 안 죽는다.
더 무서운 것은 이 콘솔 창들이 남아 있으면 윈도 종료도 안 된다. ㄷㄷ

원인은 윈도 업데이트 KB978037과 윈도 프로세스 CSRSS인 것으로 보이나, 해당 업데이트를 삭제하는 것 외에 별다른 해결책은 아직 없는 것 같다.
http://social.msdn.microsoft.com/Forums/en/vsdebug/thread/f7c82383-b6dc-4572-975a-b45683775fa1

과감하게 삭제하면 ㅇㅋ

Rendering to OpenCV window

개발과 트러블슈팅 2010. 4. 5. 11:11 Posted by 양고

문제
OpenGL로 실시간으로 렌더링한 그림을 OpenCV에서 사용하고자 한다.
그러나 일반적으로 사용되는 GLUT은 OpenCV와 마찬가지로 윈도우나 메시지 처리를 위한 자체 프레임워크를 가지고 있어서, OpenCV와 함께 사용하는 것이 어렵다.
따라서 OpenCV에서 제공하는(cvNamedWindow) 윈도우에 OpenGL 렌더링이 가능한 방법을 찾게 되었다.

해결방향
우선 이 글을 참조하기 바란다.
OpenGL in a PROPER Windows APP (NO GLUT!!)
Nehe의 Lesson01도 비슷한 성격이지만, 위 링크가 더 자세한 설명을 제공한다.
렌더링 과정을 요약하면 이렇다. OpenGL drawing → HGLRC → HDC → application window.
이렇게 하려면 Window Class(WC)를 윈도우즈에 등록하고 직접 CreateWindow 해야한다. 그러나 이 방법은 기본적으로 Win32 응용프로그램 환경을 가정하고 있어서, 콘솔 프로그램이면서 윈도 생성 등은 HighGUI로 따로 빼 놓은 OpenCV에서 사용하기는 힘들다.

결론
OpenCV에서 HDC를 얻어서 HGLRC와 연결해 주면 된다. 예제에서는 "RENDERED"라는 이름의 창에 그린다.
다음과 같이 설정한 후, OpenGL에서 drawing해보자.

HINSTANCE hinstance = GetModuleHandle(NULL);
HWND hwnd = (HWND)cvGetWindowHandle("RENDERED");
HDC hdc = GetDC(hwnd);

PIXELFORMATDESCRIPTOR pfd = {0};
pfd.nSize = sizeof( PIXELFORMATDESCRIPTOR );
pfd.nVersion = 1;
pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 32;
int chosenPixelFormat = ChoosePixelFormat(hdc, &pfd);
if( chosenPixelFormat == 0 )
FatalAppExit( NULL, TEXT("ChoosePixelFormat() failed!") );
printf("You got ID# %d as your pixelformat!\n", chosenPixelFormat);
if(SetPixelFormat(hdc, chosenPixelFormat, &pfd) == NULL)
FatalAppExit( NULL, TEXT("SetPixelFormat() failed!") );

HGLRC hglrc = wglCreateContext(hdc);

wglMakeCurrent(hdc, hglrc);


OpenCV 윈도우에서는 그려짐과 동시에 사라지는데, 이는 HighGUI의 redraw 메커니즘 때문일 것이다.
내용을 유지하고 싶다면, OpenGL drawing 직후 color buffer 내용을 읽어오면 된다.
예제에서는 "image"로 읽어와서 "MODEL" 윈도우에 표시한다.

glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, image->imageData);
GLenum ge = glGetError();
printf("GL Error: %X\n", ge);
cvShowImage("MODEL", image);



주의사항
OpenCV는 BGR 순서로 저장되기 때문에 R과 G가 바뀐다. 위아래도 바뀐다.
나중에 골치아파질 부분이다...
 
추가
화면에 보이는 OpenCV 윈도의 DC를 사용할 경우, 겹쳐진 다른 윈도 등이 해당 DC 위에 그려짐으로써 GL 렌더링 외에 다른 것들이 렌더링 컨텍스트에 함께 그려져 버린다. 이는 윈도를 minimize해도 마찬가지.
이런 문제를 피하기 위해서는 결국 off-screen rendering을 해야 한다. 간단하게 설명한다.
console application이지만 window class를 등록하고 CreateWindow - 아래 코드 참조.
그런 다음 얻어진 HDC를 가지고 HGLRC와 연결.
내 경우 그렇게 해도 잘 안 됐는데, PixelFormatDescriptor에서 PFD_DOUBLEBUFFER를 disable했기 때문으로 밝혀졌다. 반드시 enable해주자.

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
 return DefWindowProc (hwnd, iMsg, wParam, lParam) ;
}
HWND hwndConsole = NULL;
HWND CreateOffscreenWindow()
{
 const char szClassName[] = "myWindowClass";
 WNDCLASSEX wc;
 hwndConsole = GetConsoleWindow();
 HINSTANCE hinstance = (HINSTANCE)GetWindowLong(hwndConsole, GWL_HINSTANCE);
//Step 1: Registering the Window Class
 wc.cbSize        = sizeof(WNDCLASSEX);
 wc.style         = 0;
 wc.lpfnWndProc   = WndProc; //(WNDPROC)GetWindowLongPtr(hwndConsole, GWLP_WNDPROC); // WndProc;
 wc.cbClsExtra    = 0;
 wc.cbWndExtra    = 0;
 wc.hInstance     = hinstance; //(HINSTANCE)GetWindowLong(hwndConsole, GWL_HINSTANCE); //hInstance;
 wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
 wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName  = NULL;
 wc.lpszClassName = szClassName;
 wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);
 if(!RegisterClassEx(&wc))   
 {
  MessageBox(NULL, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
  return 0;
 }
// Step 2: Creating the Window
 HWND hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, szClassName, "The title of my window", WS_OVERLAPPEDWINDOW,
  CW_USEDEFAULT, CW_USEDEFAULT, width, height, NULL, NULL, hinstance, NULL);
 if(hwnd == NULL)
 {
  MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
  return 0;
 }
// ShowWindow(hwnd, SW_SHOW); //nCmdShow);
// UpdateWindow(hwnd);
 return hwnd;
}
노트북에서 언젠가부터 웹상의 pdf를 클릭하면 IE 내에 표시하다가 IE까지 왕창 죽어버리는, very×3 annoying한 증상이 나타났다.

구글 뒤져보니 거의 IE로 pdf를 열려면 어떻게 하는가?에 대한 포스팅들이 많더라만...
도대체 왜? IE 안에 pdf를 열어보려는지 이해가 안 간다. 따로 Adobe Acrobat이나 Reader에서 열면 쓸데없이 IE 프레임 안에다 띄우는 것보다 공간도 절약되고 훨씬 안정적인데 말이지.

어쨌든 IE가 pdf를 손 못 대게 하려면,
IE > Tools > Internet Options > Programs > Manage Add-Ons 에서 다음과 같이 Acrobat OCX 3총사를 죽...이지는 못하고 불구로 만들자.


<추가>
위 dll들을 disable하니 처음 한 번은 pdf가 offline으로 Acrobat에서 잘 열렸다. 그러나...
그 다음부터는 다시 IE가 열어대는 악몽이 재현되는 것이다! ㅜㅜ

결국 Acrobat (Reader에서는 어떨지 모르겠다) 의 옵션을 수정함으로써 문제는 해결되었다...
편집 > 기본 설정 > 인터넷에서 다음과 같이 모조리 언체크했다.


저 아름다운 pdf 다운로드 창을 보라... 속이 다 시원하다.
그나저나 논문 좀 보려던 내 오후 시간은 이 삽질로 인해 날아갔네... 어흑

Decklink SDK installed

개발과 트러블슈팅 2010. 2. 3. 21:36 Posted by 양고
dxtrans.h 문제 외에는 잘 넘어간다.
histogram 예제가 있길래 돌려봤더니, 한 프레임 당 5~10초는 걸리는 듯. 히스토그램 계산 자체는 빠르지만 프리뷰가 느린 것 같다.


...
Now what?

(추가)
OpenCV보다 Decklink SDK가 빠른 것처럼 보였던 이유는,
Decklink capture sample은 samplegrabber를 사용하지 않기 때문인 것으로 결론.
즉 samplegrabber를 거치면 실시간 HD 처리는 불가능한 것으로... ㅜㅜ

OpenCV로 HD 캡처...

개발과 트러블슈팅 2010. 2. 3. 20:24 Posted by 양고
결국 본질적인 문제는,

 CvCapture* cap = cvCreateCameraCapture(CV_CAP_DSHOW + 1);

이거였다.
힌트: http://www.conv2.com/spboard/board.cgi?id=opencv_qna&action=view&gul=330-1&page=1&go_cnt=4
내 PC에 dshow device 0번은 TV수신카드라서;

전에는 저 +1을 해도 잘 안 됐는데...
잘 되는 지금 상황을 일단 정리하자면, 캡처 전에 체크할 사항은 다음과 같다:
1. 카메라 출력 (HD SDI or SD SDI)
2. Decklink 보드 설정 (아래 그림)
3. CV_CAP_DSHOW + index


캡처 속도는,
HD 캡처는 70ms = 14fps (cvQueryFrame에 overhead 때문인듯)
SD 캡처는 33ms = 30fps

<2010.4.14 추가>
DeckLink 기본 제공 소프트웨어인 Media Express에서 SD 전환이 안 될 경우,
graphedit에서 캡처필터 속성을 NTSC로 다시 한 번 설정해주자.




다들 솔루션이 atlbase.h를 편집하여 다음 라인을 주석 처리하라는 것인데,
내 atlbase.h에는 그런 라인이 없다. -ㅜ

#pragma comment(lib, "atlthunk.lib")

결국 별 쓸 데 없는 파일인 것 같은데, 무시하면 된다. ㅡㅡ


다음 사이트로부터 무단 전제:
http://social.msdn.microsoft.com/forums/en-US/windowssdk/thread/ed097d2c-3d68-4f48-8448-277eaaf68252/

Answerdxtrans.h missing in Microsoft DirectX SDK (November 2007)...

  • Sunday, November 02, 2008 4:28 PMkenc34 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
  •  Proposed Answer

    Very helpful!  With one more line you can get by without editing qedit.h.

     

    #pragma include_alias( "dxtrans.h", "qedit.h" )

    #define __IDxtCompositor_INTERFACE_DEFINED__

    #define __IDxtAlphaSetter_INTERFACE_DEFINED__

    #define __IDxtJpeg_INTERFACE_DEFINED__

    #define __IDxtKey_INTERFACE_DEFINED__

    #include <qedit.h>


1>MSVCRTD.lib(MSVCR90D.dll) : error LNK2005: _free이(가) LIBCMTD.lib(dbgfree.obj)에 이미 정의되어 있습니다.
1>MSVCRTD.lib(MSVCR90D.dll) : error LNK2005: __finite이(가) LIBCMTD.lib(_ieeemisc_.obj)에 이미 정의되어 있습니다.
1>MSVCRTD.lib(MSVCR90D.dll) : error LNK2005: _malloc이(가) LIBCMTD.lib(dbgmalloc.obj)에 이미 정의되어 있습니다.
1>MSVCRTD.lib(MSVCR90D.dll) : error LNK2005: ___iob_func이(가) LIBCMTD.lib(_file.obj)에 이미 정의되어 있습니다.
1>MSVCRTD.lib(MSVCR90D.dll) : error LNK2005: _exit이(가) LIBCMTD.lib(crt0dat.obj)에 이미 정의되어 있습니다.
1>MSVCRTD.lib(ti_inst.obj) : error LNK2005: "private: __thiscall type_info::type_info(class type_info const &)" (??0type_info@@AAE@ABV0@@Z)이(가) LIBCMTD.lib(typinfo.obj)에 이미 정의되어 있습니다.
1>MSVCRTD.lib(ti_inst.obj) : error LNK2005: "private: class type_info & __thiscall type_info::operator=(class type_info const &)" (??4type_info@@AAEAAV0@ABV0@@Z)이(가) LIBCMTD.lib(typinfo.obj)에 이미 정의되어 있습니다.
1>LINK : warning LNK4098: 'MSVCRTD' defaultlib가 다른 라이브러리와 충돌합니다. /NODEFAULTLIB:library를 사용하십시오.

디버그와 릴리스버전이 충돌해 발생하는 에러라는데...
해결책은 프로젝트 속성 → 구성속성 → C/C++ → 코드생성 → 런타임라이브러리 → Multithreaded Debug DLL (/MDd)를 선택하는 것이다.
프로젝트와 다른 라이브러리는 디버그 모드인데 런타임 라이브러리가 일반(릴리스) 모드라 발생하는 문제인 듯.
근데 프로젝트 설정을 디버그로 선택하면 자동으로 /MDd가 선택돼야 하는 것 아님? 매번 생기는 의문...