원격 디버깅으로 테스트 하다가

실행 못한다고 나오길레..

당연히 c-runtime dll들을 복사 해주면 될 줄 알았더니..

안되었음..

 

검색질 해보니

vs2008 sp1에서 manifest versions 가 업데이트 안되서

Microsoft.VC90.DebugCRT.manifest을 수정하면 된다고 함.

 

version="9.0.30729.4148"을 version="9.0.21022.8"으로 변경..

 

잘 됨.. -_-;

 

vs2008이 옛날꺼 되었어도 좀 고쳐라 MS..

 

http://stackoverflow.com/questions/3515450/installing-ms-debug-dlls-for-remote-debugging

 

참고..

- 원격 디버깅 서버 프로그램 경로

C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\Remote Debugger\msvsmon.exe

 

- DLL경로

C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\redist

Posted by 셈말짓기 :


static const WORD MAX_CONSOLE_LINES = 500;

#include <fcntl.h>
#include <io.h>
#include <iostream>
#include <fstream>

void RedirectIOToConsole()
{
 int hConHandle;
 long lStdHandle;

 CONSOLE_SCREEN_BUFFER_INFO coninfo;

 FILE *fp;

 // allocate a console for this app

 AllocConsole();

 // set the screen buffer to be big enough to let us scroll text
 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);

 coninfo.dwSize.Y = MAX_CONSOLE_LINES;
 SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);

 // redirect unbuffered STDOUT to the console
 lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE);
 hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
 fp = _fdopen( hConHandle, "w" );
 *stdout = *fp;
 setvbuf( stdout, NULL, _IONBF, 0 );

 // redirect unbuffered STDIN to the console
 lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE);
 hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
 fp = _fdopen( hConHandle, "r" );
 *stdin = *fp;
 setvbuf( stdin, NULL, _IONBF, 0 );

 // redirect unbuffered STDERR to the console
 lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE);
 hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
 fp = _fdopen( hConHandle, "w" );
 *stderr = *fp;
 setvbuf( stderr, NULL, _IONBF, 0 );

 // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog
 // point to console as well
 std::ios::sync_with_stdio();
}

Posted by 셈말짓기 :

Windows Sleep(1)은 1 msec을 안 놀아주고 약 10 msec를 놀아 준다.
그래서 대충 1 msec 놀겠금 구현한 함수....
하지만, 태스크 메니저보면 cpu점유을은 100%으로 보이긴 하나 괜춚다!
어차피 열나게 컨텍스트 스위칭 할테니...

extern "C" int delay (unsigned int time)

{

        if (time<10 && time!=0)

        {

               LARGE_INTEGER start;

               LARGE_INTEGER end;

               LARGE_INTEGER frequency;

               LARGE_INTEGER differance;

 

               long double   duration;

       

               QueryPerformanceFrequency(&frequency);

               QueryPerformanceCounter  (&start);

               while (1)

               {

                       Sleep (0); // or SwitchToThread();

 

                       QueryPerformanceCounter (&end);

       

                       differance.QuadPart = end.QuadPart - start.QuadPart;

                       duration            = (long double)(differance.QuadPart*1000/frequency.QuadPart);

 

                       if (time <= duration)

                       {

                              break;

                       }

               }
        }

        else

        {

               Sleep (time);

        }

       

        return 0;

}

 

Posted by 셈말짓기 :

EXCEL EXPORT

2010. 10. 27. 16:23 from 셈말짓기/Windows

 

/////////////////////////////////////////////////////////////////////////////

//===========================================================================

#import "C:\\Program Files\\Common Files\\Microsoft Shared\\OFFICE12\\MSO.DLL" \

        rename( "RGB", "MSORGB" ) \

        rename( "DocumentProperties","MSODocumentProperties" )

//using namespace Office;

 

#import "C:\\Program Files\\Common Files\\Microsoft Shared\\VBA\\VBA6\\VBE6EXT.OLB"

//using namespace VBIDE;

 

#import "C:\\Program Files\\Microsoft Office\\OFFICE12\\EXCEL.EXE" \

        rename( "DialogBox", "ExcelDialogBox" ) \

        rename( "RGB", "ExcelRGB" ) \

        rename( "CopyFile", "ExcelCopyFile" ) \

        rename( "ReplaceText", "ExcelReplaceText" ) \

        exclude("IFont") \

        exclude("IPicture")

 

/////////////////////////////////////////////////////////////////////////////

//===========================================================================

#include <string>

#include <cx/StringUtility.h>

 

/////////////////////////////////////////////////////////////////////////////

//===========================================================================

void Export_Excel_1 (void)

{

        std::string target_filepath_a = "D:\\a.xlsx";

 

 

        _bstr_t    target_filepath;

        _variant_t cell_item_value;

 

 

        target_filepath = cx::string_to_wstring( target_filepath_a ).c_str();

        cell_item_value = _bstr_t(L"2:2=Export_Excel_1");

 

 

        Excel::_ApplicationPtr pApplication;

        Excel::_WorkbookPtr    pWorkbook;

        Excel::_WorksheetPtr   pWorksheet;

       

        pApplication.CreateInstance    ( _T("Excel.Application") );

        pApplication->PutDisplayAlerts ( 0, VARIANT_FALSE );

        pApplication->Workbooks->Add   ( _variant_t ( Excel::xlWBATWorksheet ) );

        /*Excel::XlWBATemplate::xlWBATWorksheet*/

 

        pWorkbook  = pApplication->Workbooks->Item [1];

        pWorksheet = pWorkbook->Sheets->Item[1];

 

        pWorksheet->Cells->Item[2][2] = cell_item_value;

        pWorksheet->Cells->Item[2][3] = cell_item_value;

        pWorksheet->Cells->Item[2][4] = cell_item_value;

 

        pWorksheet->SaveAs ( target_filepath );

       

        pWorkbook->Close ( VARIANT_FALSE );

 

        pApplication->Quit ();

}

 

//===========================================================================

void Export_Excel_2 (void)

{

        std::string source_filepath_a = "D:\\a.xlsx";

        std::string target_filepath_a = "D:\\b.xlsx";

 

        _bstr_t    source_filepath;

        _bstr_t    target_filepath;

        _variant_t cell_item_value;

        _variant_t option ((long)DISP_E_PARAMNOTFOUND, VT_ERROR);

 

        source_filepath = cx::string_to_wstring( source_filepath_a ).c_str();

        target_filepath = cx::string_to_wstring( target_filepath_a ).c_str();

        cell_item_value = _bstr_t(L"3:2=Expor_tExcel_2");

 

 

        Excel::_ApplicationPtr pApplication;

        Excel::_WorkbookPtr    pWorkbook;

        Excel::_WorksheetPtr   pWorksheet;

 

 

        pApplication.CreateInstance( _T("Excel.Application") );

        pApplication->PutDisplayAlerts ( 0, VARIANT_FALSE );

 

        pWorkbook  = pApplication->Workbooks->Open( source_filepath,

                     option, option, option, option, option,

                     option, option, option, option, option, option, option );

        pWorksheet = pWorkbook->Sheets->Item[ 1 ];

 

        pWorksheet->Name = L"Export_Excel_2";

        pWorksheet->Cells->Item[3][2] = cell_item_value;

        pWorksheet->Cells->Item[3][3] = cell_item_value;

        pWorksheet->Cells->Item[3][4] = cell_item_value;

 

        pWorksheet->Cells->Item[4][2] = cell_item_value;

        pWorksheet->Cells->Item[4][3] = cell_item_value;

        pWorksheet->Cells->Item[4][4] = cell_item_value;

 

#if 1 // overwrite

        pWorkbook->Close ( VARIANT_TRUE );

#else

        pWorksheet->SaveAs ( target_filepath );

 

        pWorkbook->Close ( VARIANT_FALSE );

#endif

 

        pApplication->Quit ();

}

 

