Search results for '전체'

  1. 2019.01.30 -- 델파이 코드 작성 규칙
  2. 2019.01.23 -- 이더넷 어댑터 정보((MacAddress, IP 등) 목록 알아오기
  3. 2019.01.14 -- CEF4Delphi(크로미움 기반 웹브라우저) 컴포넌트 설치 및 실행하기 (2)
  4. 2019.01.14 -- [REST API] MAC(Message Authentication Code)/HMAC 델파이로 구현하기
  5. 2018.12.20 -- OAuth 2.0 연동 - 카카오 API(카카오톡 프로필)
  6. 2017.12.19 -- RFID 리더(한미IT RF Prisma) 연동하기 - 델파이에서 JAR 이용 (2)
  7. 2017.12.06 -- WaitDialog 구현 - 재사용 가능한 프레임 구현하기
  8. 2017.11.22 -- [튜토리얼] 메일 전송(IdSMTP 이용) (2)
  9. 2017.11.22 -- [튜토리얼] FTP 업로드(TIdFTP 이용)
  10. 2017.11.02 -- 델파이/C++빌더에 TTcpClient, TTcpServer, TUdpSocket 등록하기
  11. 2017.10.30 -- 안면인식(Face Detection) 라이브러리(안드로이드, iOS)
  12. 2017.10.30 -- TTS(Text-to-Speech) 라이브러리(윈도우, 맥OS, iOS, 안드로이드)
  13. 2017.10.30 -- 델파이로 빅데이터 데이터베이스 연동하기(Cassandra, Couchbase, MongoDB)
  14. 2017.09.20 -- [FMX] TListView 더보기 버튼 구현하기
  15. 2017.09.18 -- [REST API] 다음 Kakao > 로컬 > 주소검색 연동하기
  16. 2017.09.12 -- [FMX] 폼의 높이를 애니메이션으로 변경하기, 툴바를 끌어 폼 이동하기
  17. 2017.09.08 -- [FMX] iOS 시스템 볼륨 제어하기
  18. 2017.09.08 -- TListView 행별로 배경색 설정 및 글꼴변경하기
  19. 2017.06.14 -- "REST API 웹서비스 연동" 교육자료 (1)
  20. 2017.05.25 -- 프로세스 메모리 사용량 로그 기록 - 성능 모니터 이용

델파이 코드 작성 규칙

2019.01.30 13:37

데브기어에서 진행 중인 프로젝트 과정에서 사용 중인 코드작성 규칙을 공유합니다.

https://docs.google.com/document/d/1eYWWv_YJRl-FYw3FkcIaBRSzaHsL0V-zRjA2rzJsPZM



험프리.김현수 Delphi/C++Builder

이더넷 어댑터 정보((MacAddress, IP 등) 목록 알아오기

2019.01.23 16:08

윈도우에 설치된 네트워크(이더넷 어댑터) 정보를 알아오는 방법입니다.(10.3 리오에서 구현했습니다.)


uses 절에 Winapi.IPTypes, Winapi.IPHlpAPi 추가해야 합니다.

var
  I: integer;
  NumInterfaces: DWORD;
  AdapterInfo: array of TIpAdapterInfo;  // uses Winapi.IpTypes
  OutBufLen: ULONG;
begin
  GetNumberOfInterfaces(NumInterfaces); // uses Winapi.IpHlpApi
  SetLength(AdapterInfo, NumInterfaces);
  OutBufLen := NumInterfaces * SizeOf(TIpAdapterInfo);
  GetAdaptersInfo(@AdapterInfo[0], OutBufLen);

  Memo1.Lines.Clear;
  for I := 0 to NumInterfaces - 1 do begin
    if AdapterInfo[I].Description = '' then
      Continue;
    Memo1.Lines.Add(AdapterInfo[I].Description);
    Memo1.Lines.Add(AdapterInfo[I].IpAddressList.IpAddress.S);
    Memo1.Lines.Add(Format('%.2x:%.2x:%.2x:%.2x:%.2x:%.2x',
      [AdapterInfo[I].Address[0], AdapterInfo[I].Address[1],
       AdapterInfo[I].Address[2], AdapterInfo[I].Address[3],
       AdapterInfo[I].Address[4], AdapterInfo[I].Address[5]]));
  end;

기타 정보도 TIpAdapterInfo 구조체를 통해 알아올 수 있습니다.


메모에 출력된 결과 화면


참고


험프리.김현수 Delphi/C++Builder

CEF4Delphi(크로미움 기반 웹브라우저) 컴포넌트 설치 및 실행하기

2019.01.14 17:06

REST API 관련 컨설팅 중 학습한 내용을 공유합니다.


고객사의 요청으로 VendHQ 사의 REST 서비스와 연동을 진행했습니다.

OAuth 2.0 연동 중 웹브라우저 이슈가 있어 해결방안을 공유합니다.


OAuth 2.0 인증 시 크게 3가지 단계로 진행합니다.
1) 서비스의 인증페이지에 로그인 해 인증코드를 받는다.
2) 인증코드를 이용해 엑세스 토큰을 취득한다.
3) 엑세스 토큰을 이용해 서비스에 접근한다.

이슈는 1)번 과정에서 발생했습니다.
델파이 내장 웹브라우저 컴포넌트(TWebBrowser)가 vend사의 로그인 페이지를 정상 출력하지 않아 다음 단계로 진행되지 않습니다.(vend사에서 표준을 지키지 않고 페이지를 만든것으로 예상됩니다.)

다음과 같이 스타일이 적용되지 않고, 허용 버튼(Allow Access) 클릭이 되지 않습니다.

해당 이슈는 VCL과 FMX 두가지 TWebBrowser가 동일합니다.


그래서 다른 대안으로 크롬미움 기반 웹브라우저 써드파티 컴포넌트(크로미움)를 테스트 해봤습니다.
해당 컴포넌트로는 인증 페이지가 정상 출력되고, 인증코드를 받아오는 부분까지 정상 진행되었습니다.


크로미움 기반 웹브라우저 컴포넌트 설치

CEF4Delphi는 크로미움 기반 웹브라우저 써드파티 컴포넌트로 오픈소스로 진행됩니다.

깃허브 저장소를 통해 제공하고 있습니다.

CEF4Delphi를 사용하려면 컴포넌트 설치 후 실행(및 배포) 시 크로미움 관련 라이브러리들을 함께 배포해야 합니다.


CEF4Delphi 다운로드


CEF4Delphi 깃허브 페이지에서 컴포넌트를 다운로드 합니다.(Clone or download > Download ZIP)


다운로드 받은 파일을 압축 해제 후 적절한 라이브러리 저장 경로에 이동합니다.(해당 경로의 패키지를 설치하고 델파이에 링크하게 됩니다.)


CEF4Delphi 컴포넌트 설치

델파이를 실행하고 다운로드 받은 파일들에서 .\packages\CEF4Delphi.dpk 패키지 프로젝트 파일을 엽니다.

프로젝트에서 오른쪽 마우스 클릭 후 팝업 메뉴에서 인스톨 메뉴를 선택해 설치합니다.

 


라이브러리 패스 추가

패키지 설치 후 CEF4Delpih 소스코드를 델파이 라이브러리 패스에 추가합니다.


델파이 라이브러리 화면을 표시합니다.

Tools > Options, Language > Delphi Options > Library


플랫폼을 선택 후 Library path에 CEF4Delphi 소스 디렉토리를 추가합니다.


CEF4Delphi 프로그램 실행

패키지(컴포넌트)를 정상 설치 후 데모를 실행하면 오류가 발생합니다.

내장 된 데모 중 SimpleBrowser2(.\CEF4Delphi\demos\SimpleBrowser2)를 열고 실행 시 다음과 같은 오류가 발생합니다.


오류 내용을 보면 CEF3 바이너리가 누락되었다는 내용입니다.

일반적으로 위와 같은 오류의 조치방법은 실행파일과 같은 경로 또는 시스템 패스에 해당 라이브러리들을 복사하는 방법이 있습니다.

하지만 CEF4Delphi는 소스코드 내에서 해당 경로를 지정하는 방법을 제공합니다.


CEF 바이너리 지정

SimpleBrowser2의 프로젝트 파일을 열면 다음과 같이 GlobalCEFApp 전역변수와 각종 경로를 지정하는 코드가 주석처리 되어 있습니다.

경로를 지정하는 코드의 주석을 풀고, 해당 경로에 CEF 바이너리를 넣거나 경로를 임의로 지정할 수 있습니다.


GlobalCEFApp.FrameworkDirPath := 'cef'; 경로는 실행파일과 같은 경로의 cef 디렉토리를 의미합니다.


우리는 위의 코드에서 주석 해제 후 지정한 디렉토리(.\cef)에 CEF 바이너리를 복사하도록 하겠습니다.

CEF 바이너리 다운로드

CEF4Delphi 깃허브 페이지에서 CEF 바이너리를 다운로드 제공합니다.

윈도우즈 32비트 플랫폼 애플리케이션에서 CEF 이용 시 32 bits를 다운로드 합니다.
(64비트 프로젝트 개발 시 64 bits를 다운로드 합니다.)


CEF4Delphi 컴포넌트의 경로 하위 bin 디렉토리에 다운로드 받은 파일을 압축해제 합니다.

CEF 바이너리 복사

SimpleBrowser2 데모를 컴파일하면 .\CEF4Delphi\bin 디렉토리에 실행파일이 생성됩니다.
(Project > Options > Delphi Compiler > Output directory가 "..\..\bin"으로 설정)


bin 디렉토리 하위에 cef 디렉토리를 생성합니다.


CEF 바이너리 파일 중 아래 디렉토리의 모든 파일과 디렉토리를 생성한 cef 디렉토리에 복사합니다.

  • Release\*.*
  • Resources\*.*

이후 다시 데모 프로젝트를 실행하면 오류없이 정상 실행을 확인할 수 있습니다.


배포 시에도 실행파일 하위 cef 디렉토리를 함께 배포하거나, CEF 바이너리 디렉토리를 지정해야 합니다.


관련/참고 링크



험프리.김현수 데이터 엑세스

  1. Blog Icon
    bioman

    좋은 자료 공유 감사합니다.

  2. Blog Icon

    비밀댓글입니다

[REST API] MAC(Message Authentication Code)/HMAC 델파이로 구현하기

2019.01.14 11:56

REST API 관련 컨설팅 중 학습한 내용을 공유합니다.


