여러 PC를 사용하는 프로그램에서 PC를 제어하기 위해, TCP 서버로 XML을 교환하려고 했다.

xml문을 전달하려고 하니, xml문서를 버퍼에 저장하고 반대로 버퍼에서 xml문서를 만드는 기능이 필요했다.

다행히 tinyxml2는 버퍼에 xml을 쓰거나, 버퍼의 xml을 읽어서 XMLDocument로 만드는 기능을 지원한다.  

 

아래 예제는 m_ServerInfos에 저장된 정보를 xml로 만들어 const char*로 받고,

반대로 const char*로부터 XMLDocument를 만드는 예제를 보여준다.

 

마지막 세줄을 제외하고는 그냥 xml 문서를 만드는 구문이다.

마지막 세줄이 버퍼에 xml을 출력하는 구문인데, XMLPrinter를 하나 만들어 여기다가 doc를 출력하면 된다.

그 다음 XMLPrinter의 CStr( )을 호출하면 xml문서의 const char* 포인터를 받을 수 있다.

문자열의 길이는 XMLPrinter::CStrSize를 호출하면 알 수 있다.

반대로 버퍼속의 xml문서를 객체로 만들기 위해서는 tinyxml2::XMLDocument::parse를 하면된다.

첫번째 파라미터는 xml문서의 포인터이고 두번째 파라미터는 문서 문자열의 길이다.

파싱된 xml로부터 이전의 IP주소가 정상적으로 출력되는 것을 볼 수 있다.

 

끝!

Posted by 굿쟌
,

컴퓨터 여러대로 동작하는 프로그램에서 다른 서버의 IP 정보를 XML로 저장해 두고 싶었다.

아래와 같이 TestEnvironment라는 Root element아래 서버정보를 기록해서 파일로 만들었다.

위 XML파일을 만드는데 사용한 코드는 아래와 같다.

어려울 것 없다.

새 element를 doc로 만들고, 상위 element의 LinkEndChild를 호출 해 만들어 놓은 element추가하면 된다.

attribute를 추가하고 싶으면 해당 elelment의 setAttribute를 호출 하면 된다.

비슷하게 text를 추가하고 싶으면 setText를 호출하면 된다.

 

XML파일을 파싱 할 때도 거의 비슷하다.

차이점이라면, element의 attribute를 불러 올 때 원하는 자료형으로 가져올 수 있다.

혹은 그냥 text로 받아오는 것도 가능하다.

위 코드에서, for문은 다음 sibling이 없을때 까지, 모든 sibling의 text와 "idx" atrribute를 받아온다.

NextSiblingElement함수를 호출하면 해당 XMLElement와 동일 레벨의 sibling들을 찾아올 수 있다.

만약 현재 xmlElement가 마지막 element라면 NextSiblingElement는 NULL을 반환한다.

 

Posted by 굿쟌
,

https://sourceforge.net/projects/tinyxml/

요기 들어가서 clone or download 눌러서 다운 받자. xinyxml2-master.zip이라는 파일로 다운된다.

최상위 폴더에 CMakeList가 있는걸 봐서 CMake도 지원하나보다.

Makefile이 있으니 리눅스 쓰시는 분들은 그냥 make로 빌드하시면 될듯..

근데 고맙게도 visual studio 2015버전 솔루션으로 바로 라이브러리를 빌드 할 수 있게 해놨다.

tinyxml2 폴더에 들어 가면 visual studio 2015 솔루션 파일이 한개 있다.

근데 내 컴퓨터에 visual studio 2015가 없어서 그냥 2010 솔루션 파일로 보인다.

visual studio 2010으로 열어도 변환 없이 그냥 열린다. 

뭔가 에러도 안나고, 변환도 안하고, 기분좋은 예감에 그냥 빌드하면 아래와 같은 에러를 만날 수 있다.

 

"error MSB8008: 지정된 플랫폼 도구 집합(v140)이 설치되지 않았거나 올바르지 않습니다."

왜냐면 나는 돈이 없어서 vs2015는 없으니까...

빌드하기 전에 아래와 같이 플랫폼 도구 집합을 변경해주자.