Posted by 셈말짓기 :

class CTFMForm : public CDialogImpl<CTFMForm>
{
public:
 enum { IDD = IDD_TFM };

 BOOL PreTranslateMessage(MSG* pMsg)
 {
  return CWindow::IsDialogMessage(pMsg);
 }

 BEGIN_MSG_MAP(CTFMForm)
  MESSAGE_HANDLER      (WM_INITDIALOG, OnInitDialog)
  MESSAGE_HANDLER      (WM_DESTROY,    OnDestroy   )
 END_MSG_MAP()

public:
 LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
 {
  return 0;
 }

 LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
 {
  bHandled = FALSE;
  return 0;
 }
};

#include <atlscrl.h>
class CTFMView : public CScrollWindowImpl<CTFMView>
{
public:
 DECLARE_WND_CLASS(NULL)

 BOOL PreTranslateMessage(MSG* pMsg)
 {
  pMsg;
  return FALSE;
 }

 void DoPaint(CDCHandle dc)
 {
  //TODO: Add your drawing code here
 }

 BEGIN_MSG_MAP(CTFMView)
  MESSAGE_HANDLER (WM_CREATE,  OnCreate )
  MESSAGE_HANDLER (WM_DESTROY, OnDestroy)
  MESSAGE_HANDLER (WM_SIZE,    OnSize   )
  CHAIN_MSG_MAP   (CScrollWindowImpl<CTFMView>)
 END_MSG_MAP()

public:
 CTFMForm m_Form;
 CSize    m_FormSize;

public:
 LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
 {
  m_Form.Create(m_hWnd);
  
  CRect rc;
  m_Form.GetClientRect (&rc);
  m_FormSize.cx = rc.Width();
  m_FormSize.cy = rc.Height(); 
  
  SetScrollSize(m_FormSize.cx, m_FormSize.cy);

  bHandled = FALSE;
  return 0;
 }

 LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
 {
  bHandled = FALSE;

  return 0;
 }

 LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
 {
  CSize size;
  CSize newsize;

  size.cx = GET_X_LPARAM(lParam);
  size.cy = GET_Y_LPARAM(lParam);

  if (::IsWindow (m_Form))
  {
   if (size.cx>m_FormSize.cx)
   {
    newsize.cx = size.cx;
   }
   else
   {
    newsize.cx = m_FormSize.cx;
   }

   if (size.cy>m_FormSize.cy)
   {
    newsize.cy = size.cy;
   }
   else
   {
    newsize.cy = m_FormSize.cy;
   }

   m_Form.SetWindowPos (0,0,0,newsize.cx,newsize.cy,SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);

  }

  bHandled = FALSE;

  return 0;
 }
};

Posted by 셈말짓기 :

/////////////////////////////////////////////////////////////////////////////
//
// in MainFrame.H
// m_hWndClient = m_view.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, WS_EX_CLIENTEDGE);
//
/////////////////////////////////////////////////////////////////////////////

class C_WTLWINVIEW_View : public CWindowImpl<C_WTLWINVIEW_View>
{
public:
 DECLARE_WND_CLASS(NULL)

 BOOL PreTranslateMessage(MSG* pMsg)
 {
  pMsg;
  return FALSE;
 }

 BEGIN_MSG_MAP(C_WTLWINVIEW_View)
  MESSAGE_HANDLER(WM_PAINT, OnPaint)
 END_MSG_MAP()

// Handler prototypes (uncomment arguments if needed):
// LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
// LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
// LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)

 LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
 {
  CPaintDC dc(m_hWnd);

  //TODO: Add your drawing code here

  return 0;
 }
};

/////////////////////////////////////////////////////////////////////////////
//
// in MainFrame.H
// m_hWndClient = m_view.Create(m_hWnd);
//
/////////////////////////////////////////////////////////////////////////////
#include <atlscrl.h>
class C_WTLFORMVIEW_View : public CDialogImpl<C_WTLFORMVIEW_View>
{
public:
 enum { IDD = IDD_TEMPVIEW_FORM };

 BOOL PreTranslateMessage(MSG* pMsg)
 {
  return CWindow::IsDialogMessage(pMsg);
 }

 BEGIN_MSG_MAP(C_WTLFORMVIEW_View)
 END_MSG_MAP()
};


/////////////////////////////////////////////////////////////////////////////
//
// m_hWndClient = m_view.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_HSCROLL | WS_VSCROLL, WS_EX_CLIENTEDGE);
// // replace with appropriate values for the app
// m_view.SetScrollSize(2000, 1000);
/////////////////////////////////////////////////////////////////////////////
class C_WTLSCROLLVIEW_View : public CScrollWindowImpl<C_WTLSCROLLVIEW_View>
{
public:
 DECLARE_WND_CLASS(NULL)

 BOOL PreTranslateMessage(MSG* pMsg)
 {
  pMsg;
  return FALSE;
 }

 void DoPaint(CDCHandle dc)
 {
  //TODO: Add your drawing code here
 }

 BEGIN_MSG_MAP(C_WTLSCROLLVIEW_View)
  CHAIN_MSG_MAP(CScrollWindowImpl<C_WTLSCROLLVIEW_View>)
 END_MSG_MAP()
};

Posted by 셈말짓기 :

#pragma comment(linker, "/entry:WinMainCRTStartup /subsystem:console")
Posted by 셈말짓기 :

GetRemovableDrives()

2009. 11. 27. 14:09 from 셈말짓기/Windows


 void GetRemovableDrives (std::vector<std::wstring>& logicalDrives)
 {
  TCHAR  buf[512];
  TCHAR* rootPathName = buf;
  BOOL   hasVolumeInfo;
  UINT   driveType;


  if (0==GetLogicalDriveStrings (512-1, buf))
   return;

  do
  {
   driveType     = GetDriveType (rootPathName);
   hasVolumeInfo = GetVolumeInformation (rootPathName,
              NULL, 0,
              NULL, NULL, NULL,
              NULL, 0);
   if (driveType==DRIVE_REMOVABLE && hasVolumeInfo==TRUE)
   {
    logicalDrives.push_back (std::wstring (rootPathName) );
   }
   while (*rootPathName++);
  } while (*rootPathName);
 }

Posted by 셈말짓기 :


HINSTANCE CreateInstanceFromDll(LPCTSTR lpDllName, REFCLSID rclsid, REFIID riid, LPVOID * ppv)
{
 (*ppv) = NULL;

 HINSTANCE hDll = LoadLibrary( lpDllName );
 if ( NULL == hDll )
 {
  return NULL;
 }

 typedef HRESULT (__stdcall *GETCLASS_PROC)(REFCLSID,REFIID,LPVOID*);

 GETCLASS_PROC procGetClassObject = (GETCLASS_PROC)GetProcAddress( hDll, "DllGetClassObject" );

 if( procGetClassObject )
 {
  IClassFactory* pFactory = NULL;

  HRESULT hr = procGetClassObject(rclsid, IID_IClassFactory, (void**)&pFactory);
  if( pFactory )
  {
   hr = pFactory->CreateInstance( NULL, riid, ppv);

   pFactory->Release();
   pFactory = NULL;

   if( NULL == *ppv )
   {
    FreeLibrary( hDll );
    return NULL;
   }
  }
  else
  {
   FreeLibrary( hDll );
   return NULL;
  }
 }
 else
 {
  FreeLibrary( hDll );
  return NULL;
 }

 return hDll;
}