한 고객사의 요청으로 Unleashed 사의 REST 서비스와 연동을 진행했습니다.

그 과정 중 HMAC(해시 기반 메시지 인증 코드) 구현 과정을 공유합니다.


HMAC은 Unleashed 사 뿐아니라 AWS의 REST API 연동에도 사용되는 등 많은 REST 서비스에 구현되는 내용입니다.


MAC과 HMAC

먼저 MAC(Message Authenticate Code: 메시지 인증 코드)를 살펴봅니다.

(출처: https://ko.wikipedia.org/wiki/메시지_인증_코드)


MAC는 발신자(Sender)와 수신자(Receiver) 사이에 메시지 변조 여부를 확인하기 위한 메시지 인증 방식입니다.

위 그림을 통해 설명하면, 

Sender는 보내는 메시지(MESSAGE)와 지정된 키(Key)를 조합해 MAC을 만들고 메시지와 MAC을 전달합니다.

Receiver는 메시지와 MAC를 수신 후 메시지와 지정된 키를 조합해 MAC을 만들어 수신한 MAC과 비교해 데이터의 위변조를 판단할 수 있습니다.


HMAC(Hashed MAC)는 MAC Algorithm에 해쉬 함수를 적용해 암호화 하는 방식입니다.


HMAC 예시

제가 진행한 Unleashed 사는 API 요청 시 HTTP 해더에 다음 정보를 포함해야 합니다.

  • Content-Type, Accept
  • api-auth-id
  • api-auth-signature
Content-type과 Accept는 송수신 시의 데이터 포맷인 application/json을 입력하면 됩니다.
api-auth-id는 서비스 등록 시 발급받은 API ID를 입력하면 됩니다.
api-auth-signature는 HMAC을 생성해 입력해야 합니다.

서비스 제공사의 문서를 보면 HMAC-SHA256을 어떻게 만들어야 하는지 안내합니다.

위 문서 중 일부는 다음과 같습니다.

The method signature must be generated by taking the query string, and creating a HMAC-SHA256 signature using your API key as the secret key.
(메소드 시그니처는 쿼리 스트링을 가져와 API Key를 시크릿 키로 HMAC-SHA256 시그니처를 생성해야 한다.)

위에서 API 키는 서비스 등록시 발급받은 값입니다.


쿼리 스트링은 URL 중 "?" 뒤의 문자열입니다. 예를 들면

Customers?customerCode=ACME 중 customerCode=ACME가 쿼리 스트링입니다.


HMAC-SHA256은 다음과 같이 구현할 수 있습니다.

HMAC-SHA256

다음 샘플은 쿼리스트링(ProductCode=XXX)와 API Key(UNLEASHED_API_KEY: 상수)를 이용해 HMAC을 SHA256으로 시그니처를 생성해 HTTP 해더에 추가하는 내용입니다.

uses
  System.Hash,          // sha256
  System.NetEncoding;   // base64

var
  signature: string;
  param: string;
begin
  param := 'ProductCode=' + AProductCode;

  // PHP: base64_encode(hash_hmac('sha256', $request, $key, true));
  signature := TBase64Encoding.Base64.EncodeBytesToString(
                  THashSHA2.GetHMACAsBytes(param, UNLEASHED_API_KEY, SHA256));

  RESTRequest1.Params.AddItem('api-auth-id', UNLEASHED_API_ID, pkHTTPHEADER);
  RESTRequest1.Params.AddItem('api-auth-signature', signature, pkHTTPHEADER, [poDoNotEncode]);
end;


추가 학습할 내용

HMAC 인증외에 OAuth 2.0 인증도 많이 사용됩니다.

다음 글을 통해 OAuth 2.0을 통해 카카오 API에 연동하는 내용을 살펴볼 수 있습니다.

다음 글들을 통해 REST API를 이해하고 실습할 수 있습니다.

험프리.김현수 데이터 엑세스

OAuth 2.0 연동 - 카카오 API(카카오톡 프로필)

2018.12.20 01:35


이 글에서는 OAuth 2.0을 이용해 카카오 API와 연동하는 방법을 델파이를 통해 알아봅니다.

이 글을 통해 카카오톡 프로필 정보와 사진을 델파이 애플리케이션에서 불러오는 예제를 작성할 수 있습니다.


OAuth 2.0

API(또는 서비스) 이용 시 인증(Authentication)과 리소스(제공 서비스)에 대한 권한부여(Authorization)는 필수사항입니다. 인증과 권한부여의 대표적인 방법 중 하나가 OAuth입니다.


OAuth는 서버와 클라이언트 사이에 인증을 완료 시 권한부여의 결과로 엑세스 토큰(Access Token)을 발급하고, 이 엑세스 토큰을 이용해 클라이언트는 API(또는 서비스)에 접근 및 서비스를 요청하게 됩니다. 서버는 엑세스 토큰 기반으로 서비스와 권한에 대한 접근 여부를 판단해 데이터를 제공합니다.


OAuth는 현재 2.0 버전을 제공하며, 카카오, 구글, 페이스북에서 OAuth 2.0을 통해 서비스에 대한 인증 및 권한부여를 사용하고 있습니다.


OAuth 2.0에 대한 내용은 자세한 내용은 이 글의 하단 "관련/참고 링크"를 통해 알아볼 수 있습니다.


OAuth 2.0 사용 시 API 인증 흐름

다음 그림은 카카오 API 서비스에 접근하기 위해 OAuth 2.0 인증의 흐름을 7 단계로 나타냅니다.

0, 카카오 서비스를 이용하려면 사전에 앱을 등록 후 앱의 API 키를 발급받아야 합니다.


1, 카카오 서비스에 접근하기 위해 카카오 로그인 페이지를 웹브라우저에 표시합니다.


2, 사용자는 로그인 페이지에 ID, 비밀번호를 입력해 인증을 요청합니다.


3, 카카오 인증서버는 사용자를 인증하고 사용자 인증완료 페이지로 리다이렉션합니다. 이때 인증 코드를 함께 전달합니다.


4, 애플리케이션은 리다이렉션 URL을 분석해 인증코드를 획득합니다.


5, 애플리케이션은 카카오 인증서버에 제대로 인증된 사용자인지 확인 요청을 합니다.


6, 카카오 인증서버는 인증된 사용자임을 확인하고, 엑세스 토큰(Access Token)을 발급합니다.


7, 애플리케이션은 발급받은 엑세스 토큰을 이용해 카카오 API 서버에 접근합니다.



델파이로 OAuth 2.0 구현

위의 API 흐름을 카카오 OAuth와 카카오톡 프로필과 연동하는 과정을 델파이를 통해 구현해봅니다.


다음과 같은 데모를 구현합니다.


구현 과정은 크게 준비 + 3단계로 구분됩니다.

[준비] 카카오 서비스에 앱 등록 및 API 키 발급

[1단계] 인증페이지에 로그인 해 인증코드 취득

[2단계] 인증코드로 엑세스 토큰 취득

[3단계] 엑세스 토큰으로 서비스 접근


[준비] 앱 등록 및 API 키 발급

카카오 서비스를 이용하기 위해서는 사전에 앱을 등록 후 API 키를 발급받는 과정이 필요합니다.
다음 링크를 방문해 앱을 생성하고, REST API 키를 획득합니다.

앱 만들기

앱 이름을 입력하고 [앱 만들기] 버튼을 클릭합니다.

앱을 생성하면 다음 그림과 같이 키가 생성됩니다. 우리는 REST API 키를 사용할 것이므로 REST API 키를 복사해 보관해 둡니다.

하단의 설정 링크를 눌러 상세 설정화면으로 이동합니다.


플랫폼 추가

기본 정보 화면에서 [플랫폼 추가] 버튼을 누릅니다.


웹을 선택하고, 여러분들의 사이트 도메인을 입력합니다. [추가] 버튼을 누릅니다.


사이트 도메인과 Redirect Path를 확인 후 [저장] 버튼을 누릅니다.

사이트 도메인 + Redirect Path(저의 경우 http://hjf.pe.kr/oauth)는 실제 존재하는 페이지를 지정해야 합니다.

이 페이지는 카카오 로그인 후 리다이렉션되는 페이지로 아무 기능이 없더라도 페이지를 생성해 놔야 합니다.(페이지가 없으면 404 not found 오류가 발생합니다.)


운영하는 서비스가 없이 테스트 목적이라면 제 도메인을 등록하도록 합니다.(하지만 언제든 페이지를 삭제할 수 있으니 테스트 목적으로만 사용하시기 바랍니다.)


사용자 관리 활성화

사용자 관리 메뉴로 이동 후, 사용자 관리를 활성화 합니다. 

우리는 카카오 프로필 정보에 접근할 것이므로 프로필 정보 하단의 수집목적을 적절히 입력하고, [설정] 버튼을 클릭합니다.


앱 등록 및 API 키 발급 과정이 완료되었습니다.


[준비] 프로젝트 생성 및 화면 구성

이 예제는 델파이 10.3 리오 버전을 이용해 작성되었습니다. XE5이후 버전에서 문제가 없을것으로 생각됩니다. 다른 버전으로 진행 시 문제가 있다면 댓글을 통해 문의 주시기 바랍니다.

이 예제는 Multi-device Application(FMX 프레임워크)로 작성합니다. VCL Form Application으로 진행 가능하지만, 일부 속성 및 메소드, 이벤트에 차이가 있을 수 있습니다.

File > New > Multi-Device Application 메뉴를 선택 후 Blank Application을 선택 해 프로젝트를 생성합니다.

다음 화면을 참고해 화면을 구성합니다.


[1단계] 로그인 및 인증코드 취득

카카오 인증서버에 로그인 후 인증코드를 받는 과정을 개발합니다.(위의 API 인증 흐름의 1~4 단계 과정입니다.)


카카오 개발가이드 중 사용자 관리-로그인 부분의 문서를 참고해 개발합니다.


[Request]


[Response]


Request와 같이 페에지를 표시 후 사용자 로그인 성공 시 Response와 같이 redirect_url로 페이지 이동됩니다. 이때 인증 코드(authorize_code)가 함께 전달됩니다.


Button1 클릭 이벤트에 다음과 같이 코드를 입력합니다.

procedure TForm1.Button1Click(Sender: TObject);
var
  url: string;
  param: string;
begin
  Edit1.Text := '';

  url := 'https://kauth.kakao.com';
  param := '/oauth/authorize?client_id={app_key}&redirect_uri={redirect_uri}&response_type=code';
  param := param.Replace('{app_key}', API_KEY);
  param := param.Replace('{redirect_uri}', 'http://hjf.pe.kr/oauth');

  WebBrowser1.URL := url + param;
  WebBrowser1.Navigate;
end;

API_KEY는 상수로 implementation 위에 등록했습니다.(앱 생성 시 등록한 REST API 키를 XXXXX 대신 입력합니다.)

const
  // 카카오톡 개발자 사이트에서 앱 등록 후 API키를 등록하세요.
  API_KEY = 'XXXXXXXXXXXXXXXXX';

implementation

로그인 성공 시 인증코드 수신하는 내용을 작성합니다. WebBrowser1의 OnDidFinishLoad(페이지 전환 완료) 이벤트 생성 후 다음 코드를 입력합니다.

procedure TForm1.WebBrowser1DidFinishLoad(ASender: TObject);
var
  url: string;
  code: string;
begin
  Memo1.Lines.Add('WebBrowser1DidFinishLoad' + WebBrowser1.URL);

  if Edit1.Text <> '' then
    Exit;

  url := WebBrowser1.URL;

  if Pos('code=', url) > 0 then
  begin
    code := Copy(url, Pos('code=', url) + Length('code='), Length(url));
    if Pos('&', code) > 0 then
      code := Copy(code, 1, Pos('&', code)-1);

    Edit1.Text := code;
  end;
end;

제일 첫줄은 URL을 메모에 출력하는 로그성 기능입니다.


13~20줄에서 변경된 URL 중 인증코드 파라메터("code=")가 있는 경우 인증코드 값을 가져와 Edit1.Text에 설정합니다.


[2단계] 엑세스 토큰 취득

인증코드를 받은 다음, 이를 이용해 실제로 API를 호출할 수 있는 엑세스 토큰(Access Token)을 받아오는 내용을 구현합니다.


이 부분도 카카오 개발가이드 중 사용자 관리-로그인, 사용자 토큰 받기 부분의 문서를 참고해 개발합니다.


[Request]


[Response]


위 문서와 같이 POST로 요청 후 받은 응답 값(json 포맷)에서 access_token 값을 취득해야 합니다.

이 기능은 REST Client 프레임워크를 이용해 개발합니다.


화면에 TRESTClient, TRESTRequest, TRESTResponse 3개의 컴포넌트를 추가 합니다.


[3. 엑세스 토큰 취득] 버튼의 클릭 이벤트에 다음과 같이 구현합니다.
(아래 과정은 디자인 타임에서 컴포넌트에 직접 설정해도 무관합니다.)

procedure TForm1.Button2Click(Sender: TObject);
var
  token: string;
begin
  RESTClient1.BaseURL := 'https://kauth.kakao.com/';

  RESTRequest1.Resource := 'oauth/token';
  RESTRequest1.Method := rmPOST;
  RESTRequest1.Params.Clear;
  RESTRequest1.Params.AddItem('grant_type',   'authorization_code');
  RESTRequest1.Params.AddItem('client_id',    API_KEY);
  RESTRequest1.Params.AddItem('redirect_uri', 'http://hjf.pe.kr/oauth');
  RESTRequest1.Params.AddItem('code',         Edit1.Text);

  RESTRequest1.Execute;

  Memo1.Lines.Text := RESTResponse1.Content;

  if RESTResponse1.JSONValue.TryGetValue<string>('access_token', token) then
    Edit2.Text := token;
end;

개발가이드와 같이 요청 정보를 RESTClient와 RESTRequest 컴포넌트의 속성과 파라메터에 설정한 후 실행(RESTRequest1.Execute;) 후 받은 응답에서 엑세스 토큰(access_token)을 받아 Edit2.Text에 설정합니다.


엑세스 토큰을 받는 과정까지 마쳤습니다. 이제 엑세스 토큰을 이용해 카카오톡 프로필 정보에 접근해 데이터를 연동 할 수 있습니다.


[3단계] 카카오톡 프로필과 연동

엑세스 토큰을 얻었다면 카카오톡 프로필 서비스와 연동해 프로필 정보를 받아올 수 있습니다.


카카오 개발가이드 중 카카오톡-프로필요청 부분의 문서를 참고해 개발합니다.



[Request]


[Response]


위 문서와 같이 GET으로 요청 후 프로필 정보와 프로필 이미지 정보를 받아올 수 있습니다.
주의사항은 요청 시 Authorization 항목이 포함되어 권한 컴포넌트를 하나더 사용합니다.

화면에 TRESTClient, TRESTRequest, TRESTResponse, TOAuth2Authenticator 4개의 컴포넌트를 추가 합니다.


그리고, 프로필 이미지를 받기 위한 컴포넌트를 화면에 추가합니다.

[4, 카카오톡 프로필 조회] 버튼의 클릭 이벤트에 다음과 같이 구현합니다.

procedure TForm1.Button3Click(Sender: TObject);
var
  Url: string;
  Stream: TMemoryStream;
begin
  OAuth2Authenticator1.AccessToken := Edit2.Text;

  RESTClient2.BaseURL := 'https://kapi.kakao.com/';
  RESTClient2.Authenticator := OAuth2Authenticator1;

  RESTRequest2.Client := RESTClient2;
  RESTRequest2.Response := RESTResponse2;

  RESTRequest2.Resource := 'v1/api/talk/profile';
  RESTRequest2.Execute;

  Memo1.Lines.Text := RESTResponse2.Content;

  Url := RESTResponse2.JSONValue.GetValue<string>('profileImageURL');

  RESTClient3.BaseURL := Url;
  RESTClient3.Authenticator := OAuth2Authenticator1;
  RESTRequest3.ExecuteAsync(procedure
    begin
      Stream := TMemoryStream.Create;
      try
        Stream.WriteData(RESTResponse3.RawBytes, RESTResponse3.ContentLength);
        ImageControl1.Bitmap.LoadFromStream(Stream);
      finally
        Stream.Free;
      end;
    end
  );
end;

6번째 라인에서 권한 컴포넌트에 엑세스 토큰을 설정합니다.


8~17 라인에서 프로필 정보를 요청하고, 응답받은 컨텐츠 내용을 메모에 출력합니다.


19번째 라인에서 프로필 이미지 URL을 추출합니다.


21~33 라인에서는 프로필 이미지를 비동기(Async)로 받아 이미지 컨트롤에 표시합니다.


완료 및 테스트

카카오톡 프로필과 연동하는 예제 구현이 완료되었습니다.

작성한 프로젝트를 실행해 여러분의 카카오 계정을 이용해 테스트 진행할 수 있습니다.

완성된 프로젝트 파일

추가 학습할 내용

카카오 서비스 연동 및 인증(OAuth 2.0)은 REST API 기반으로 구현됩니다. 다음 글들을 통해 REST API를 이해하고 실습할 수 있습니다.
REST 클라이언트에 대한 개념을 아래 글을 통해 습득하실 수 있습니다.

관련/참고 링크


험프리.김현수 데이터 엑세스

RFID 리더(한미IT RF Prisma) 연동하기 - 델파이에서 JAR 이용

2017.12.19 09:17

(아래 내용은 델파이 10.2 도쿄 릴리즈 1과 릴리즈 2에서 작성된 내용으로 다른 버전에서는 일부 내용이 다를 수 있습니다.)


개발 컨설팅을 통해 의뢰한 작업 중 RFID 리더 연동한 내용 공유합니다.

(3일간의 개발 컨설팅으로 RFID 리더, TMAP 연동, 원격 데이터 연동 기술을 전파하는 작업을 진행했습니다.)


RFID 리더와 연동은 제조사에서 제공하는 라이브러리(안드로이드 JAR)를 이용했습니다.

이 과정을 통해 델파이에서 JAR 파일 연동하는 내용을 확인할 수 있습니다.


RFID 리더 연동



위 영상의 RFID 리더는 RFID 태그의 값을 읽고, 바코드의 값을 읽어 안드로이드 앱에 데이터를 전달합니다.

안드로이드 앱은 장비를 구동 및 설정하고, 장비가 읽은 데이터를 받아 화면에 표시합니다.


안드로이드 앱은 델파이(파이어몽키)를 이용해 개발했으며, 장비와 연동하는 부분은 제조사에서 제공한 JAR 형태의 라이브러리를 이용했습니다.


델파이에서 JAR 파일 연동 과정은 아래와 같습니다

1, 작업 준비

2, 델파이용 JAR 브릿지 파일 생성

3, 델파이 프로젝트에 JAR 파일 추가

4, 브릿지 파일로 JAR 연동 코드 작성


기타  참고사항

 - 안드로이드 연동 시 참고사항

 - 프레임을 이용해 재사용 가능한 화면 제작

샘플 프로젝트


작업 준비

대상 장비 - 한미IT RF Prisma


한미IT RF Prisma

제품 링크 : http://www.hanmiit.co.kr/hanmiit/handler/Main-Start


제품 문의

한미IT영업 임상기과장 skyoflsk@hanmi.co.kr


라이브러리 준비 및 분석

위 제품 링크 페이지에서 SDK Download 메뉴를 이용해 SDK 관련 파일을 제공합니다.

(안드로이드, iOS, 윈도우용 라이브러리를 제공합니다. 이글에서는 안드로이드 라이브러리만 다룹니다.)


다운로드 받은 압축파일에는 SDK 파일과 문서, 샘플이 포함되어 있습니다.

(앱스토어에서 RFPrisma로 검색 해 샘플 앱을 설치할 수 있습니다.)

문서와 샘플을 통해 제공하는 기능을 확인하고, 대략적인 사용법을 익히도록 합니다. 특히 라이브러리를 호출하는 부분은 정확히 숙지해야 합니다.


델파이용 JAR 브릿지 파일 생성

델파이에서 JAR 파일을 연동하기 위해 브릿지 파일(JAR 파일에 대한 델파이 인터페이스)을 생성해야 합니다.

브릿지 파일 생성

Java2OP.exe를 이용 델파이 브릿지 파일을 생성합니다. Java2OP는 JAR 파일 또는 Java 소스파일을 호출할 수 있는 델파이 코드를 생성합니다.(참고: 파이어몽키에서 외부 라이브러리 연동하기(jar. so, a))


아래 커맨드를 이용 브리지 파일(Androidapi.JNI.rfidreaderapi.pas)을 생성합니다.
set path=%PATH%;"c:\Program Files (x86)\Embarcadero\Studio\19.0\bin\converters\java2op"

java2op -jar ..\SDK\rfid.reader.api.jar -unit Androidapi.JNI.rfidreaderapi
위 코드를 명령 프롬프트에서 바로 입력 및 실행하거나, 배치파일(*.bat)로 실행할 수 있습니다.
(*.jar 파일의 경로를 상대경로로 입력 시 주의하시기 바랍니다. 절대경로를 이용해도 됩니다.)

델파이 프로젝트에 JAR 파일 추가

라이브러리 추가

멀티-디바이스 애플리케이션(파이어몽키) 프로젝트에서 타겟 플랫폼을 안드로이드로 설정 후 트리를 펼쳐 Libraries 항목에 JAR 파일을 추가해야 합니다.

델파이 브릿지 파일 추가

JAR와 연동하기 위해 델파이 브릿지 파일(Androidapi.JNI.rfidreaderapi.pas)을 프로젝트에 추가합니다.

브릿지 파일 확인을 위해 컴파일 후 오류를 조치합니다.


만약, 컴파일 시 E2029 오류 발생 시 다음을 참고해 조치합니다.

E2029 오류 조치방법

E2029 오류는 예약어를 용도와 다른 곳에서 사용할 경우 발생합니다.

오류가 발생하는 예약어 키워드 앞에 "&"을 추가해 해결합니다.

(예> type -> &type, in -> &in)

(참고: http://tech.devgear.co.kr/delphi_qna/420082)


브릿지 파일로 JAR 연동 코드 작성

JAR와 연동하는 코드는 아래와 같이 클래스를 이용해 작성했습니다.

FMX.HanmiIT.RFIDReader.pas


구현한 내용 중 다음 내용을 살펴보겠습니다.

1, 인스턴스 메소드와 클래스 메소드 접근

2, 자바 이벤트 리스너 설정


인스턴스 메소드와 클래스 메소드 접근

RF Prisma JAR 라이브러리에는 독특하게 클래스 메소드를 많이 사용하도록 구현되어 있습니다.


연동 시 델파이 클래스(TJATRfidManager)는 클래스 인터페이스(JATRfidManagerClass)와 인스턴스 인터페이스(JATRfidManager) 쌍으로 이뤄집니다. 

클래스 인터페이스(JATRfidManagerClass)는 객체를 생성하기 전의 클래스를 통해 접근하는 함수, 속성, 상수를 제공합니다. 자바코드를 사용하는 경우 "델파이클래스명.JavaClass.클래스메소드" 형식으로 JavaClass 속성을 통해 자바 클래스에 접근해야 합니다.

인스턴스 인터페이스(JATRfidManager)는 객체 생성 후 사용가능한 인스턴스 함수와 속성 상수를 제공합니다.

이 라이브러리에는 객체(JATRfidReader 등) 생성 시 아래와 클래스 메소드를 이용합니다. 해당 객체의 추가 기능은 인스턴스 메소드로 제공합니다.
var
  FReader: JATRfidReader;
...
  FReader := TJATRfidManager.JavaClass.getInstance;

  FReader.setEventListener(FEventListener);
  FReader.connectDevice(StringToJString(AAddress));
  FReader.setStoredMode(Value);
  FReader.setReportMode(Value);

자바 이벤트 리스너 설정

연동 시 가장 우려하던 부분입니다. RFID 태그를 읽거나 연결상태 가 변경되는 등 장비에서 동작해 발생하는 이벤트 정보를 리스너(JATRfidEventListener)를 통해 앱에서 받습니다.


리스너 구현시 메인 클래스(TRfidReader)에서 바로 리스너 인터페이스를 위임받아 구현해도 되지만, 복잡해 지기 때문에 별도의 클래스에서 이벤트 리스너를 구현하고 필요한 정보만 받도록  분리해 구현했습니다.


이벤트 리스너 구현 선언부

type
  TRfidEventListner = class(TJavaLocal, JATRfidEventListener)
  private
    FHandler: IRfidEventHandler;
  public
    constructor Create(AHandler: IRfidEventHandler);

    { JATRfidEventListenerClass }
    procedure onAccessResult(P1: JATRfidReader; P2: Jtype_ResultCode; P3: JActionState; P4: JString; P5: JString; P6: Single; P7: Single); cdecl;
    procedure onActionChanged(P1: JATRfidReader; P2: JActionState); cdecl;
    procedure onCommandComplete(P1: JATRfidReader; P2: JCommandType); cdecl;
    procedure onDebugMessage(P1: JATRfidReader; P2: JString); cdecl;
    procedure onDetactBarcode(P1: JATRfidReader; P2: JBarcodeType; P3: JString; P4: JString); cdecl;
    procedure onLoadTag(P1: JATRfidReader; P2: JString); cdecl;
    procedure onReadedTag(P1: JATRfidReader; P2: JActionState; P3: JString; P4: Single; P5: Single); cdecl;
    procedure onRemoteKeyStateChanged(P1: JATRfidReader; P2: JRemoteKeyState); cdecl;
    procedure onStateChanged(P1: JATRfidReader; P2: JConnectionState); cdecl;
  end;

위와 같이 JTARfidEventListener 인터페이스를 위임받고, 해당 인터페이스의 함수를 정의합니다.


주의할 사항은 Create 메소드의 파라메터로 IRfidEventHandler 인터페이스를 받아 FHandler에 저장하도록 구현합니다.


델파이 이벤트 인터페이스 선언부

IRfidEventHandler는 아래와 같이 필요한 메소드만 정의했습니다. 특히 파라메터는 사용하기 편하도록 델파이 자료형으로 재정의 했습니다.

type
  IRfidEventHandler = interface
  ['{FFEB910C-3BB8-48CA-BE11-B09CC07E53AC}']
    // Rfid Reader
    procedure ReadedTag(AReader: JATRfidReader; ATag: string);
    procedure StateChagned(AReader: JATRfidReader; AState: TConnectionState);

    // Barcode
    procedure ActionChagned(AReader: JATRfidReader; AState: TActionState);
    procedure DetactBarcode(AReader: JATRfidReader; ABarcodeType, ACodeId, ABarcode: string);
  end;


메인 클래스에서 델파이 이벤트 인터페이스 위임
위 인터페이스는 메인 클래스에서 위임받았고, 이벤트 핸들러 생성 시 파라메터로 전달합니다.
그리고, FReader 객체에 이벤트 리스너를 설정(setEventListener)합니다.
type
  TRFIDReader = class(TInterfacedObject, IRfidEventHandler)
...
procedure TRFIDReader.InitReader;
begin
...
  FEventListener := TRfidEventListner.Create(Self);
...
  FReader := TJATRfidManager.JavaClass.getInstance;
  FReader.setEventListener(FEventListener);
end;

이벤트 발생 시 델파이 이벤트 인터페스를 통해 전달
JATRfidEventListener에서 이벤트 발생 시 IRfidEventHandler에 이벤트를 전달하도록 구현했습니다.
procedure TRfidEventListner.onStateChanged(P1: JATRfidReader;
  P2: JConnectionState);
var
  State: TConnectionState;
begin
  if Assigned(FHandler) then
  begin
    State := TConnectionState.Disconnected;
    if P2.getState = TJConnectionState.JavaClass.Connected.getState then
      State := TConnectionState.Connected
    else if P2.getState = TJConnectionState.JavaClass.Connecting.getState then
      State := TConnectionState.Connecting
    else if P2.getState = TJConnectionState.JavaClass.Listen.getState then
      State := TConnectionState.Listen
    ;

    FHandler.StateChagned(P1, State);
  end;
end;

이후 이벤트 정보를 받은 메인 클래스에서 비지니스 로직을 수행하도록 구현합니다.

기타 참고사항

안드로이드 연동 시 참고사항

가장 좋은 참고자료는 파이어몽키에 구현된 안드로이드 연동한 내용을 참고하는 것입니다.

(델파이 정품 설치 시 설치경로 하위의 source 디렉토리에는 파이어몽키 라이브러리 소스코들이 포함되어 있습니다.)


그중 다음 소스코드들을 참고하면 아주 좋습니다.

안드로이드 SDK 브릿지 파일

기본 안드로이드 SDK 델파이 브릿지 파일이 아래 경로에 포함되어 있습니다.
  • C:\Program Files (x86)\Embarcadero\Studio\19.0\source\rtl\android - 10.2 도쿄 기준

파이어몽키 라이브러리

파이어몽키 컴포넌트와 라이브러리 등을 어떻게 구현했는지 아래 경로의 파일들에서 살펴볼 수 있습니다.

  • C:\Program Files (x86)\Embarcadero\Studio\19.0\source\fmx - 10.2 도쿄 기준


프레임을 이용해 재사용 가능한 화면 제작

일부 기능적인 화면들이 필요한데 다른 프로젝트에서도 활용할 만한 기능들이어서 재사용 가능하도록 구현해봤습니다.

libs 디렉토리에 포함된 3개의 프레임입니다.

  • FMX.UI.OverflowMenu.pas - 메인 화면의 우측 상단의 연결 팝업 메뉴 구현
  • FMX.UI.SelectBluetoothDeviceDialog.pas - 블루투스 장비를 탐색 후 장비 선택 정보 제공하도록 구현
  • FMX.UI.WaitDialog.pas - 비동기로 진행하는 블루투스 장비 연결을 기다리는 화면
프레임을 사용한 이유는 화면의 일부 영역을 표현하기 위함입니다.
프레임은 화면을 포함한 객체입니다.(Create, Destroy, Show, Hide 이벤트 등을 제공하지 않아 필요한 경우 직접 구현해야 합니다.)
화면등에서 객채 생성하는 코드를 줄이기 위해 클래스 메소드로 기능 호출하도록 구현했습니다.

클래스 메소드로 기능화면 호출
위 유닛 파일을 유즈절(uses)에 추가 후 아래와 같이 기능을 호출할 수 있습니다.
  TWaitDialog.Show('블루투스를 활성화 합니다.', 2000);

  TOverflowMenu.Settings.Top := ToolBar1.Height + 1;
  TOverflowMenu.Settings.Width := Width * 0.9;
  TOverflowMenu.Settings.RightPadding := 10;
  TOverflowMenu.ShowMenu([
      'Connect to last bluetooth device',
      'Connect to new bluetooth device'],
    procedure(AIndex: Integer; AText: string)
    begin
      case AIndex of
        0: ConnectToLastDevice;
        1: ConnectToNewDevice;
      end;
    end);

자세한 별도의 글을 통해 소개하도록 하겠습니다.(그 전에는 직접 소스코드를 통해 내용을 확인하시기 바랍니다.)

기타 궁금한 내용은 댓글 또는 http://blog.hjf.pe.kr/482의 댓글을 참고하거나 등록해 주세요.


험프리.김현수 파이어몽키

  1. 블루투스 바코드 스캐너(BI-07) 안드로이드 라이브러리를 델파이에서 연동하는 방법( http://blog.hjf.pe.kr/452 )도 참고하시기 바랍니다.

  2. Blog Icon
    주만지

    와와와.. 저희 회사도 rfid 연동하는데 시간 날때 한번 해봐야 겠어여
    한국엔 라드 자료가 많이 없는데 우연히 구글링하다 들어와서 잘 보고 갑니다^^*
    네이버라면 친추하겠는데,,ㅠ
    혹시 가끔 모르는 거 들어와서 여쭤 봐도 될까요? ㅋ

WaitDialog 구현 - 재사용 가능한 프레임 구현하기

2017.12.06 13:36

얼마전 진행한 모바일 개발 컨설팅에서 블루투스 장비와 연결 후 기다리는 동안 표시할 화면이 필요했습니다.

WaitDialog라는 화면을 만들었는데 이 화면은 앞으로도 많이 사용하게 될 것 같아 TFrame을 이용해 재사용 가능하도록 구현해 봤습니다.


WaitDialg 구현에 아래 기술을 사용했습니다.

1) TFrame

2) 클래스 메소드

3) 싱글톤 패턴


이 내용을 학습하면

1) 자주 사용하는 화면을 프레임으로 제작 해 재사용 할 수 있습니다.