난 vs2010에서 코딩할 거라 도구집합을 v100으로 변경해서 빌드했다.

빌드가 다 되면, 메인폴더의 bin폴더 아래 빌드 구성에 따라 라이브러리가 생성된다.

 

빌드 구성은 아래 4개가 있으니까 쓰고 싶은 것 빌드해서 쓰면 된다.

Debug-Dll : 디버깅용 동적라이브러리

Debug-Lib : 디버깅용 정적라이브러리

Release-Dll: 릴리즈용 동적라이브러리

Release-Lib: 릴리즈용 정적라이브러리

 

참고로 솔루션에 프로젝트가 2개 들어가 있다.

한개는 라이브러리 빌드하는 프로젝트고 나머지 한개는 테스트용 프로그램..

둘다 빌드해 놓고 test프로그램을 실행시키면 dll이 없다고 실행이 안된다.

그냥 디버깅할 때, vs디버거가 사용하는 working 디렉토리가 아닌 곳에 dll이 생성되서 그런다.

 

만들어 놓은 test.exe와 dll을 그냥 모두 복사해서 tinyxml2.h 가 있는 폴더에다 옮겨보자.

그리고 test.exe를 실행시켜보자.

뭔가 콘솔이 잠깐 켜졌다가 꺼지는데 resources/out에 아래같이 파일이 생기면 성공한거다.

 

끝!

Posted by 굿쟌
,

코딩 하다보니까 조금 헷갈려서 확인차 이것 저것 해보다보니 더 헷갈렸다.

C#의 reference, value참조에 대해서 MSDN에 나와 있는 것 + 구글링 한 내용으로 정리 해 본다.

 

코드를 보는게 가장 빠르다.

 

Call By Value 

 public void CallByValue(int a)

{

a = 100;

}

 

static void main(string args[])

{

int test = 0;

CallByValue(test);

Console.WriteLine(test);

}

 

결과는 0

 

Call By Reference 

 public void CallByReference(ref int a)

{

a = 100;

}

 

static void main(string args[])

{

int test = 0;

CallByReference(test);

Console.WriteLine(test);

}

 

결과는 100

참고로 out을 써도 되는데 ref와 out에는 다음과 같은 차이가 있다.

out : 초기화 안되도 됨

ref : 초기화 되어야만 함

 

Class경우

 public class A

{

    public int m_Int = 0;

}

 

// 파라미터로 입력되는 A의 Instance에 대한 참조 카운터가 1개 증가

public Function1(A param)

{

    //참조카운터 2 상태 (main에서 사용하는 instance와 이 함수의 param)

    param.m_Int = 100;

   

    // 동일 메모리를 가리키는 하나의 포인터 제거 의미

    // 참조 카운터 1상태 (main에서 사용하는 instance는 메모리에 할당 된 A를 여전히 가리킴)

    param = null;

}

 

// 파라미터로 입력되는 A의 Instance에 대한 참조 카운터가 그대로 유지

public Function2(ref A param)

{

    //참조 카운터가 증가하지 않음

    // main의 instance를 param이라는 이름으로 바꿔 쓰는 의미

    param.m_int = 100;

   

    // param이 가리키는 메모리에 대한 참조 카운터가 0이 되어 메모리 에서 릴리즈 된다.

    // 더이상 main의 instance도 null이다.

    param = null;

 

}

 

 

static void main(string args[])

{

A instance = new A();

Function1(instance);

Console.WriteLine(instance.m_int);  //100 출력, instance는 여전히 메모리에 할당 된 영역 가리킴

 

Function2(instance);

Console.WriteLine(Instance.m_int); // Instance는 null이므로 에러가 발생한다.

 

}

 

Structure의 경우

 public structure A

{

    public int m_Int = 0;

}

 

// 구조체는 instance의 값이 param에 복사된다.

public Function1(A param)

{

    param.m_Int = 100;   

    param = null;

}

 

public Function2(ref A param)

{

    // main의 instance를 param이라는 이름으로 바꿔 쓰는 의미

    param.m_int = 100;

   

    // param이 가리키는 메모리에 대한 참조 카운터가 0이 되어 메모리 에서 릴리즈 된다.

    // main의 instance도 이제 null이다.

    param = null;

 

}

 

 