Posted by 셈말짓기 :

// wf1.aspx.cs
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

using System.Drawing;
using System.Drawing.Imaging;

public partial class wf1 : System.Web.UI.Page
{
    private const int    IMAGE_WIDTH  = 320;
    private const int    IMAGE_HEIGHT = 240;
    private const string IMAGE_FORMAT = "image/gif";

    private Bitmap     _bitmap;
    private Graphics   _graphics;
    private Font       _font      = new Font ("굴림", 8);
    private SolidBrush _fontBrush = new SolidBrush(Color.Black);
    private SolidBrush _fillBrush = new SolidBrush(Color.Yellow);
    private string     _label     = "테스트";

    protected void Page_Load(object sender, EventArgs e)
    {
        _bitmap = new Bitmap(IMAGE_WIDTH, IMAGE_HEIGHT, PixelFormat.Format32bppArgb);

        _graphics = Graphics.FromImage(_bitmap);

        _graphics.FillRectangle(_fillBrush, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
        _graphics.DrawString   (_label, _font, _fontBrush, 10, 10);

        Response.ContentType = IMAGE_FORMAT;
        _bitmap.Save(Response.OutputStream, ImageFormat.Gif);
    }
}

Posted by 셈말짓기 :




wince에서는 CreateRoundRectRgn()함수가 지원이 안되서 구글 힘을 빌려 만들어 봤습니다. 원본소스는 
http://www.ocera.org/archive/upvlc/public/components/sa-rtl/sa-rtl-2.2-pre2/mw/mwin/winrgn.c
에 있는 일부분을 참고해서 만들었습니다.

 
// TestCEGraphView.h : interface of the CTestCEGraphView class
//
/////////////////////////////////////////////////////////////////////////////

#pragma once

#include <vector>

HRGN CreateRoundRectRgn (int left, int top, int right, int bottom, int ellipse_width, int ellipse_height )
{
 HRGN              hrgn = 0;
 int               asq, bsq, d, xd, yd;
 RECT              rect;
 std::vector<RECT> rects;

 if (ellipse_width == 0 || ellipse_height == 0)
  return CreateRectRgn( left, top, right, bottom );

 /* Make the dimensions sensible */
 if (left > right ) { int tmp = left; left = right;  right  = tmp; }
 if (top  > bottom) { int tmp = top;  top  = bottom; bottom = tmp; }

 ellipse_width  = abs(ellipse_width);
 ellipse_height = abs(ellipse_height);

 /* Check parameters */
 if (ellipse_width  > right-left) ellipse_width  = right-left;
 if (ellipse_height > bottom-top) ellipse_height = bottom-top;

 /* Ellipse algorithm, based on an article by K. Porter */
 /* in DDJ Graphics Programming Column, 8/89 */
 asq = ellipse_width  * ellipse_width  / 4; /* a^2 */
 bsq = ellipse_height * ellipse_height / 4; /* b^2 */
 if (asq == 0) asq = 1;
 if (bsq == 0) bsq = 1;
 d  = bsq - asq * ellipse_height / 2 + asq / 4; /* b^2 - a^2b + a^2/4 */
 xd = 0;
 yd = asq * ellipse_height;                     /* 2a^2b */

 rect.left   = left + ellipse_width  / 2;
 rect.right  = right - ellipse_width / 2;

 rects.reserve (ellipse_height);

 /* Loop to draw first half of quadrant */
 while (xd < yd)
 {
  /* if nearest pixel is toward the center */
  if (d > 0) 
  {
   /* move toward center */
   rect.top    = top++;
   rect.bottom = rect.top + 1;
   rects.push_back (rect);

   rect.top    = --bottom;
   rect.bottom = rect.top + 1;
   rects.push_back (rect);

   yd -= 2*asq;
   d  -= yd;
  }
  /* next horiz point */
  rect.left --;       
  rect.right++;
  xd += 2*bsq;
  d  += bsq + xd;
 }

 /* Loop to draw second half of quadrant */
 d += (3 * (asq-bsq) / 2 - (xd+yd)) / 2;
 while (yd >= 0)
 {
  /* next vertical point */
  rect.top    = top++;
  rect.bottom = rect.top + 1;
  rects.push_back (rect);

  rect.top    = --bottom;
  rect.bottom = rect.top + 1;
  rects.push_back (rect);

  /* if nearest pixel is outside ellipse */
  if (d < 0)  
  {
   /* move away from center */
   rect.left --;    
   rect.right++;
   xd += 2*bsq;
   d  += xd;
  }
  yd -= 2*asq;
  d  += asq - yd;
 }

 /* Add the inside rectangle */
 if (top <= bottom)
 {
  rect.top    = top;
  rect.bottom = bottom;
  //rects.push_back (rect);
  rects.insert (rects.begin(), rect);
 }
 
 static int count=0;
 std::vector<RECT>::iterator i;
 for (i=rects.begin(); i!=rects.end(); i++)
 {
  ATLTRACE (_T("[%d]%3d,%3d:%3d,%3d \r\n"), ++count,
   (*i).top,
   (*i).bottom,
   (*i).left,
   (*i).right
   );
 }
 if (rects.empty())
  return NULL;

 RGNDATAHEADER* pRgnData;
 UINT           RgnDataSize;
 UINT           RgnRectCount;
 LPRECT         pRect;

 RgnRectCount = rects.size();
 RgnDataSize  = sizeof(RGNDATAHEADER) + sizeof(RECT)*RgnRectCount;
 pRgnData     = (RGNDATAHEADER*)new BYTE[ RgnDataSize ];
 if (pRgnData==NULL)
  return NULL;

 pRgnData->dwSize         = sizeof(RGNDATAHEADER);
 pRgnData->iType          = RDH_RECTANGLES;
 pRgnData->nCount         = RgnRectCount;
 pRgnData->rcBound.left   = 0;
 pRgnData->rcBound.top    = 0;
 pRgnData->rcBound.right  = 0;
 pRgnData->rcBound.bottom = 0;

 pRect = (LPRECT) ( (LPBYTE) pRgnData + sizeof(RGNDATAHEADER) );

 memcpy (pRect, &*rects.begin(), RgnRectCount*sizeof(RECT));

 hrgn = ExtCreateRegion(NULL, RgnDataSize, (LPRGNDATA)pRgnData);

 delete pRgnData;

 return hrgn;
}

class CTestCEGraphView : public CWindowImpl<CTestCEGraphView>
{
public:
 DECLARE_WND_CLASS(NULL)

 BOOL PreTranslateMessage(MSG* pMsg)
 {
  pMsg;
  return FALSE;
 }

 BEGIN_MSG_MAP(CTestCEGraphView)
  MESSAGE_HANDLER(WM_PAINT, OnPaint)
 END_MSG_MAP()

// Handler prototypes (uncomment arguments if needed):
// LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
// LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
// LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
 
 LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
 { 
  CPaintDC dc(m_hWnd);
  CBrush brush[3];

  brush[0].CreateSolidBrush (RGB(0xff,0x00,0x00));
  brush[1].CreateSolidBrush (RGB(0x00,0xff,0x00));
  brush[2].CreateSolidBrush (RGB(0x00,0x00,0xff));
  
  HRGN hrgn;
  
  hrgn = CreateRoundRectRgn (10,10,200,100,200,200);
  dc.FillRgn (hrgn , brush[0]);
  DeleteObject (hrgn);

  hrgn = CreateRoundRectRgn (10,150,200,250,20,50);
  dc.FillRgn (hrgn , brush[1]);
  DeleteObject (hrgn);

  hrgn = CreateRoundRectRgn (10,300,200,400,20,20);
  dc.FillRgn (hrgn , brush[2]);
  DeleteObject (hrgn);

  return 0;
 }
};

Posted by 셈말짓기 :
[0000 0000 ~ 0000 03ff] WM_NULL, WM_CREATE, ...   : Messages reserved for use by the system.
[0000 0400 ~ 0000 07ff] WM_USER ~ WM_USER+0x03ff : Integer messages for use by private window classes.
[0000 0800 ~ 0000 bfff] WM_APP  ~ WM_APP +0x03ff : Messages available for use by applications
[0000 c000 ~ 0000 ffff] RegisterWindowMessage()  : String messages for use by applications.
[0001 0000 ~ ffff ffff] Reserved by the system.



WM_USER
WM_APP 
WM_reg 
WM_sys 

Posted by 셈말짓기 :

PostThreadMessage()를 이용한 쓰레드에 메세지 전송

● 알아두어야 할 사항
1. 윈도우 OS시스템에서는 자동적으로(GetMessage()호출시?) 메세지 큐를 각각 쓰레드마다 생성한다.
2. Posted Message를 위한 메세지 큐의 크기는 Windows 2000이나 XP인경우
   10000이다. (최소 값: 4000) 이 값은 아래 윈도우즈 레지스트리에
   HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Windows/
     USERPostMessageLimit
   정의 한다.
3. PostThreadMessage()로 보내어지는 메세지는 윈도우와 관련이 없다.


● 결론
1. 간단한 메세지만 전송받아 처리 하는 쓰레드인 경우는 큐만든다고 삽질하지 말자.
2. 기본에 충실하자.
3. 옛날에 삽질한게 억울하다.

// --------------------------------------------------------------------------
//  예제
// --------------------------------------------------------------------------
CAppModule _Module;

DWORD WINAPI BackgroundThread (LPVOID param)
{
 MSG msg;

 while (GetMessage(&msg, NULL, 0, 0))
 {
  ATLTRACE (_T("hwnd    = %x \r\n"),    msg.hwnd    );
  ATLTRACE (_T("message = %x \r\n"),    msg.message );
  ATLTRACE (_T("wParam  = %x \r\n"),    msg.wParam  );
  ATLTRACE (_T("lParam  = %x \r\n"),    msg.lParam  );
  ATLTRACE (_T("time    = %d \r\n"),    msg.time    );
  ATLTRACE (_T("pt      = %d %d \r\n"), msg.pt.x, msg.pt.y);
  ATLTRACE (_T("\r\n"));

  Sleep (1000);

  while (::PeekMessage (&msg, NULL, WM_USER, WM_USER+5, PM_REMOVE));
 }

 ATLTRACE (_T("BackgroundThread(): End \r\n"));

 return msg.wParam;
}

int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWNORMAL)
{
 CMessageLoop theLoop;
 _Module.AddMessageLoop(&theLoop);

 CMainFrame wndMain;

 DWORD  dwThreadId  = 0;
 HANDLE hThread     = CreateThread (NULL, 0, BackgroundThread, NULL, 0, &dwThreadId);
 wndMain.m_ThreadId = dwThreadId;

 if(wndMain.CreateEx() == NULL)
 {
  ATLTRACE(_T("Main window creation failed!\n"));
  return 0;
 }
 
 wndMain.ShowWindow(nCmdShow);

 int nRet = theLoop.Run();

 _Module.RemoveMessageLoop();

 WaitForSingleObject (hThread, INFINITE);
 CloseHandle (hThread);

 return nRet;
}
// --------------------------------------------------------------------------

LRESULT CMainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
 ...
 SetTimer (1, 10);

 return 0;
}

LRESULT CMainFrame::OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
 bHandled = FALSE;
 KillTimer (1);
 PostThreadMessage (m_ThreadId, WM_QUIT, 0, 0);

 return 0;
}

LRESULT CMainFrame::OnTimer (UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
 static int i = 0;

 PostThreadMessage (m_ThreadId, WM_USER+(++i%5), 1, 2);

 return 0;
}
// --------------------------------------------------------------------------
// 출력결과
// --------------------------------------------------------------------------
hwnd    = 0
message = 403
wParam  = 1
lParam  = 2
time    = 73702525
pt      = 0 0

hwnd    = 0
message = 400
wParam  = 1
lParam  = 2
time    = 73703559
pt      = 0 0

hwnd    = 0
message = 400
wParam  = 1
lParam  = 2
time    = 73704571
pt      = 0 0

hwnd    = 0
message = 403
wParam  = 1
lParam  = 2
time    = 73705596
pt      = 0 0

hwnd    = 0
message = 403
wParam  = 1
lParam  = 2
time    = 73706642
pt      = 0 0

hwnd    = 0
message = 400
wParam  = 1
lParam  = 2
time    = 73707702
pt      = 0 0

hwnd    = 0
message = 403
wParam  = 1
lParam  = 2
time    = 73708749
pt      = 0 0

hwnd    = 0
message = 400
wParam  = 1
lParam  = 2
time    = 73709776
pt      = 0 0

CMessageLoop::Run - exiting
BackgroundThread(): End
'BackgroundThread' (0x8706cf42) 스레드가 0 (0x0) 코드에서 끝났습니다.
모듈 언로드: commctrl.dll
모듈 언로드: oleaut32.dll
모듈 언로드: ole32.dll
모듈 언로드: rpcrt4.dll
모듈 언로드: lpcrt.dll
'[6702ec62] Test.exe' 프로그램이 1 (0x1) 코드에서 끝났습니다.

 

 

Posted by 셈말짓기 :

 typedef struct _PRIORITY_LEVEL
 {
  int   priority;
  TCHAR name[32];
 } PRIORITY_LEVEL;

 PRIORITY_LEVEL Priority_Levels[] =
 {
  { THREAD_PRIORITY_TIME_CRITICAL , _T("THREAD_PRIORITY_TIME_CRITICAL") },
  { THREAD_PRIORITY_HIGHEST       , _T("THREAD_PRIORITY_HIGHEST      ") },
  { THREAD_PRIORITY_ABOVE_NORMAL  , _T("THREAD_PRIORITY_ABOVE_NORMAL ") },
  { THREAD_PRIORITY_NORMAL        , _T("THREAD_PRIORITY_NORMAL       ") },
  { THREAD_PRIORITY_BELOW_NORMAL  , _T("THREAD_PRIORITY_BELOW_NORMAL ") },
  { THREAD_PRIORITY_LOWEST        , _T("THREAD_PRIORITY_LOWEST       ") },
  { THREAD_PRIORITY_ABOVE_IDLE    , _T("THREAD_PRIORITY_ABOVE_IDLE   ") },
  { THREAD_PRIORITY_IDLE          , _T("THREAD_PRIORITY_IDLE         ") }
 };
 HANDLE Current_Thread = GetCurrentThread();
 int    Current_Priority;
 int    i;

 for (i=0; i<sizeof(Priority_Levels)/sizeof(PRIORITY_LEVEL); i++)
 {
  SetThreadPriority (Current_Thread, Priority_Levels[i].priority);
  Current_Priority = CeGetThreadPriority (Current_Thread);
 
  ATLTRACE (_T("SetThreadPriority(%d:%s) => CeGetThreadPriority()=%d \r\n"),
  Priority_Levels[i].priority,
  Priority_Levels[i].name,
  Current_Priority);

 }