2) 클래스 메소드를 활용해 코드를 짧게 사용 할 수 있습니다.

결과화면

결과 화면은 아래와 같습니다.


구현한 내용

화면구성

파이어몽키 프레임을 이용해 WaitDialog 화면을 구성했습니다.

파이어몽키에서 TFrame은 폼디자이너에서 화면을 구성할 수 있는 객체입니다. UI 컴포넌트와 논비주얼 컴포넌트를 화면에 추가하고 사용할 수 있습니다.


WaitDialog 코드

type
  TWaitDialog = class(TFrame)
    rctBackground: TRectangle;
    lytMessage: TLayout;
    rctMessageBG: TRectangle;
    lblMessage: TLabel;
    AniIndicator1: TAniIndicator;
    Timer: TTimer;
    procedure TimerTimer(Sender: TObject);
  private
    class var FInstance: TWaitDialog;
  private
    { Private declarations }
  public
    { Public declarations }
    destructor Destroy; override;

    class procedure Show(ATitle: string = ''; ATimeout: Integer = -1);
    class procedure Hide;
  end;

implementation

{$R *.fmx}

{ TFrame1 }

class procedure TWaitDialog.Show(ATitle: string; ATimeout: Integer);
begin
  if not Assigned(FInstance) then
    FInstance := Create(nil);

  FInstance.Parent := Application.MainForm;
  FInstance.Align := TAlignLayout.Client;
  FInstance.BringToFront;
  FInstance.Visible := True;

  if ATitle <> '' then
  begin
    FInstance.lblMessage.Text := ATitle;
  end;

  if ATimeout > 0 then
  begin
    if ATimeout < 1000 then
      ATimeout := 1000;
    FInstance.Timer.Interval := ATimeout;
    FInstance.Timer.Enabled := True;
  end;