static void main(string args[])

{

A instance = new A();

Function1(instance);

Console.WriteLine(instance.m_int);  //0 출력, instance는 Function1에 값만 복사 해 줬다.

 

Function2(instance);

Console.WriteLine(Instance.m_int); // Instance의 m_int는 100이 되었다.그러나 instance가 null이 되어

                                                  // 이 문구에서 에러가 발생하게 된다. 

}

 

http://msdn.microsoft.com/en-us/library/0f66670z.aspx 

이 문서를 참조 하였다.

 

'프로그래밍 > 기타' 카테고리의 다른 글

UML-클래스다이어그램 관계 정리  (1) 2015.01.15
Posted by 굿쟌
,

다음과 같은 폼으로 헤더파일을 만들어 주면, #ifndef 전처리 문으로 인해

2번째 선언시에 _CLASS_ 상수가 정의 되어 있어서 중복선언을 막아준다. 

 

전방선언 하고 헤더를 소스파일 cpp에 넣어서 교차포함을 피하는 방법도

있기는 하지만,이것저것 오류가 나는 경우가 굉장히 많았다.

 

이 방법이 그냥 단순무식 하면서도 편하게 코딩 할 수 있는 방법인듯 하다.

 

// class 헤더의 선언

// "class.h"

 

 #ifndef _CLASS_

 

#define _CLASS_                   

#include "포함할 헤더파일"

[클래스 및 함수 선언]

 

#endif

    

 

 

 

 

 

 

 

 

 

 

 

 // class 소스파일

// "class.cpp"

 

#include "stdafx.h"

#include "class.h"

 

[클래스 및 함수 정의]

 

미리 컴파일 된 헤더파일을 사용하면 헤더에 헤더를 포함해 주지 않아도

stdafx.h에 선언된 클래스를 class.h에서 사용 할 수 있다.

 

단, 소스파일에서 stdafx.h를 반드시 추가시켜 줘야 미리 컴파일 된 헤더를 사용할 수 있다.

참고로 stdafx.h 이전에 포함 된 헤더파일은 모두 무시 되니, 이 점을 꼭 고려해야 한다.

 

Posted by 굿쟌
,

가상 메모리를 RAM보다 더 큰 크기로 할당 할 수 있는 비밀은 HDD의 일부를 SWAP FILE로 사용하여 RAM의 상태를 저장하는데 있다. 이 부분에 대해서 정리한 파일을 올려본다. 사진은 보고 있는 "뇌를 자극하는 Windows System Programming"에서 발췌하였다.

 

 

 

 

 

 

'프로그래밍 > WinSysProgram' 카테고리의 다른 글

가상메모리 (1)  (0) 2015.01.16
16비트 CPU 명령어 설계  (0) 2014.10.25
간단한 CPU 구조  (0) 2014.10.25
Posted by 굿쟌
,

 뇌를 자극하는 Windows 시스템 프로그래밍에서 가상 메모리에 대한 내용 즉, "어떻게 각 프로세스에게 실제 메인 메모리 ( RAM ) 용량보다 많은 메모리를 할당 할 수 있는가"에 대한 해답을 정리한 내용이다.

 

공부를 할 수록 그동안 모르고 있던 것을 알게되어 기쁘다. 사실 현업에서는 별 필요 없는 이론적인 이야기지만, 그동안 몰랐던 것을 알게되니 안보이던 것들이 보여 시야가 넓어지는 기분이다.

 

 

 

'프로그래밍 > WinSysProgram' 카테고리의 다른 글

가상 메모리 (2)  (0) 2015.01.18
16비트 CPU 명령어 설계  (0) 2014.10.25
간단한 CPU 구조  (0) 2014.10.25
Posted by 굿쟌
,

 C# 으로 외부 SDK를 DllImport해서 사용하는 도중에 아래와 같은 런타임 에러가 발생했다.

 

 

"CreateSceneInstance'에 대한 호출 결과 스택이 불안정하게 되었습니다. 관리되는 PInvoke 시그니처와 관리되지 않는 대상 시그니처가 일치하지 않기 때문인 것 같습니다. 호출 규칙 및 PInvoke 시그니처의 매개 변수와 관리되지 않는 대상 시그니처가 일치하는지 확인하십시오."

 