---------------------------------------------------------------------------------------------- SetThreadPriority(0:THREAD_PRIORITY_TIME_CRITICAL) => CeGetThreadPriority()=248
 SetThreadPriority(1:THREAD_PRIORITY_HIGHEST      ) => CeGetThreadPriority()=249
 SetThreadPriority(2:THREAD_PRIORITY_ABOVE_NORMAL ) => CeGetThreadPriority()=250
 SetThreadPriority(3:THREAD_PRIORITY_NORMAL       ) => CeGetThreadPriority()=251
 SetThreadPriority(4:THREAD_PRIORITY_BELOW_NORMAL ) => CeGetThreadPriority()=252
 SetThreadPriority(5:THREAD_PRIORITY_LOWEST       ) => CeGetThreadPriority()=253
 SetThreadPriority(6:THREAD_PRIORITY_ABOVE_IDLE   ) => CeGetThreadPriority()=254
 SetThreadPriority(7:THREAD_PRIORITY_IDLE         ) => CeGetThreadPriority()=255

Posted by 셈말짓기 :


# WinCE -> PC : 192.168.55.100를 이용하여 접속
  PC    = 192.168.55.100
  WinCE = 192.168.55.101

# PC -> WinCE : 127.0.0.1을 이용하여 접속
  1. ActiveSync Proxy 설정
     1) PC의 레지스트리
         HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows CE Services\ProxyPorts에
         DWORD값 설정후 적당한 이름을 붙인후 Port번호 기입

------------------------------------------------------------------------------------
 Test.Reg
------------------------------------------------------------------------------------
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows CE Services\ProxyPorts]
"Test"=dword:000007d0
------------------------------------------------------------------------------------

원본:
http://leigh.innori.com/2

Posted by 셈말짓기 :

Take 1.

void Sleep4uSec (long double usec)
{
 LARGE_INTEGER start;
 LARGE_INTEGER end;
 LARGE_INTEGER frequency;

 LARGE_INTEGER differance;
 //LARGE_INTEGER duration;
 long double   duration;

 QueryPerformanceFrequency(&frequency);
 QueryPerformanceCounter  (&start);
 for (;;)
 {
  QueryPerformanceCounter (&end);
  differance.QuadPart = end.QuadPart-start.QuadPart;
  duration            = (long double)(differance.QuadPart*1000000/frequency.QuadPart);
  if (usec < duration)
  {
   //RETAILMSG (1, (L"%f \r\n", duration));
   ATLTRACE (L"%f \r\n", duration);
   return;
  }
 }
}



Take 2.

__inline double large_integer_div (LARGE_INTEGER a, const double b)
{
 // See the derivation above in operator/ (const ACE_UINT32). 
 return ((double) 0xffffffffu - b + 1.0) / b * a.HighPart  +  (double) a.HighPart  +  (double) a.LowPart / b;
}

__inline LARGE_INTEGER large_integer_sub (LARGE_INTEGER a, LARGE_INTEGER b)
{
 LARGE_INTEGER ret;

 unsigned __int64 * tmpa = (unsigned __int64 *)&a;
 unsigned __int64 * tmpb = (unsigned __int64 *)&b;
 unsigned __int64 * tmpc = (unsigned __int64 *)&ret;

 //if ((__int64) (*tmpa - *tmpb) < (__int64) 0)

 if( b.HighPart  > a.HighPart ? 1 : b.HighPart < a.HighPart  ? 0 : b.LowPart  > a.LowPart)
 {
  //*tmpc = (unsigned __int64) ~((unsigned __int64) (*tmpa - *tmpb));

  *tmpc = *tmpa - *tmpb;
  //*tmpc = (unsigned __int64) ~(*tmpc);
  *tmpc = 0xffffffffffffffff - *tmpc;

  //ret.HighPart = ~ret.HighPart;
  //ret.LowPart  = ~ret.LowPart;

  // ret.HighPart = ~(a.HighPart - b.HighPart);
  // ret.LowPart = ~(a.LowPart - b.LowPart);
 }
 else
 {
  *tmpc = *tmpa - *tmpb;
 }

 /*
 ret.LowPart = a.LowPart - b.LowPart;
 ret.HighPart = a.HighPart - b.HighPart;

 if (a.LowPart < b.LowPart)
 --ret.HighPart;
 */

 return ret;
}


DWORD ThreadProc (LPVOID param)
{
 DWORD  dwObject;
 HANDLE hEvent;

    LARGE_INTEGER   currcount;
    LARGE_INTEGER   frequency;
    int             prev_usec;
    int             curr_usec;
    int             diff_usec;


 hEvent = CreateEvent (NULL, FALSE, FALSE, L"uSec_Timer_Event");

 prev_usec = 0;
 curr_usec = 0;
 diff_usec = 0;

    QueryPerformanceCounter   (&currcount);
    QueryPerformanceFrequency (&frequency);

#pragma warning (push)
#pragma warning (disable: 4244) // conversion from 'double' to 'int', possible loss of data
    prev_usec = large_integer_div (currcount, large_integer_div( frequency, (double)1000000));
#pragma warning (pop)

    for(;;)
    {
        if ((dwObject=WaitForSingleObject(hEvent, INFINITE))== WAIT_OBJECT_0)
        {
            QueryPerformanceCounter(&currcount);
            // QueryPerformanceFrequency(&frequency);

#pragma warning (push)
#pragma warning (disable: 4244) // conversion from 'double' to 'int', possible loss of data
            curr_usec = large_integer_div (currcount, large_integer_div( frequency, (double)1000000));
#pragma warning (pop)
   diff_usec = (prev_usec > curr_usec) ? diff_usec = ~(curr_usec - prev_usec) : diff_usec = curr_usec - prev_usec;
            prev_usec = curr_usec;

            if (diff_usec > 1000) // 1000 usec
            {
    // ...
            }
        }
  else
  {
   break;
  }
    }

 if (hEvent)
  CloseHandle (hEvent);

    return 0;
}


 

Posted by 셈말짓기 :

2004. 02. 19

WebService C++ SoapClient

by code1009@empal.com


Win32 / WinCE.net / Pocket PC Platform 환경에서 C++ Soap Client를 작성하여 WebService를 호출하는 방법을 소개합니다.





목차

  1. 머릿말
  2. WebService 작성
  3. Client의 WebService 호출
  4. Win32 Soap Client 작성
  5. WinCE.net Soap Client 작성
  6. PocketPC Soap Client 작성



머릿말

프로젝트 중에서 서버에 있는 자원을 다양한 클라이언트 플랫폼에서 쉽게 이용할 수 있는 방법을 찾던 중에 웹서비스를 이용하면 될 것 같아서 찾아본 내용을 정리하여 올리는 것입니다.

물론 .net CF를 이용하여 임베디드 시스템에서 웹서비스를 쉽게 호출이 가능하나, .net CF환경에서 개발한 어플리케이션은 조금 느린감이 없지 않아 있고 C++로 만들면 코드가 멋있어 보이는 개인적인 취향 때문에 (^_^;) 만들게 되었습니다.

그리고, 저는 웹서비스에 대해서 자세히 모릅니다.
그냥 Web에서 호출되는 RPC(Remote Procedure Call)이라는 정도 밖에는요.
그래서, 아래 제가 설명하는 부분 중에 틀린 부분도 있을 겁니다.
틀린 부분이 있더라도 너그럽게 봐주시고, 저와 같은 초보분들에게 조금이나마 도움이 되었으면 합니다.