end;

class procedure TWaitDialog.Hide;
begin
  if not Assigned(FInstance) then
    Exit;
  FInstance.Visible := False;
  FInstance.DisposeOf;
end;

procedure TWaitDialog.TimerTimer(Sender: TObject);
begin
  Timer.Enabled := False;
  Hide;
end;

destructor TWaitDialog.Destroy;
begin
  FInstance := nil;

  inherited;
end;

initialization
finalization
  TWaitDialog.Hide;

클래스 메소드

WaitDialog를 보여주고 감추는 메소드(Show, Hide)를 클래스 메소드(class procedure, class function)로 구현했습니다.

클래스 메소드는 클래스를 생성하기 전에 호출할 수 있는 메소드로 Create 등이 대표적인 클래스 메소드입니다.


클래스 메소드를 사용한 이유는 WaitDialog를 호출하는 측의 코드를 최대한 짧게 작성할 수 있도록 하기위해서 입니다.


싱글톤 패턴

클래스 메소드를 사용 후 객체를 생성하기 위해 클래스 변수(class var)를 사용했습니다. 


객체 생성은 Show 메소드에서, 객체 해제는 Hide 메소드에서 합니다. Hide 시키지 않고 앱을 종료하는 경우를 대비 finalization에서 Hide 메소드를 호출 합니다.