라는 런타임 에러인데... SDK가 외국 회사 SDK라서 물어보기도 애매한데 에러가 나서 당황했지만, SDK에 포함되어 있는 샘플 프로그램과 하나하나 비교해보니 샘플 프로그램은 닷넷 2.0으로, 내가 짜는 프로그램은 닷넷 4.0을 기준으로 설정되어 있는 것을 확인 했다.

 

그래서 내가 만든 프로젝트도 닷넷 2.0으로 설정을 바꾸니 이 에러 없이 정상 동작 한다.. ㅎㅎ

 

 

 

인터넷에서 검색을 해봐도 이 에러가 발생했을 때, 닷넷 프레임 워크 3.5이하 버전으로 대상 프레임 워크를 변경하면 된다는 답변이 있었다.. 그래도 뭔가 이렇게 끝내려고 하니 안 닦고 나온 기분이라 좀더 검색을 해봤는데, 이 문제의 원인은 DLL파일을 Import할 때 함수 호출규약 CallingConvention을 DLL파일과 동일하게 설정해 주지 않았기 때문이란다.

 

닷넷 4.0부터는 DllImport할 때 CallingConvention을 지정하지 않는 경우 무조건 __stdcall로 간주하고 함수를 가져오는데, 이 때문에 dll에 들어 있는 함수와 실제 부르려고 하는 함수간 호출규약이 다르면 이런 에러가 날 수 있다고 한다.

 

이제 함수를 부를 때 아래와 같이 실제 CallingConvenction을 명기해주면, 정상적으로 런타임 에러 없이 프로그램이 동작한다.

 

출처 : 다음 블로그 어딘가 impactlife라는 분이 남기신 댓글에서 이 정보를 얻었다. 2013년에 올리신 답변이 2015년에

         어떤 초보 개발자를 구했다. 감사하다는 말을 남긴다.

 

Posted by 굿쟌
,

 

프로그램 개발 하기 전에 나는 클래스 다이어그램과 시퀀스 다이어그램만 그리는데, 매번 그릴때마다 헷갈려서 이렇게 정리해 봤다. 점선도 매번 햇갈려서 같이 넣어봤다. ㅋ

Posted by 굿쟌
,

postgresql 관련 서적이 다양하지 않아 wrox사에서 출판된 beginning database with postgresql을 알라딘에서 중고서적으로 구해 보고 있다. 상당히 오래 전의 postgresql을 대상으로 책이 씌여졌기 때문에 설치 부분이나 pgAdmin III같은 부분들이 반영되지 않았지만, sql문법이나 기본 데이터베이스 관련 지식은 변함 없기 때문에 이 책도 썩 나쁘지는 않다.

 

그런데, 테스트 데이터 베이스 샘플을 구축하기 위해 Wrox사에서 출판한 "beginning database with postgresql" (빨간 바탕에 아저씨 두명) 의 소스코드를 다운 받을려고 책에서 설명한대로 Wrox사 홈페이지에 들어가 보면, 황당하게도 해당 서적에 대한 서적검색도 안되고 소스코드도 찾아 볼 수가 없는데 이 문제 때문에 한참을 구글링을 했다.

 

결론부터 말하자면, 해당 서적에 대한 판권이 Apress사로 넘어가게 되면서 이 책의 소스코드도 apress사로 넘어가게 되었단다. ㅎㅎ..

 

http://www.apress.com/9781590594780

 

아래 싸이트에 들어가면 여전히 서적에서 제공하는 sql파일과 소스코드를 다운 받을 수 있다.

 

참고로 sql문서는 처음 그대로 돌리면 에러가 발생한다.

아마도 postgresql 버전이 변경되면서 읽을 수 있는 Date 포맷이 변경되어서 인지, sql파일의 date를 받아들이지 못하는 현상이 발생하기 때문이다..이 에러 같은 경우는 사용자가 날짜를 2014-12-12와 같은 포맷으로 변경해주면 책에서 소개하는 테이블 셋을 간단히 만들수 있다.

Posted by 굿쟌
,