WebService 작성

먼저 클라이언트들이 호출할 간단한 웹서비스를 만들어 보겠습니다. 개발 환경은 아래와 같습니다.

운영체제 Microsoft Windows 2000 SP4
개발도구 Microsoft Visual Studio.net 2003
사용언어 C#


WebService를 생성하기 위해서는 Microsoft Visual Studio.net에서 아래와 같이 프로젝트를 생성합니다.
 

사용자 삽입 이미지



프로젝트를 생성하면 WebService 코드를 XXXX.asmx.cx 파일을 열어 아래와 같이 추가합니다.
아래 코드는 Test()라는 이름으로 생성하여 문자열을 하나 받아서 다시 1차원 문자열 배열로 리턴하는 코드로 작성하였습니다.
 
사용자 삽입 이미지


작성이 완료 되었으면 Compile을 한후에 아래와 같이 확인 하실 수 있습니다.
 
사용자 삽입 이미지
위에 내용을 잘 살펴 보면 WebService는 http로 xml 데이터를 특정 형식에 맞추어 데이터를 보내면 실행 결과를 xml 데이터로 다시 전송해주는 (Soap) 형태를 띄고 있습니다.

이러한 xml 데이터를 http로 전송하면

POST /asp.net/svc/MyWebSvc/MyWebSvc.asmx HTTP/1.1
Host: XXX.XXX.XXX.XXX
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://tempuri.org/Test"

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
               xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
               xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <Test xmlns="http://tempuri.org/">
      <message>웹에서 호출</message>
    </Test>
  </soap:Body>
</soap:Envelope>


http로 이러한 xml 데이터 형태를 받아서 결과를 얻는 것입니다.

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
               xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
               xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <TestResponse xmlns="http://tempuri.org/">
      <TestResult>
        <string>Result[0]=웹에서 호출</string>
        <string>Result[1]=웹에서 호출</string>
        <string>Result[2]=웹에서 호출</string>
      </TestResult>
    </TestResponse>
  </soap:Body>
</soap:Envelope>




Client의 WebService 호출

 

void CSoapClient_XXXXXDlg::OnButton1() 
{
	// TODO: Add your control notification handler code here
	if (FAILED(CoInitializeEx(NULL,COINIT_MULTITHREADED)))
		return;
	InvokeWebSvc  (GetDlgItem (IDC_LIST1)->GetSafeHwnd ());
	CoUninitialize();	
}

       

모든 클라이언트들은 다이얼로그 프로젝트로 리스트박스 컨트롤과 버튼을 하나씩 가지고 있습니다.
버튼이 클릭했을때 클라이언트 프로그램은 InvokeWebSvc() 함수를 호출하여 IDC_LIST1의 리스트 컨트롤에 가져온 데이터를 채워넣는 구조를 가지고 있습니다.



Win32 Soap Client 작성