싱글톤 패턴은 프로그램 내에서 객체를 하나만 생성하는 디자인 패턴입니다. 위 예제에서 객체는 하나만 생성합니다.

만약, 다른 곳에서 싱글톤 객체가 필요하다면 아래와 같은 코드를 추가할 수 있습니다.

class function TWaitDialog.Instance: TWaitDialog; begin if not Assigned(FInstance) then FInstance := Create; Result := FInstance; end; class procedure TWaitDialog.ReleaseInstance; begin if Assigned(FInstance) then FInstance.DisposeOf; end; initialization finalization TWaitDialog.ReleaseInstance;

위와 같이 구현하면 TWaitDialog.Instance를 이용해 접근하면 객체를 유일하게 사용할 수 있습니다.(너무 멀리까지 나갔네요.^^)

사용방법

uses FMX.WaitDialog;

  TWaitDialog.Show;
  TWaitDialog.Show('잠시만 기다려 주세요.');
  TWaitDialog.Show('잠시만 기다려 주세요.', 10000);

  TWaitDialog.Hide;

uses 절에 유닛을 추가하고, Show 클래스 메소드를 다양한 방식으로 호출해 화면을 표시합니다.

비동기 동작이 완료된 경우 Hide 클래스 메소드를 호출하면 화면이 감춰집니다.


데모 프로젝트

WaitDialog.zip


험프리.김현수 파이어몽키

[튜토리얼] 메일 전송(IdSMTP 이용)

2017.11.22 14:27

IdSMTP, IdMessage를 이용 메일 전송 예제


참고코드

procedure TForm2.Button1Click(Sender: TObject);
begin
  SMTP.Host := ''; // host address
  SMTP.Port := 25;

  MailMessage.From.Address := ''; // From email address
  MailMessage.Recipients.EMailAddresses := Edit2.Text;//'hskim@embarcadero.kr';

  MailMessage.Subject := Edit1.Text;
  MailMessage.Body.Text := Memo1.Lines.Text;
  MailMessage.CharSet := 'UTF-8';
  SMTP.Connect;
  SMTP.Send(MailMessage);
  if SMTP.Connected then
    SMTP.Disconnect;

  ShowMessage('');
end;

샘플 프로젝트

SendMail.zip


문단제목




험프리.김현수 Delphi/C++Builder

  1. 파일 첨부
    // uses IdAttachmentFile;
    MailMessage.MessageParts.Clear;
    TIdAttachmentFile.Create(MailMessage.MessageParts, Filename);

  2. 감사합니다 ~~~

[튜토리얼] FTP 업로드(TIdFTP 이용)

2017.11.22 14:24

IdFTP를 이용 로컬 파일을 서버로 업로드하는 예제

  • 로컬파일 선택
  • 업로드 시 프로그레스바로 진행률 표시

참고 코드

procedure TForm2.Button1Click(Sender: TObject);
begin
  if OpenDialog1.Execute then
    Edit1.Text := OpenDialog1.FileName;
end;

procedure TForm2.Button2Click(Sender: TObject);
var
  LocalPath, RemotePath: string;
begin
  LocalPath := Edit1.Text;
  RemotePath := 'test/' + ExtractFileName(LocalPath);

  IdFTP1.Host := 'hjf.pe.kr';
  IdFTP1.Port := 21;
  IdFTP1.Passive := True;
  IdFTP1.Username := '';  // FTP user
  IdFTP1.Password := '';  // FTP password
  IdFTP1.Connect;

  IdFTP1.Put(LocalPath, RemotePath);

  IdFTP1.Disconnect;
end;

procedure TForm2.IdFTP1Work(ASender: TObject; AWorkMode: TWorkMode;
  AWorkCount: Int64);
begin
  ProgressBar1.Position := AWorkCount;
end;

procedure TForm2.IdFTP1WorkBegin(ASender: TObject; AWorkMode: TWorkMode;
  AWorkCountMax: Int64);
begin
  ProgressBar1.Max := AWorkCountMax;
end;

샘플 프로젝트

IdFTPUpload.zip


문단제목





험프리.김현수 Delphi/C++Builder

델파이/C++빌더에 TTcpClient, TTcpServer, TUdpSocket 등록하기

2017.11.02 14:30

TTcpClient, TTcpServer, TUdpSocket 컴포넌트 들이 어느 버전에서 부터인지 모르지만, 기본 컴포넌트에서 빠져있습니다.


위 3개 소켓 컴포넌트를 등록하는 방법을 안내합니다.

(이 글은 RAD Studio 10.2 도쿄 버전을 기준으로 안내합니다.)


1, 윈도우 탐색기로 열고 다음 경로(기본 샘플 경로)로 이동합니다.

C:\Users\Public\Documents\Embarcadero\Studio\19.0\Samples\Object Pascal\VCL\InetWinSockets


2, RAD Studio에서 "inetwinsockets.dpk" 프로젝트를 엽니다.


3, 프로젝트 매니저의 팝업 메뉴에서 Install 메뉴를 선택 해 설치합니다.


4, 델파이 라이브러리 패스에 위 경로를 추가합니다. 

(또는 "Web.Win.Sockets.pas"를 델파이 라이브러리 패스에 포함된 곳에 복사합니다.)


5, 툴팔렛트의 "Internet" 카테고리에 컴포넌트 추가를 확인합니다.


만약, 컴포넌트 추가 후 컴파일 시 "Web.Win.Sockets" 유닛을 찾을 수 없다면 4 단계(라이브러리 패스에 추가)를 검토하시기 바랍니다.


관련링크







험프리.김현수 분류없음

안면인식(Face Detection) 라이브러리(안드로이드, iOS)

2017.10.30 15:02

델파이 개발 그룹인 grijjy 팀(블로그: https://blog.grijjy.com/)에서 안면인식(Face Detection) 라이브러리를 공개했습니다.


이 라이브러리리는 안드로이드와 iOS에 내장된 사진에서 얼굴을 감지하는 기능을 이용해, 하나의 라이브러리로 제공합니다.


안면인식 기술 개발이 필요하거나, 여러 플랫폼 기능을 하나의 라이브러리로 개발하고자 하는 경우 참고하면 아주 좋습니다.


안면인식(안드로이드, iOS)

  • https://blog.grijjy.com/2017/09/11/face-detection-on-android-and-ios/


험프리.김현수 Delphi/C++Builder

TTS(Text-to-Speech) 라이브러리(윈도우, 맥OS, iOS, 안드로이드)

2017.10.30 14:52

델파이 개발 그룹인 grijjy 팀(블로그: https://blog.grijjy.com/)에서 문자를 읽어주는 TTS(Text-to-speech) 라이브러리를 공개했습니다.


이 라이브러리는 윈도우, 맥OS, iOS, 안드로이드를 지원합니다.

(grijjy 팀에서 크로스 플랫폼 추상화 레이어 설계를 연습하기 위해 제작했으며, 각 플랫폼 API TTS 기능을 하나의 라이브러리(컴포넌트)로 제공합니다.)


해당 기능이 필요하거나, 공통된 여러 플랫폼의 API를 하나의 라이브러리(컴포넌트)로 제작하는 방법을 참고하면 아주 좋겠습니다.


Cross Platform Text-to-Speech

참고




험프리.김현수 Delphi/C++Builder

델파이로 빅데이터 데이터베이스 연동하기(Cassandra, Couchbase, MongoDB)

2017.10.30 14:32

델파이 개발 그룹인 grijjy 팀(블로그: https://blog.grijjy.com/)에서 빅데이터 데이터베이스에 직접 연동해 작업할 수 있는 델파이 라이브러리를 오픈소스로 공개하였습니다.


카산드라(Cassandra), 카우치베이스(Couchbase), 몽고DB(MongoDB) 총 3개의 빅데이터 데이터베이스 접근용 라이브러리이며, 해당 글에서는 친절하게 설치방법과 샘플 코드등을 자세히 설명합니다.


빅데이터 연동에 이슈가 있거나 관심이 있는 분들에게 큰 도움이 될 것으로 보입니다.

자세한 내용은 아래 링크를 통해 (영문으로)자세히 볼수 있습니다.


참고로, 몽고DB의 경우 델파이에 기본 내장된 FireDAC을 이용해 직접 접속할 수도 있습니다.

(하단에 관련 링크를 추가합니다.)


카산드라(Cassandra)

카산드라는 구글의 BigTable 컬럼 기반의 데이타 모델과 FaceBook에서 만든 Dynamo의 분산 모델을 기반으로 하여 제작되어 Facebook에 의해 2008년에 아파치 오픈소스로 공개된 분산 데이타 베이스 입니다. 
출처: http://bcho.tistory.com/440 [조대협의 블로그]

카우치베이스(Couchbase)

카우치베이스 서버(Couchbase Server)는 유연한 JSON 모델로 고정 데이터베이스 스키마의 제약 없이 쉽게 애플리케이션을 수정할 수 있으며, submilisecond (1/1000 ms 이하)의 초고속 데이터 입출력 처리의 높은 성능을 보장합니다. 또한, 간편한 스케일 아웃(scale-out)으로 다운타임 없이 시스템 구성 변경 및 확장을 지원합니다.

몽고DB(MongoDB)

몽고DB(MongoDB←HUMONGOUS)는 크로스 플랫폼 도큐먼트 지향 데이터베이스 시스템이다. NoSQL 데이터베이스로 분류되는 몽고DB는 JSON과 같은 동적 스키마형 문서들(몽고DB는 이러한 포맷을 BSON이라 부름)을 선호함에 따라 전통적인 테이블 기반 관계형 데이터베이스 구조의 사용을 삼간다. 이로써 특정한 종류의 애플리케이션을 더 쉽고 더 빠르게 데이터 통합을 가능케 한다.


참고로, 

몽고DB는 델파이에 기본 내장된 FireDAC을 통해 직접 연동할 수 있습니다.


험프리.김현수 Delphi/C++Builder

[FMX] TListView 더보기 버튼 구현하기

2017.09.20 13:49

모바일 앱을 개발할 때에 리스트 항목이 많은 경우, 한번에 가져오면 시간이 오래 걸려 좋지 않은 사용자 경험이 됩니다.


이 경우, 리스트 중 일부를 빠르게 표시하고, 리스트 끝으로 이동 시 추가로 표시하는 방식을 통해 문제를 해결할 수 있습니다.


이 글에서는, 

리스트뷰(TListView)의 목록 끝으로 이동 시, 더보기 버튼을 표시하도록 (매우 심플하게)구현합니다.

버튼 클릭 시 항목을 추가합니다.


이 글을 참고해 리스트 끝으로 이동 시 자동으로 항목을 추가하도록 구현할 수도 있습니다.


리스트뷰 더보기 버튼  구현하기

결과

결과 화면은 다음과 같습니다.


처음 24개 항목 표시 후, 목록 끝으로 이동 시 버튼이 표시되고, 버튼을 눌러 항목을 추가합니다.


구현방법

1) 더보기 버튼을 리스트뷰(TListView)에 올려놓고 감춥니다.(Visible := False)

2) 리스트뷰의 스크롤 이동(OnScrollViewChange) 이벤트 핸들러에서 제일 끝으로 이동한 경우 버튼을 표시합니다.


컴포넌트 구성은 아래와 같습니다.


구현된 주요 코드는 아래와 같습니다.

procedure TForm2.AddItem(ACount: Integer);
var
  I: Integer;
  Item: TListViewItem;
begin
  for I := 0 to ACOunt - 1 do
  begin
    Item := ListView1.Items.Add;
    Item.Text := 'Item ' + ListView1.Items.Count.ToString;
  end;
end;

procedure TForm2.FormCreate(Sender: TObject);
begin
  AddItem(24);
  btnListViewMore.Visible := False;
end;

procedure TForm2.btnListViewMoreClick(Sender: TObject);
begin
  AddItem(6);
  btnListViewMore.Visible := False;
end;

procedure TForm2.ListView1Resized(Sender: TObject);
begin
  ListView1ScrollViewChange(Sender);
end;

procedure TForm2.ListView1ScrollViewChange(Sender: TObject);
var
  LastItemBottom, ListViewBottom: Single;
begin
  LastItemBottom := ListView1.GetItemRect(ListView1.ItemCount - 1).Bottom;
  ListViewBottom := ListView1.LocalRect.Bottom;

  btnListViewMore.Visible := ((LastItemBottom - ListViewBottom) < 30);
end;


샘플 프로젝트

ListViewMoreButton.zip


이 샘플에서는 더보기 버튼 클릭 시 단순하게 목록을 추가했습니다. 실무에서는 더보기 버튼 클릭시 추가 데이터를 수신 후 목록을 동적으로 갱신하도록 구현해야 합니다.


당겨서 새로고침(Pull to refresh) 구현하기

모바일 앱에서는 새로운 정보를 가져오기 위해 당겨서 새로고침 기능을 사용할 수 있습니다.

이 기능은 리스트뷰(TListView)의 속성을 이용해 구현할 수 있습니다.


PullToRefresh 속성을 True로 설정 시, 목록 상단에서 당겨서 새로고침 기능을 제공합니다.

위 동작이 발생하면 OnPullRefresh 이벤트가 발생합니다.


참고링크


험프리.김현수 파이어몽키

[REST API] 다음 Kakao > 로컬 > 주소검색 연동하기

2017.09.18 15:06

다음 등의 포털 사에서는 자사 데이터 일부를 Open API로 공개하고 있습니다.

특히 지도나 주소, 검색 등은 직접 데이터를 수집하는 것보다 포털의 데이터를 활용하는 것이 개발 및 유지보수에 유리할 수 있습니다.


오늘은 데브기어 테크게시판을 통해 다음 카카오의 주소검색 API 연동을 문의주셔서 해당 내용을 공유합니다.


아래 샘플을 REST API를 이용해 카카오 주소 검색 Open API와 연동하는 내용입니다.

(카카오 Open API의 대부분은 REST API를 제공합니다. )


해당 내용을 잘 익혀서 다양한 Open API를 여러분의 앱에서 활용하실 수 있습니다.


카카오 개발자 > 로컬 : https://developers.kakao.com/docs/restapi/local


카카오 Open API를 연동하기 위해서는 앱을 등록하고, 앱 키를 받아야 합니다.(해당 내용의 설명은 생략합니다.)

카카오 개발자 > 내 애플리케이션 : https://developers.kakao.com/apps


위 링크를 참고해 개발했으며, 제일 문제가 됐던 부분은 HTTP 해더에 Authorization 값을 추가하는 부분입니다.


연동한 결과는 아래와 같습니다.


주요 코드는 아래와 같습니다.

uses
  REST.TYpes;

const
  API_KEY = '';
{
  https://developers.kakao.com/ 등록 > 앱 생성 > 앱키(REST API 키)를 위(API_KEY)에 입력
}

procedure TForm2.Button1Click(Sender: TObject);
begin
  RESTRequest1.Params.ParameterByName('query').Value := Edit1.Text;

  RESTRequest1.Execute;
end;

procedure TForm2.FormCreate(Sender: TObject);
var
  Param: TRESTRequestParameter;
begin
  RESTClient1.BaseURL := 'https://dapi.kakao.com';
  RESTClient1.Accept := 'application/json, text/plain; q=0.9, text/html;q=0.8,';
  RESTClient1.AcceptCharset := 'UTF-8, *;q=0.8';

  RESTRequest1.Resource := 'v2/local/search/address.json?query={query}';
  Param := RESTRequest1.Params.AddHeader('Authorization', 'KakaoAK ' + API_KEY);
  Param.Options := [TRESTRequestParameterOption.poDoNotEncode];

  RESTResponseDataSetAdapter1.RootElement := 'documents';
end;

샘플 프로젝트

KakaoLocalLocation.zip


문단제목



험프리.김현수 Delphi/C++Builder

[FMX] 폼의 높이를 애니메이션으로 변경하기, 툴바를 끌어 폼 이동하기

2017.09.12 15:59

약국용 라디오 어플을 개발하는 개발사에서는, 오래전부터 PC 기반으로만 라디오 서비스를 하고 있습니다.

해당 개발사에서는 노후된 앱을 최신 운영체제(윈도우 10 등) 지원과 모바일 확장을 위해 파이어몽키로 재개발 중입니다.

(파이어몽키는 윈도우, OSX, iOS, 안드로이드를 하나의 소스코드로 개발할 수 있습니다.)


개발 중 몇가지 질문을 주셔서 기술지원 후 해당 내용 일부를 공유합니다.


이 글에서는 다음 내용의 구현 방법을 소개합니다.

1, 폼의 일부영역 보이기/가리기(Collapse)

2, Border가 없는 폼에서 특정영역(Toolbar)을 마우스로 이동하기


결과 화면은 아래와 같습니다.

1, 폼의 일부영역 보이기/가리기(Collapse)

이 기능은 TFloatAnimation 컴포넌트를 사용해 손쉽게 구현할 수 있었습니다.

(파이어몽키에는 애니메이션과 효과를 기본 컴포넌트로 제공합니다.)


TFloatAnimation은 지정 된 시작과 끝 Float 값에 대해 애니메이션 되면 값이 변경할 수 있어, 크기, 위치, 각도, 투명도 등을 천천히 변경할 수 있습니다.


하지만, 폼의 높이(Height) 속성에는 FloatAnimaion을 지정할 수 없어, 폼에 레이아웃 컴포넌트를 놓고, 레이아웃 컴포넌트의 높이를 변경시키고, 변경 시 발생하는 OnProcess 이벤트에서 폼의 높이를 조정하도록 구현했습니다.


위 기능의 코드는 아래와 같습니다.

procedure TForm2.FormCreate(Sender: TObject);
begin
  Self.BorderStyle := TFmxFormBorderStyle.None;

  FOrgHeight := lytMain.Height;
end;

procedure TForm2.Button1Click(Sender: TObject);
begin
  lytMain.Align := TAlignLayout.None;
  FloatAnimation1.Duration := 0.5;
  if lytMain.Height = 0  then
  begin
    FloatAnimation1.StartValue := 0;
    FloatAnimation1.StopValue := FOrgHeight;
    FloatAnimation1.Start;
  end
  else
  begin
    FOrgHeight := lytMain.Height;
    FloatAnimation1.StartValue := FOrgHeight;
    FloatAnimation1.StopValue := 0;
    FloatAnimation1.Start;
  end;
end;

procedure TForm2.FloatAnimation1Finish(Sender: TObject);
begin
  lytMain.Align := TAlignLayout.Client;
end;

procedure TForm2.FloatAnimation1Process(Sender: TObject);
begin
  // 레이아웃 크기 조정 시 폼의 크기 조정
  Self.Height := Trunc(ToolBar1.Height + lytMain.Height) + 1;
end;


2, Border가 없는 폼에서 특정영역을 마우스로 이동하기

테두리가 없는 폼에서 제목등의 특정영역을 마우스로 끌어 이동하기 위해 다음 코드를 사용했습니다.

(해당 코드는 윈도우와 OSX(맥)에서 모두 동작합니다.)

procedure TForm2.ToolBar1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Single);
begin
  if (Button = TMouseButton.mbLeft) then StartWindowDrag;