운영체제 Microsoft Windows XP SP1
개발도구 Microsoft Visual Studio 6.0 SP5
사용언어 C++(MFC)
SDK - Soap Toolkit 3.0 [Download]
(http://www.microsoft.com/downloads/details.aspx?familyid=c943c0dd-ceec-4088-9753-86f052ec8450&languageid=f49e8428-7071-4979-8a67-3cffcb0c2524&displaylang=en)

- Microsoft XML 2.0 이상

버튼이벤트에 대한 내용은 위에서 설명한 내용과 동일하여 생략하고 WebService를 호출하는 부분만 코드로 주석을 이용하여 설명하겠습니다.

       

// COM 관련 클래스를 사용하기 위해 해더 파일을 인클루드합니다.
#include <comdef.h>
#include <atlbase.h>

// MSXML과 MSSoap30 COM의 스마트 포인터를 위해 임포트 시킵니다.
#import "C:\Windows\System32\msxml3.dll"
#import "C:\Program Files\Common Files\MSSoap\Binaries\mssoap30.dll" \
         named_guids exclude("IStream", "IErrorInfo", "ISequentialStream", \
         "_LARGE_INTEGER", "_ULARGE_INTEGER", "tagSTATSTG", "_FILETIME")

// 네임스페이스를 무시합니다.
using namespace MSXML2;
using namespace MSSOAPLib30;

void InvokeWebSvc (HWND hWnd)
{
	BSTR    bstrWsdl   = SysAllocString (L"http://XXX.XXX.XXX.XXX/asp.net/svc/MyWebSvc/MyWebSvc.asmx?WSDL");
	                     // WSDL파일 URL경로를 지정
	BSTR    bstrMethod = SysAllocString (L"Test");       // 웹서비스 메소드 이름
	BSTR    bstrParam  = SysAllocString (L"From Win32"); // 웹서비스 메소드 파라메터
	VARIANT varResult;                                   // 웹서비스 메소드의 리턴값

	CComPtr<ISoapClient> pSoapClient; // MSSoap30 객체의 스마트 포인터

	HRESULT    hr;
	DISPPARAMS dispparams;   // IDispatch::Invoke() 함수를 부르기 위한 파라메터들
	EXCEPINFO  excepinfo;
	DISPID     dispid;
	UINT       uArgErr;

	UINT uDim        = 0;    // 결과값 문자열 배열의 차원 정보
	long lLBound     = 0l;   // 결과값 문자열 배열의 낮은 인덱스
	long lUBound     = 0l;   // 결과값 문자열 배열의 높은 인덱스
	long nBoundIndex = 0l;   // 결과값 문자열 배열 인덱스로 값을 읽어올때 사용합니다.
	BSTR bstrElement = NULL; // 결과값 문자열 배열의 하나의 값을 읽어올때 사용합니다.


#if !(defined(_UNICODE) || defined(OLE2ANSI)) // UNICODE / MBCS 설정에 관계없이 사용하기 위해서 추가했습니다.
	USES_CONVERSION;
#endif

	// IDispatch::Invoke() 파라메터/리턴값 초기화
	VariantInit(&varResult);
	ZeroMemory (&excepinfo,  sizeof(EXCEPINFO));
	ZeroMemory (&dispparams, sizeof(DISPPARAMS));

	try
	{
		hr = pSoapClient.CoCreateInstance (__uuidof(SoapClient30)); // MSSoap30 객체를 생성합니다.

		hr = pSoapClient->MSSoapInit (bstrWsdl, L"", L"", L"");     // WSDL파일 URL경로를 이용하여
		                                                            // MSSoap30 객체를 초기화합니다.

		dispparams.rgvarg             = new VARIANTARG[1];          // IDispatch::Invoke()의 파라메터
		dispparams.cArgs              = 1;                          // 값을 설정합니다.
		dispparams.cNamedArgs         = 0;
		dispparams.rgdispidNamedArgs  = NULL;	 
		dispparams.rgvarg[0].vt       = VT_BYREF|VT_BSTR;
		dispparams.rgvarg[0].pbstrVal = &bstrParam;                 // L"From Win32" 값을 설정합니다.

		// Test()의 이름으로 메소드 아이디를 얻습니다.
		hr = pSoapClient->GetIDsOfNames (IID_NULL, &bstrMethod, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
		// Test() 메소드를 수행합니다.
		hr = pSoapClient->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD,
                                 &dispparams, &varResult, &excepinfo, &uArgErr);

		// 결과값이 문자열 배열인지 확인합니다.
		if ((VT_BSTR|VT_ARRAY)==varResult.vt)
		{		
			uDim = SafeArrayGetDim    (varResult.parray);                 // 몇 차원배열인지 확인합니다.
			hr   = SafeArrayGetLBound (varResult.parray, uDim, &lLBound); // 배열의 낮은 인덱스를 구합니다.
			hr   = SafeArrayGetUBound (varResult.parray, uDim, &lUBound); // 배열의 높은 인덱스를 구합니다.

			// 1차원 배열임을 보증합니다.
			ASSERT (uDim == 1);

			// 배열의 갯수 만큼 반복
			for (nBoundIndex=lLBound; nBoundIndex<=lUBound; nBoundIndex++)
			{
				// 배열로 부터 인덱스에 해당하는 문자열을 읽어옵니다.
				hr = SafeArrayGetElement(varResult.parray, &nBoundIndex, &bstrElement);

				// 문자열을 리스트박스 컨트롤에 추가합니다.
#if !(defined(_UNICODE) || defined(OLE2ANSI))
				SendMessage (hWnd, LB_ADDSTRING, 0, (LPARAM)W2A(bstrElement));
#else
				SendMessage (hWnd, LB_ADDSTRING, 0, (LPARAM)bstrElement);
#endif
				SysFreeString (bstrElement);
				bstrElement = NULL;
			}
		}
	}
	catch (CException* pE)
	{
		// 오류가 발생할 경우 에러메세지를 출력합니다.
		TCHAR szErrMessage[512];

		ZeroMemory (szErrMessage, sizeof(TCHAR[512]));
		pE->GetErrorMessage(szErrMessage, sizeof(TCHAR[512]), NULL);
		AfxMessageBox (szErrMessage);
		delete pE;
	}
	catch (...)
	{
		AfxMessageBox (TEXT("Unknown Exception!"));
	}

	// 사용된 리소스를 해제 합니다.
	VariantClear (&varResult);		
	if (bstrElement)       SysFreeString (bstrElement);
	if (bstrParam)         SysFreeString (bstrElement);
	if (bstrMethod)        SysFreeString (bstrElement);
	if (bstrWsdl)          SysFreeString (bstrElement);
	if (pSoapClient)       pSoapClient.Release();
	if (dispparams.rgvarg) delete [] dispparams.rgvarg;
}

       

실행결과
사용자 삽입 이미지




WinCE.net Soap Client 작성

운영체제 Microsoft Windows CE .net 4.20 Emualtor
개발도구 Microsoft embedded Visual C++ 4.0 SP 2
사용언어 C++(MFC)
SDK - MSSoap 1.0

WinCE.net안에 내장되어있는 MSSoap1.0을 이용하여 WinCE.net에서 Soap Client를 작성하는 방법을 알아 보겠습니다.
위에서 사용한 MSSoap3.0과 달리 1.0은 메소드를 실행하는 것이 아니라 맨 첫 부분에 보았던 xml 문서를 파싱해서 처리해야합니다.

아래 코드 중에 hr로 받은 값이 실패면 에러처리를 해야하는데 귀찮은 관계로(-_-;;) 안했습니다.
잘 알고 계시겠지만 혹시 모르시는 분들을 위해 WinCE 계열 플랫폼에서 코드를 작성할때 문자열은 유니코드로 작성해야됩니다.
그 이유는 제가 WinCE를 안 만들어서 잘모릅니다.(^o^;;)

설명하는 부분은 위 Win32와 동일합니다.

[참고] 일반 WinCE.net 플랫폼 빌더(? 이름이 맞는지 기억이 잘 안나여 -_-;)를 이용해서 PDA를 운영체제를 만들때 운영체제의 용량을 작게하기 위해서 이 Soap 컴포넌트를 빼는 경우가 있습니다. 제가 회사에서 굴러다니는 WinCE.net용 PDA에서 테스트 해본결과 이 컴포넌트가 없어서 에뮬레이터에서 테스트 했습니다.

  

// COM 관련 클래스를 사용하기 위해 해더 파일을 인클루드합니다.
#include <Atlbase.h>
#include <ComDef.h>
#include <Mssoap.h>
#include <Msxml2.h>

void InvokeWebSvc(HWND hWnd)
{
	CComVariant varWsdl         (L"http://XXX.XXX.XXX.XXX/asp.net/svc/MyWebSvc/MyWebSvc.asmx?WSDL");
	                            // WSDL파일 URL경로를 지정
	CComVariant varSoapAction   (L"http://tempuri.org/Test"); // SoapAction 지정
	CComBSTR    bstrUri         (L"http://tempuri.org/");     // uri 지정
	CComBSTR    bstrMethod      (L"Test");          // 웹서비스 메소드 이름
	CComBSTR    bstrReqParamName(L"message");       // 파라메터 이름
	CComBSTR    bstrReqParamVal (L"From WinCE420"); // 파라메터 값

	CComPtr<ISoapSerializer> pSerializer   = NULL; // Soap 직렬 객체
	CComPtr<ISoapConnector>  pConnector    = NULL; // Soap 연결 객체
	CComPtr<ISoapReader>     pReader       = NULL; // Soap 읽기 객체
	CComPtr<IStream>         pIStream      = NULL; // Soap 입력 스트림
	CComPtr<IStream>         pOStream      = NULL; // Soap 출력 스트림
	CComPtr<IXMLDOMDocument> pDOMDocument  = NULL; // xml 결과 문서 객체
	CComPtr<IXMLDOMElement>  pDOMElement   = NULL; // xml 결과 부분의 항목
	CComPtr<IXMLDOMNodeList> pDOMChildNodes= NULL; // xml 결과 부분의 노드리스트
	CComPtr<IXMLDOMNode>     pDOMChildNode = NULL; // xml 결과 부분의 노드
	
	HRESULT      hr;
	VARIANT_BOOL vbSuccess;
	CComVariant  varTemp;
	CComBSTR     bstrResult;

	BSTR bstrElement=NULL;
	long lCount     =0l;
	long lIndex     =0l;


	// Soap 관련 COM 객체를 생성합니다.
	hr = pConnector .CoCreateInstance(__uuidof(HttpConnector));
	hr = pSerializer.CoCreateInstance(__uuidof(SoapSerializer));
	hr = pReader    .CoCreateInstance(__uuidof(SoapReader));
	

	// Soap 객체의 초기화를 합니다.
	hr = pConnector ->Reset();
	hr = pSerializer->reset();
	

	// Soap 객체의 속성을 지정합니다.
	hr = pConnector->put_Property(CComBSTR(L"EndPointURL"), varWsdl);
	hr = pConnector->put_Property(CComBSTR(L"SoapAction"),  varSoapAction);
	
	
	// Soap 연결 객체를 초기화하고 전송할 SOAP 메세지를 작성합니다.
	hr = pConnector->Connect();
	hr = pConnector->BeginMessage();
	
	hr = pConnector->get_InputStream(&pIStream);
	varTemp = pIStream;
	hr = pSerializer->Init(varTemp);
	
	hr = pSerializer->startEnvelope(NULL, NULL, NULL);
	hr = pSerializer->startBody    (NULL);
	hr = pSerializer->startElement (bstrMethod, NULL, NULL, NULL);
	hr = pSerializer->SoapAttribute(CComBSTR(L"xmlns"),NULL,  bstrUri, NULL);
	hr = pSerializer->startElement (bstrReqParamName, NULL, NULL, NULL);
	hr = pSerializer->writeString  (bstrReqParamVal);
	hr = pSerializer->endElement   ();
	hr = pSerializer->endElement   ();
	hr = pSerializer->endBody      ();
	hr = pSerializer->endEnvelope  ();
	
	hr = pConnector->EndMessage();
	

	// SOAP 읽기 객체로 부터 응답 메세지를 받습니다.
	hr      = pConnector->get_OutputStream(&pOStream);
	varTemp = pOStream;
	
	hr = pReader->load(varTemp, CComBSTR(L""), &vbSuccess);


	// 디버깅 창에 받은 메세지를 출력합니다.
	hr = pReader     ->get_DOM (&pDOMDocument);	
	hr = pDOMDocument->get_xml (&bstrResult);
	TRACE (L"\n# Response\n{\n%s\n}\n\n", bstrResult);


	hr = pReader       ->get_RPCResult (&pDOMElement);    // xml 결과 부분의 항목을 가져옵니다.
	hr = pDOMElement   ->get_childNodes(&pDOMChildNodes); // xml 결과 부분의 노드리스트를 가져옵니다.
	hr = pDOMChildNodes->get_length    (&lCount);
	for (lIndex=0; lIndex<lCount; lIndex++)
	{
		// xml 결과 데이터를 하나씩 읽습니다.
		hr = pDOMChildNodes->nextNode (&pDOMChildNode);
		hr = pDOMChildNode ->get_text (&bstrElement);
		
		// 리스트 박스에 결과 데이터를 추가합니다.
		SendMessage (hWnd, LB_ADDSTRING, 0, (LPARAM)bstrElement);

		SysFreeString (bstrElement);
		bstrElement = NULL;

		pDOMChildNode.Release ();
	}
}

       

실행결과
사용자 삽입 이미지




PocketPC Soap Client 작성

운영체제 한글 Pocket PC 2003
장치 iPAQ 5450
개발도구 Microsoft embedded Visual C++ 4.0 SP 2
사용언어 C++(MFC)
SDK - PocketSoap v1.5 beta 1 [Downlaod]
(http://www.pocketsoap.com/pocketsoap/)

Pocket PC에서의 Client는 MS가 만들어준 SOAP SDK가 없었습니다.
MSDN에서 찾아보니 PocketSoap이라는 외국에 어떤분께서 만들어 공개한걸 이용하라는 것만 있었습니다.
그래서, 샘플 프로그램을 만들어본 결과 WinCE.net에서 Soap Client를 만든었던것과 거의 동일하게 코드를 작성하시면 됩니다.

PocketSoap을 인스톨하고 단말기에 싱크할여 설치하면 아래의 파일들이 인스톨이 됩니다.
참고 하시고 혹시 이 PocketSoap을 이용하여 프로그램을 개발 후 배포하실때 같이 CAB으로 묶어서 배포하시면 됩니다.
  • xmltok.dll
  • xmlparse.dll
  • psoap.dll
  • pszlib.dll
  • pockethttps.dll

    그리고, 컴파일시에 필요한 파일들은 제가 따로 분리해 놓았습니다.
    그 파일들은 PocketPC 소스 폴더 하위 폴더에 있습니다.

  •  
      
    // COM 관련 클래스를 사용하기 위해 해더 파일을 인클루드합니다.
    #include <atlbase.h>
    
    // 제가 분리해놓은 파일중 이 파일 하나만 인클루드 하면됩니다.
    #include "PocketSOAP\pSOAP.h"
    
    void InvokeWebSvc (HWND hWnd)
    {
    	CComBSTR    bstrWsdl        (L"http://XXX.XXX.XXX.XXX/asp.net/svc/MyWebSvc/MyWebSvc.asmx?WSDL");
    	                            // WSDL파일 URL경로를 지정
    	CComBSTR    bstrUri         (L"http://tempuri.org/");      // uri 지정
    	CComBSTR    bstrSoapAction  (L"http://tempuri.org/Test");  // SoapAction 지정
    	CComBSTR    bstrMethod      (L"Test");        // 웹서비스 메소드 이름
    	CComBSTR    bstrReqParamName(L"message");     // 파라메터 이름
    	CComVariant varReqParamVal  (L"From PPC2K3"); // 파라메터 값
    
    	CComPtr<ISOAPEnvelope>     pEnvelope;   // PocketSoap 객체
    	CComPtr<IHTTPTransportAdv> pHttpTrans;  // Http 전송 객체
    	CComPtr<ISOAPNodes>        pReqParams;  // Request 노드 리스트
    	CComPtr<ISOAPNode>         pReqParam;   // Request 노드
    	CComPtr<ISOAPNodes>        pResParams;  // Response 노드 리스트
    	CComPtr<ISOAPNode>         pResParam;   // Response 노드 리스트
    	CComPtr<ISOAPNodes>        pChildNodes; // 결과값 노드 리스트
    	CComPtr<ISOAPNode>         pChildNode;  // 결과값 노드
    
    	HRESULT     hr;
    	CComBSTR    bstrReqXMLData; // Request  xml 문자열
    	CComBSTR    bstrResXMLData; // Response xml 문자열
    	CComVariant varValue;
    
    	long        lChildNodeCount = 0;
    	long        lIndex          = 0;
    
    
    	// Soap 관련 COM 객체를 생성합니다.
    	hr = pEnvelope .CoCreateInstance(__uuidof(CoEnvelope));
    	hr = pHttpTrans.CoCreateInstance(__uuidof(HTTPTransport));
    
    	// Soap 객체에 속성을 지정합니다.
    	hr = pEnvelope->put_EncodingStyle (CComBSTR(L""utf-8"));
    	hr = pEnvelope->SetMethod (bstrMethod, bstrUri);
    
    	hr = pEnvelope ->get_Parameters(&pReqParams); // Soap 객체에 파라메터를 지정합니다.
    	hr = pReqParams->Create(bstrReqParamName, varReqParamVal, bstrUri, NULL, NULL, NULL);
    
    	hr = pHttpTrans->put_SOAPAction(bstrSoapAction);
    
    
    	// Soap 보낼 xml 데이터를 작성합니다.
    	hr = pEnvelope ->Serialize (&bstrReqXMLData);
    	TRACE (L"# Request\n{\n%s\n}\n\n", bstrReqXMLData); // 보낼 xml 데이터 디버깅 창에 출력합니다.
    
    	// xml 데이터를 보냅니다.
    	hr = pHttpTrans->Send (bstrWsdl, bstrReqXMLData);
    
    
    	// xml 데이터를 받습니다.
    	hr = pEnvelope ->Parse(CComVariant(pHttpTrans), NULL);
    
    	hr = pEnvelope ->get_Parameters(&pResParams);
    	hr = pResParams->get_Item      (0, &pResParam);
    
    
    	hr = pEnvelope ->Serialize (&bstrResXMLData);
    	TRACE (L"# Response\n{\n%s\n}\n\n", bstrResXMLData); // 받은 xml 데이터 디버깅 창에 출력합니다.
    
    
    	hr = pResParam  ->get_Nodes (&pChildNodes);
    	hr = pChildNodes->get_Count (&lChildNodeCount);
    	for (lIndex=0; lIndex<lChildNodeCount; lIndex++)
    	{
    		// 데이터를 하나씩 읽습니다.
    		hr = pChildNodes->get_Item  (lIndex, &pChildNode);
    		hr = pChildNode ->get_Value (&varValue);
    
    		// 리스트 박스에 결과 데이터를 추가합니다.
    		SendMessage (hWnd, LB_ADDSTRING, 0, (LPARAM)varValue.bstrVal);
    
    		pChildNode.Release ();
    		varValue  .Clear   ();
    	}
    }         
    
           

    실행결과
    사용자 삽입 이미지



    Posted by 셈말짓기 :