end;




험프리.김현수 파이어몽키

[FMX] iOS 시스템 볼륨 제어하기

2017.09.08 15:21

엠바카데로 블로그에 HARUYUKI MOHRI가 작성한 C++빌더로 iOS 시스템 볼륨 제어하는 내용이 있어 델파이로 작업해 봤습니다.


원글 : https://community.embarcadero.com/blogs/entry/how-to-control-the-system-audio-volume-of-ios?utm_source=Facebook_Organic&utm_medium=social


아래와 같이 Up/Down 버튼을 누르면 시스템 볼륨을 제어합니다.




MPVolumeView 클래스(iOSapi.MediaPlayer.pas)와 UISlider 클래스(iOSapi.UIKit.pas)를 사용했습니다.


uses 절에 "iOSapi.MediaPlayer, iOSapi.UIKit" 추가해야 합니다.


다음 2개 변수를 선언해야 합니다.

  private
    { Private declarations }
    FMPVolumeView: MPVolumeView;
    FSlider: UISlider;

구현된 델파이 코드는 아래와 같습니다.

procedure TForm1.FormCreate(Sender: TObject);
var
  I, J: Integer;
begin
  FMPVolumeView := TMPVolumeView.Create;

  I := 0;
  J := FMPVolumeView.subviews.count;

  if I = J then
  begin
    log.d('');
  end;

  if FMPVolumeView.subviews.count > 0 then
  begin
    FSlider := TUISlider.Wrap(FMPVolumeView.subviews.objectAtIndex(0));
    FSlider.setValue(0.0);
  end;
end;

procedure TForm1.btnVolumeUpClick(Sender: TObject);
var
  Vol: Single;
begin
  Vol := FSlider.value;
  FSlider.setValue(Vol + 0.1);
end;

procedure TForm1.btnVolumeDownClick(Sender: TObject);
var
  Vol: Single;
begin
  Vol := FSlider.value;
  FSlider.setValue(Vol - 0.1);
end;


샘플 프로젝트

iOSVolumeControl.zip


참고 링크

험프리.김현수 분류없음

TListView 행별로 배경색 설정 및 글꼴변경하기

2017.09.08 10:56

리스트뷰(TListView)는 많은 데이터를 목록으로 표시하기 위한 컴포넌트입니다.

스와이프(스크롤) 속도가 빠른 대신 항목 구성하기가 까다롭습니다.


이번 글에서는 리스트뷰 표현 방식 중 DynamicAppearance(동적 외관구성)를 이용해 외관 구성 후, 아래 기능을 구현했습니다.

1) 표시 항목을 추가(현재 2개, 여러 항목 표시가능)

2) 조건에 따라 배경색상을 변경

3) 조건에 따라 글꼴 변경


결과 화면은 아래와 같습니다.

(아이폰에서는 "여자" 글꼴을 Bold로 주니 글자가 약간 커지네요.)



구현한 내용은 아래와 같습니다.

화면구성

대표 컴포넌트는 리스트뷰(TListView)와 이미지리스트(TImageList)입니다.

이미지 리스트에는 2개의 색상 이미지(16x16)를 추가했습니다.


리스트뷰의 ItemAppearance.ItemAppearance를 DynamicAppearance로 설정했습니다.


아이템 오브젝트는 문자를 표현할 Text 항목 2개와 배경을 표현할 Image 항목 총 3개로 구성했습니다.

(Image 항목을 추가한 이유는 Rectangle과 같은 도형을 지원했다면 도형의 배경으로 처리했겠지만, 지원하지 않아 이미지를 이용해 배경으로 처리했습니다.)


코드작성

코드의 주요 기능은 2가지 입니다.

1) 리스트뷰 아이템(TListViewItem)의 값에 따라 배경색 및 글꼴 설정

2) 리스트뷰 크기 변경(OnResized 이벤트) 시 항목너비 조정


참고로 리스트뷰 아이템 서식 변경의 경우 OnUpdateObjects 이벤트에서 처리했지만, 

코드로 목록을 추가하는 경우, 추가하는 시점에 서식을 설정할 수도 있습니다.

procedure TForm1.FormCreate(Sender: TObject);
begin
  ListView1.ItemSpaces := TBounds.Create(RectF(0, 0, 0, 0));
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Item: TListViewitem;
begin
  Item := ListView1.Items.Add;
  Item.Data['Text1'] := '김현수';
  Item.Data['Text2'] := '남자';
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  Item: TListViewitem;
begin
  Item := ListView1.Items.Add;
  Item.Data['Text1'] := '아이유';
  Item.Data['Text2'] := '여자';
//  (Item.Objects.ObjectByName('Image2') as TListItemImage).Bitmap := ImageList1.Bitmap(TSizeF.Create(16, 16), 1);
end;

function FindTextObject(const AListView: TListView; AName: string): TCommonObjectAppearance;
var
  Obj: TCommonObjectAppearance;
begin
  Result := nil;

  for Obj in AListView.ItemAppearanceObjects.ItemObjects.Objects do
  begin
    if Obj.Name = AName then
      Exit(Obj as TCustomTextObjectAppearance);
  end;
end;

procedure TForm1.ListView1Resized(Sender: TObject);
var
  Text1, Text2: TCommonObjectAppearance;
begin
  Text1 := FindTextObject(ListView1, 'Text1');
  Text2 := FindTextObject(ListView1, 'Text2');

  Text1.Width := ListView1.Width / 2;
  Text2.PlaceOffset.X := Text1.Width;
  Text2.Width := ListView1.Width / 2;
end;

procedure TForm1.ListView1UpdateObjects(const Sender: TObject;
  const AItem: TListViewItem);
var
  ImageItem: TListItemImage;
  TextItem: TListItemText;
begin
  ImageItem := AItem.Objects.DrawableByName('Image2') as TListItemImage;
  TextItem := AItem.Objects.DrawableByName('Text2') as TListItemText;

  if Assigned(ImageItem) then
  begin
    if AItem.Data['Text1'].ToString = '김현수' then
      ImageItem.Bitmap := ImageList1.Bitmap(TSizeF.Create(16, 16), 0)
    else
      ImageItem.Bitmap := ImageList1.Bitmap(TSizeF.Create(16, 16), 1)
    ;
    ImageItem.Visible := True;
  end;

  if Assigned(TextItem) then
  begin
    if Textitem.Text = '여자' then
      Textitem.Font.Style := [TFontStyle.fsBold, TFontStyle.fsItalic];
  end;
end;

샘플 프로젝트


위 구성은 리스트뷰 항목별로 배경과 글꼴을 설정했습니다.

위 내용을 참고하면, 각 항목의 위치, 크기 등을 자유자제로 편집할 수 있어 활용도는 무궁무진할 것으로 보입니다.


좋은 아이디어가 있다면, 저에게도 알려주셔서 공유 부탁드립니다.


참고자료


델파이 기본샘플을 적극 참고했습니다.


ListView 관련 샘픙은 기본 설치 경로 기준 아래와 같습니다.(10.2 도쿄 기준)
C:\Users\Public\Documents\Embarcadero\Studio\19.0\Samples\Object Pascal\Multi-Device Samples\User Interface\ListView


다음과 같은 샘플들이 있습니다.

그중 CustomAdapter와 ListViewImageIndex 샘플을 많이 참고했습니다.


CustomAdapter

웹상의 이미지를 표시하고, 상단에 큼지막한 이름과 하단에 설명과 버튼을 구성합니다.

목록의 크기를 이미지에 맞게 조정합니다.



ListViewImageIndex

리스트뷰와 데이터셋을 라이브바인딩과 코드를 이용해 목록을 구성합니다.

이미지는 이미지리스트를 활용합니다.


기타 다른 샘플들도 참고할 만한 내용이 많습니다. 다른 샘플들은 직접 둘러보시고 도움을 받으시기 바랍니다.

험프리.김현수 파이어몽키

"REST API 웹서비스 연동" 교육자료

2017.06.14 17:39

REST API 웹서비스 연동 

http://blog.hjf.pe.kr/467


여러분들의 프로젝트에 REST API 기반 웹서비스를 구축하고 연동하는 방법을 배울 수 있는 교육과정입니다.




진행 순서

 시간

 내용

 관련링크

 오전

 [이론] REST API 이해

 http://blog.hjf.pe.kr/462

 [이론] JSON 이란?

 엠바카데로 기술문서 바로가기

 [실습] REST API 서버 제작(RAD 서버 이용)

 http://blog.hjf.pe.kr/463

 오후

 [실습] REST API 서버 연동

 http://blog.hjf.pe.kr/464

 [실습] 데이터셋 기반 REST API 연동

 http://blog.hjf.pe.kr/465

 [실습] Open API 연동

 -



JSON 샘플

{
  "books":
  {
    "total":2,
    "book":
    [
      {
        "BOOK_SEQ":15,
        "BOOK_TITLE":"델파이 Begin...End",
        "BOOK_AUTHOR":"김원경"
      },     
      {
        "BOOK_SEQ":16,
        "BOOK_TITLE":"한 번에 개발하는 안드로이드 iOS앱 with 델파이. 1편",
        "BOOK_AUTHOR":"김원경 , 김현수, 오상현"
      }
    ]
  }

} 

http://www.json.org/json-ko.html


Open API 관련링크


OAuth 2.0 참고
https://developers.daum.net/services/apis/docs/oauth2_0/intro


REST API 서버 프로젝트(Books, DataSets)

EMSPackage.zip


클라이언트 프로젝트

EndPointClient.zip


DataSetClient.zip


KakaoOAuth20.zip


formdesign.txt

datasetFormDesign.txt




  object btnLoadData: TButton

    Position.X = 24.000000000000000000

    Position.Y = 16.000000000000000000

    TabOrder = 0

    Text = #45936#51060#53552' '#47196#46300

    OnClick = btnLoadDataClick

  end

  object Grid1: TGrid

    CanFocus = True

    ClipChildren = True

    Position.X = 24.000000000000000000

    Position.Y = 48.000000000000000000

    Size.Width = 369.000000000000000000

    Size.Height = 353.000000000000000000

    Size.PlatformDefault = False

    TabOrder = 1

    RowCount = 0

    OnSelChanged = Grid1SelChanged

    Viewport.Width = 365.000000000000000000

    Viewport.Height = 328.000000000000000000

  end

  object Label1: TLabel

    Position.X = 408.000000000000000000

    Position.Y = 46.000000000000000000

    Text = #51228#47785

    TabOrder = 11

  end

  object edtTitle: TEdit

    Touch.InteractiveGestures = [LongTap, DoubleTap]

    TabOrder = 12

    Position.X = 408.000000000000000000

    Position.Y = 65.000000000000000000

    Size.Width = 257.000000000000000000

    Size.Height = 22.000000000000000000

    Size.PlatformDefault = False

  end

  object Label2: TLabel

    Position.X = 408.000000000000000000

    Position.Y = 94.000000000000000000

    Text = #51200#51088

    TabOrder = 6

  end

  object edtAuthor: TEdit

    Touch.InteractiveGestures = [LongTap, DoubleTap]

    TabOrder = 7

    Position.X = 408.000000000000000000

    Position.Y = 113.000000000000000000

    Size.Width = 121.000000000000000000

    Size.Height = 22.000000000000000000

    Size.PlatformDefault = False

  end

  object Label3: TLabel

    Position.X = 408.000000000000000000

    Position.Y = 142.000000000000000000

    Text = 'ISBN'

    TabOrder = 4

  end

  object edtISBN: TEdit

    Touch.InteractiveGestures = [LongTap, DoubleTap]

    TabOrder = 5

    Position.X = 408.000000000000000000

    Position.Y = 161.000000000000000000

    Size.Width = 121.000000000000000000

    Size.Height = 22.000000000000000000

    Size.PlatformDefault = False

  end

  object Label4: TLabel

    Position.X = 408.000000000000000000

    Position.Y = 190.000000000000000000

    Text = #44032#44201

    TabOrder = 2

  end

  object edtPrice: TEdit

    Touch.InteractiveGestures = [LongTap, DoubleTap]

    TabOrder = 3

    Position.X = 408.000000000000000000

    Position.Y = 209.000000000000000000

    Size.Width = 121.000000000000000000

    Size.Height = 22.000000000000000000

    Size.PlatformDefault = False

  end

  object Label5: TLabel

    Position.X = 408.000000000000000000

    Position.Y = 238.000000000000000000

    Text = #44288#47144#47553#53356

    TabOrder = 9

  end

  object edtLink: TEdit

    Touch.InteractiveGestures = [LongTap, DoubleTap]

    TabOrder = 10

    Position.X = 408.000000000000000000

    Position.Y = 257.000000000000000000

    Size.Width = 257.000000000000000000

    Size.Height = 22.000000000000000000

    Size.PlatformDefault = False

  end

  object Label6: TLabel

    Position.X = 408.000000000000000000

    Position.Y = 286.000000000000000000

    Text = #49444#47749

    TabOrder = 8

  end

  object mmoDescription: TMemo

    Touch.InteractiveGestures = [Pan, LongTap, DoubleTap]

    DataDetectorTypes = []

    Position.X = 408.000000000000000000

    Position.Y = 304.000000000000000000

    Size.Width = 257.000000000000000000

    Size.Height = 97.000000000000000000

    Size.PlatformDefault = False

    TabOrder = 13

    Viewport.Width = 253.000000000000000000

    Viewport.Height = 93.000000000000000000

  end

  object btnNewData: TButton

    Position.X = 408.000000000000000000

    Position.Y = 16.000000000000000000

    TabOrder = 16

    Text = #49888#44508

    OnClick = btnNewDataClick

  end

  object btnSaveData: TButton

    Position.X = 584.000000000000000000

    Position.Y = 408.000000000000000000

    TabOrder = 14

    Text = #51200#51109

    OnClick = btnSaveDataClick

  end

  object ImageControl1: TImageControl

    Position.X = 536.000000000000000000

    Position.Y = 96.000000000000000000

    Size.Width = 129.000000000000000000

    Size.Height = 145.000000000000000000

    Size.PlatformDefault = False

    TabOrder = 17

  end

  object btnDeleteData: TButton

    Position.X = 584.000000000000000000

    Position.Y = 16.000000000000000000

    TabOrder = 15

    Text = #49325#51228

    OnClick = btnDeleteDataClick

  end

험프리.김현수 교육, 세미나

  1. Blog Icon
    이재풍

    험프리님.

    볼랜드 포럼에 질문 올렸는데요,,
    TMemo가 제대로 작동 안하는 것에 대해
    바쁘시더라도 도움 주셨으면 합니다. ㅜㅜ

    볼랜드 포럼 델파이 질문에 Nougat 관련 제목으로 최근에 올렸습니다.
    부탁드립니다...

프로세스 메모리 사용량 로그 기록 - 성능 모니터 이용

2017.05.25 11:31

개발한 프로세스에서 메모리 누수(Leak)이 발생된다 예상되면, 메모리 사용량 추적을 통해 메모리 누수 여부를 검증해야 합니다. 성능 모니터를 이용하면 프로세스의 메모리 사용량을 추적 및 로그 기록할 수 있습니다.


만약, 메모리 누수가 확인된다면, 테스트용 실행파일 등으로, 메모리 누수가 발생할 수 있는 코드의 범위를 줄여가며 반복적으로 테스트 해야 합니다.

만약, 특정 기능 수행 시 메모리 누수가 의심된다면 특정 기능을 반복적으로 실행할 수 있는 테스트 프로그램을 만들어 점검할 코드의 범위를 줄여가며 추적하기 바랍니다.


델파이로 개발된 프로젝트라면 메모리 누수 보고 기능을 켜서 메모리 누수 여부를 확인할 수 있습니다.


프로세스 메모리 사용량 추적

윈도우즈 성능 모니터를 이용해 프로세스가 사용 중인 메모리 사용량을 로그파일로 기록하는 방법을 소개합니다.


모니터링 대상 프로세스 실행

메모리 사용량 추적할 프로세스를 실행합니다. 저는 MemoryLeakTest.exe라는 실행파일을 만들어 실행했습니다.


성능 모니터에서 프로세스 메모리 사용량 기록

성능 모니터를 실행하고, 성능 > 데이터 수집기 집합 > 사용자 정의 메뉴를 선택합니다.


목록 창에서 우측 마우스를 누르고, 새로 만들기 > 데이터 수집기 집합 메뉴를 선택합니다.


이름을 지정하고, 수동으로 만들기(고급) 항목 선택 합니다.


성능 카운터 항목을 선택합니다.


[추가] 버튼을 누릅니다.

데이터 수집 가격을 지정합니다.


사용 가능한 카운터에서 Process 항목을 펼치고, Working Set 항목을 선택합니다.

인스턴스로는 추적할 프로세스를 선택합니다.(현재 실행된 프로세스 목록이 표시됩니다.)

[추가] 버튼을 눌러 추가합니다.

(Handle Count, Private Bytes 등 추적하고 싶은 카운터들도 함께 선택해도 됩니다.)

(주요 카운터에 대한 설명은 하단 참고링크 참고)


데이터 저장 경로를 지정합니다.



작업을 마칩니다.


추가한 데이터 수집기 집합의 속성에 들어가 로그 형식을 "쉼표로 구분"으로 변경합니다.(로그를 엑셀로 활용할 수 있습니다.)


성능 모니터링을 시작합니다.(데이터 수집기 집합의 속성에서 예약등을 이용해 자동 시작할 수 있습니다.)


로그파일 확인

지정한 경로에 csv 파일이 생성됩니다.


csv 파일을 엑셀로 열고, 데이터를 분석하거나, 차트를 만들어 시각적으로 메모리 사용량(Working Set) 추이를 관찰 할 수 있습니다.


참고링크


험프리.김현수 Delphi/C++Builder