2013. 5. 3. 15:31

원문출처 : 

http://www.dbguide.net/db.db?cmd=view&boardUid=13724&boardConfigUid=9&categoryUid=216&boardIdx=58&boardStep=1

ESQL/C Programming Highlights

Overview
ESQL/C
  • C 프로그램 내에 sql 구문을 바로 넣어 그 실행 결과를 프로그램에서 다양하게 사용할 수 있도록 제공되는 어플리케이션 개발 tool
  • ESQL/C 의 주된 component는 preprocessor 로서 ESQL/C code 를 C code로 변환하여 C compiler에게 에게 넘겨준다.
ESQL/C 프로그램 작성 규칙
  • ESQL/C preprocessor가 다른 C code와 구별할 수 있게 하기 위해 SQL은 “$” 혹은 “EXEC SQL” 으로 시작
  • SQL 구문의 끝에는 “;”를 붙임.
  • SQL 구문 안의 변수(host 변수라 부름)는 변수 이름 앞에 “:”를 붙임.
  • 주석은 표준 C의 주석인 “/* */ ”사용
ESQL/C 프로그램 컴파일
  • esql l [-e] [preprocessor e] [preprocessor 옵 옵션] [cc 매개변수] [-o 실행파일] ] 소스. ec
    [링크옵션]
include에 지정된 지정된 파일을 찾는 순서
  • 현재 디렉토리
  • 컴파일시 -I 옵션으로 지정한 디렉토리
  • $INFORMIXDIR/incl/esql
  • /usr/include
다음과 같은 preprocessor 구문을 사용할 수 있다
  • define, undef
  • ifdef, elseif, else, endif, ifndef
  • 예제
    EXEC SQL define USERTRANSACTIONS;
    EXEC SQL ifdef USERTRANSACTIONS;
    EXEC SQL begin work;
    EXEC SQL endif;

그림 1: include

Host variables
호스트 변수 : SQL 데이터를 저장하는 C 변수
대소문자 구분
SQL 문장안에서 컬럼명과 구분하기 위하여 호스트변수 앞에 : 기호 사용
선언
  • 달러 기호 사용
    $ CHAR * desc ;
  • EXEC SQL 키워드 사용
    EXEC SQL begin declare section;
    char * desc;
    EXEC SQL end declare section;
사용
  • SQL 내에서
    EXEC SQL update customer set zipcode = : zipcode ;
  • C 구문 안에서
    gets (dbname);
    EXEC SQL database : dbname;
external 이나 static 으로 선언하지 않은 경우자동적으로 local 범위

그림 2: local 범위

Database Connections
ESQL/C 구문
  • CONNECT TO 데이터베이스명
  • DISCONNECT ALL
CONNECT 구문의 옵션
  • Connection 이름
    · EXEC SQL CONNECT TO ‘‘stores@ munish’AS ‘munich_con’;
  • User 절
    · EXEC SQL CONNECT TO ‘stores@ munish’ USER :uid USING : passwd ;
  • Default 절 (데이터베이스를 오픈하지 않고 서버에 연결)
    · EXEC SQL CONNECT TO DEFAULT ;
    · Default 절 사용 후 다음과 같은 문장이 필요
    √ DATABASE
    √ CREATE DATABASE
    √ START DATABASE
연결 전환 (switching)
  • 구문
    EXEC SQL SET CONNECTION ‘munish _con’;
    EXEC SQL SET CONNECTION :connect_id ;
    EXEC SQL SET CONNECTION DEFAULT;
연결 종료 (disconnecting)
  • 열린 데이터베이스를 닫고 connection을 종료한다
    EXEC SQL DISCONNECT :connect_id ;
    EXEC SQL DISCONNECT CURRENT ;
    EXEC SQL DISCONNECT DEFAULT ;
    EXEC SQL DISCONNECT ALL ;
  • default로 connect 했거나 connection이 하나 일 경우 DEFAULT 사용
Error Handling
SQL 문을 실행한 후 서버에서 SQLCA라 불리는 영역에 feedback 정보를 남긴다
  • errors
  • performance
  • warnings
SQLCODE 는 sqlca. sqlcode 값과 같다
  • SQLCODE < 0 : 에러 코드 값
  • SQLCODE = 0 : 정상적 처리
  • SQLCODE = 100 : SQLNOTFOUND, 찾는 행이 없음
  • SQLCODE = 1~99 : Dynamic SQL
에러 메시지를 얻기 위한 함수
  • rgetmsg, rgetlmsg
SQL 문이 실행되고 다음과 같은 4가지 중 하나의 상태가 된다
  • 성공
  • 성공, 찾을 수 있는 데이터는 없음
  • 성공, 경고(warning) 메시지가 있음
  • 실패
성공 외의 나머지 상태에 대한 처리 방법을 exception처리로 제어한다
  • WHENEVER exception action
  • exception : NOT FOUND, SQLWARNING, SQLERROR
  • action : GO TO label, CALL function, STOP, CONTINUE
  • 디폴트 action은 CONTINUE
WHENEVER 문의 scope는 한 소스 파일에서 global 성격을 가진다
struct sqlca_s {
long sqlcode ;
char sqlerrm[72] ;
char sqlerrp[8] ;
long sqlerrd[6] ;
struct sqlcaw_s {
char sqlwarn0 ;
char sqlwarn0 ;
char sqlwarn0 ;
char sqlwarn0 ;
char sqlwarn0 ;
char sqlwarn0 ;
char sqlwarn0 ;
char sqlwarn0 ;
} sqlwarn;
} ;
extern structsqlca_s sqlca;
GET DIAGNOSTICS 사용
  • GET DIAGNOSTICS 문은 여러 개의 SQL exception을 처리할 수 있고, ANSI및 X/OPEN 표준으로 컴파일된다
  • SQLCA 는 계속 사용 가능하다
  • 다음 세가지 분류로 사용한다
    • · SQLSTATE
    • · GET DIAGNOSTICS 문
    • · GET DIAGNOSTICS EXCEPTION 문
  • GET DIAGNOSTICS 의 정보
    • · MORE : 모든 exception이 반환되었음을 나타냄
    • · NUMBER : exception의 갯수
    • · ROW_COUNT : SQL 에 의해 처리된 행 수
  • EXCEPTION 의 정보
    • · RETURNED_SQLSTATE
    • · SERVER_NAME
    • · CONNECTION_NAME
    • · CLASS_ORIGIN 등

그림 3: GET DIAGNOSTICS 사용

Indicator 사용
  • 데이터를 호스트변수에 저장할 때 다음과 같은 Exception 이 발생할 수 있다
    • · NULL 값을 fetch 하였다
    • · 컬럼 데이터에 비해 호스트 변수의 크기가 작다
  • 사용법
    • · :host 변수:indicator 변수
    • · $host 변수 $indicator 변
    • · :host 변수 INDICATOR indicator 변수 (ANSI 표준)

그림 4: Indicator 사용

Prepare, Execute
Prepare / Execute 구문

PREPARE prepare_statement_id FROM { “quoted_string” | :host_variable } ;
EXECUTE prepare_statement_id [ USING :host_variables ]

단일 SQL문 처리 예

EXEC SQL insert into customer (customer_num, fname, lname , company)
values (0, : fname, :lname , ‘MPS Corp’ );
EXEC SQL insert into items values (: itemsrec);
※ itemsrec 변수는 items 테이블의 컬럼 순서로 선언된 structure 형

PREPARE / EXECUTE 사용

EXEC SQL PREPARE ins_p from
“insert into customer (customer_num, fname , lname, company)
values (0,?,?,?)” ;
EXEC SQL EXECUTE ins_p using : fnam, lname , :company;

PREPARE를 사용하는 이유
  • PREPARE 시점에 SQL문장에 대하여 미리 parsing되고 query plan이 생성된다
  • EXECUTE 시점에는 처리해야 할 값만 넘겨주면 즉시 실행된다
  • 하나의 DML문장에서 여러번 값을 바꿔서 넘겨주어야 할 때 PREPARE 에서 한 번만 query plan을 생성하므로 유용하게 사용할 수 있다
Cursor
Cursor 이해
  • Cursor 는 select 구문에 의해 선택된 row 들을 가리키고 있는 일종의 marker라고 볼 수 있음.
  • 여러 개의 row 를 가져오는 select 문의 결과에 대해 처리하기 위해서 필요함.
  • Cursor 종류
    • Select cursor
    • √ Scroll cursor
    • √ Non-scroll cursor
    • √ For update cursor
  • Insert cursor

그림 5: Cursor 이해

Scroll Cursor
구문
  • DECLARE
    DECLARE cursor_id SCROLL CURSOR [WITH HOLD] FOR select_stmt;
  • OPEN
    OPEN cursor_id ;
  • FETCH
    FETCH [position] Cursor_id [INTO host_variable_list] ;
    Position : FIRST, LAST, CURRENT, NEXT, PREVIOUS, ABSOLUTE n, RELATIVE n

그림 6: Scroll Cursor

  • CLOSE
    CLOSE cursor_id ;
  • FREE
    FREE Cursor_id ;
WITH HOLD 구문
  • WITH HOLD 구문을 사용한 커서는 transaction이 종료되어도 close되지 않는다.
Fetch Buffer Size
  • 환경변수 : export FET_BUF_SIZE=30000
  • 전역변수 : EXEC SQL include sqlhdr ;
    FetBufSize=30000 ;

그림 7: Fetch Buffer Size

Deferred Prepare
  • 환경변수 : export IFX_DEFERRED_PREPARE=1 (enable)
             export IFX_DEFERRED_PREPARE=0 (disable)
  • SQL 구문 : EXEC SQL set deferred_prepare ;
             EXEC SQL set deferred_prepare enabled ;
             EXEC SQL set deferred_prepare disabled ;
Open-Fetch-Close
  • 환경변수 : export OPTOFC=1 (enable)
         export OPTOFC=0 (disable)
Autofree
  • 환경변수 : export IFX_AUTOFREE=1 (enable)
              export IFX_AUTOFREE=0 (disable)
  • SQL 구문 : EXEC SQL set autofree; ;           EXEC SQL set autofree enabled ;           EXEC SQL set autofree disabled ;

그림 8: Autofree

For Update Cursor
구문
  • DECLARE
    DECLARE cursor_id CURSOR [WITH HOLD] FOR select_stmt FOR UPDATE ;
  • OPEN
    OPEN cursor_id ;
  • FETCH
    FETCH cursor_id [INTO host_variable_list] ;
  • UPDATE
    UPDATE ... WHERE CURRENT OF cursor_id ;
  • CLOSE
    CLOSE cursor_id ;
  • FREE
    FREE cursor_id ;

그림 9: Update Cursor

Insert Cursor
구문
  • DECLARE
    DECLARE cursor_id CURSOR FOR insert_stmt ;
  • OPEN
    OPEN cursor_id ;
  • PUT
    PUT cursor_id [ FROM host_variable_list ] ;
  • FLUSH
    FLUSH cursor_id ;
  • CLOSE
    CLOSE cursor_id ;
  • FREE
    FREE cursor_id ;

Posted by 땡보
2013. 1. 26. 20:57

Win 환경에선 괜츈함...

http://code.google.com/p/pyodbc/ 요기서 찾을수 있고~~

pyodbc-3.0.6.win32-py2.7.exe


'Study > python' 카테고리의 다른 글

[연습]Python regular expression & sqlite  (0) 2013.09.22
[펌]Unicode In Python, Completely Demystified  (0) 2013.09.18
Encoding type table  (0) 2012.12.27
손삼 마물단계  (0) 2012.04.04
파이썬(python)3 py to exe cx_Freeze(like py2exe)  (0) 2012.04.03
Posted by 땡보
2012. 12. 27. 07:59
CodecAliasesLanguagesascii646, us-asciiEnglishbig5big5-tw, csbig5Traditional Chinesebig5hkscsbig5-hkscs, hkscsTraditional Chinesecp037IBM037, IBM039Englishcp424EBCDIC-CP-HE, IBM424Hebrewcp437437, IBM437Englishcp500EBCDIC-CP-BE, EBCDIC-CP-CH, IBM500Western Europecp720 Arabiccp737 Greekcp775IBM775Baltic languagescp850850, IBM850Western Europecp852852, IBM852Central and Eastern Europecp855855, IBM855Bulgarian, Byelorussian, Macedonian, Russian, Serbiancp856 Hebrewcp857857, IBM857Turkishcp858858, IBM858Western Europecp860860, IBM860Portuguesecp861861, CP-IS, IBM861Icelandiccp862862, IBM862Hebrewcp863863, IBM863Canadiancp864IBM864Arabiccp865865, IBM865Danish, Norwegiancp866866, IBM866Russiancp869869, CP-GR, IBM869Greekcp874 Thaicp875 Greekcp932932, ms932, mskanji, ms-kanjiJapanesecp949949, ms949, uhcKoreancp950950, ms950Traditional Chinesecp1006 Urducp1026ibm1026Turkishcp1140ibm1140Western Europecp1250windows-1250Central and Eastern Europecp1251windows-1251Bulgarian, Byelorussian, Macedonian, Russian, Serbiancp1252windows-1252Western Europecp1253windows-1253Greekcp1254windows-1254Turkishcp1255windows-1255Hebrewcp1256windows-1256Arabiccp1257windows-1257Baltic languagescp1258windows-1258Vietnameseeuc_jpeucjp, ujis, u-jisJapaneseeuc_jis_2004jisx0213, eucjis2004Japaneseeuc_jisx0213eucjisx0213Japaneseeuc_kreuckr, korean, ksc5601, ks_c-5601, ks_c-5601-1987, ksx1001, ks_x-1001Koreangb2312chinese, csiso58gb231280, euc- cn, euccn, eucgb2312-cn, gb2312-1980, gb2312-80, iso- ir-58Simplified Chinesegbk936, cp936, ms936Unified Chinesegb18030gb18030-2000Unified Chinesehzhzgb, hz-gb, hz-gb-2312Simplified Chineseiso2022_jpcsiso2022jp, iso2022jp, iso-2022-jpJapaneseiso2022_jp_1iso2022jp-1, iso-2022-jp-1Japaneseiso2022_jp_2iso2022jp-2, iso-2022-jp-2Japanese, Korean, Simplified Chinese, Western Europe, Greekiso2022_jp_2004iso2022jp-2004, iso-2022-jp-2004Japaneseiso2022_jp_3iso2022jp-3, iso-2022-jp-3Japaneseiso2022_jp_extiso2022jp-ext, iso-2022-jp-extJapaneseiso2022_krcsiso2022kr, iso2022kr, iso-2022-krKoreanlatin_1iso-8859-1, iso8859-1, 8859, cp819, latin, latin1, L1West Europeiso8859_2iso-8859-2, latin2, L2Central and Eastern Europeiso8859_3iso-8859-3, latin3, L3Esperanto, Malteseiso8859_4iso-8859-4, latin4, L4Baltic languagesiso8859_5iso-8859-5, cyrillicBulgarian, Byelorussian, Macedonian, Russian, Serbianiso8859_6iso-8859-6, arabicArabiciso8859_7iso-8859-7, greek, greek8Greekiso8859_8iso-8859-8, hebrewHebrewiso8859_9iso-8859-9, latin5, L5Turkishiso8859_10iso-8859-10, latin6, L6Nordic languagesiso8859_13iso-8859-13, latin7, L7Baltic languagesiso8859_14iso-8859-14, latin8, L8Celtic languagesiso8859_15iso-8859-15, latin9, L9Western Europeiso8859_16iso-8859-16, latin10, L10South-Eastern Europejohabcp1361, ms1361Koreankoi8_r Russiankoi8_u Ukrainianmac_cyrillicmaccyrillicBulgarian, Byelorussian, Macedonian, Russian, Serbianmac_greekmacgreekGreekmac_icelandmacicelandIcelandicmac_latin2maclatin2, maccentraleuropeCentral and Eastern Europemac_romanmacromanWestern Europemac_turkishmacturkishTurkishptcp154csptcp154, pt154, cp154, cyrillic-asianKazakhshift_jiscsshiftjis, shiftjis, sjis, s_jisJapaneseshift_jis_2004shiftjis2004, sjis_2004, sjis2004Japaneseshift_jisx0213shiftjisx0213, sjisx0213, s_jisx0213Japaneseutf_32U32, utf32all languagesutf_32_beUTF-32BEall languagesutf_32_leUTF-32LEall languagesutf_16U16, utf16all languagesutf_16_beUTF-16BEall languages (BMP only)utf_16_leUTF-16LEall languages (BMP only)utf_7U7, unicode-1-1-utf-7all languagesutf_8U8, UTF, utf8all languagesutf_8_sig all languages

'Study > python' 카테고리의 다른 글

[펌]Unicode In Python, Completely Demystified  (0) 2013.09.18
python ODBC 연결시~  (0) 2013.01.26
손삼 마물단계  (0) 2012.04.04
파이썬(python)3 py to exe cx_Freeze(like py2exe)  (0) 2012.04.03
[분석중]맵스캔..  (0) 2012.04.03
Posted by 땡보
2012. 12. 15. 20:57

안드로이드에서 sl4a 서버의 포트 찾기~

#!/bin/bash

# ADB
# The path to the Android Debugger program.
# By default, we use the one detected in the environment.
# This can be overridden below.
ADB=`which adb`
# FORWARDED_PORT
# SL4A RPC calls sent via FORWARDED_PORT on the localhost
# are forwarded to the SL4A server on the Android device.
FORWARDED_PORT=9999
# MAX_SERVER_RETRIES
# Max number of retries to detect the port number that
# the SL4A server is using on the Android device.
MAX_SERVER_RETRIES=3
SLEEP_TIME_BETWEEN_RETRIES=1

sanity_checks()
{
  if test -z "$ADB"
  then
echo "The Android Debugger program (adb) was not found in your path."
    echo "Please check your Android SDK installation and your PATH envronment."
    exit 1
  fi

PYTHON_SHELL=`which ipython`
  if test -z "$PYTHON_SHELL"
  then
PYTHON_SHELL=`which python`
  fi

if test -z "$PYTHON_SHELL"
  then
echo "The Python interpreter was not found in your path."
    echo "Please check your installation and your PATH envronment."
    exit 1
  fi
}


start_private_server()
{
  echo "Starting Scripting Layer for Android(SL4A) private server."
  ${ADB} shell am start -a com.googlecode.android_scripting.action.LAUNCH_SERVER -n com.googlecode.android_scripting/.activity.ScriptingLayerServiceLauncher
  echo "Waiting for ${SLEEP_TIME_BETWEEN_RETRIES}s to let server settle."
  sleep ${SLEEP_TIME_BETWEEN_RETRIES}
}


get_private_server_port()
{
  # Android's netstat app seems to be crippled. It does not accept
  # standard netstat switches like -l and -p. A normal 'netstat -lp'
  # command would return the list of listening ports AND their
  # associated PIDs. Because Android's netstat doesn't return this
  # info, the code simply assumes that the SL4A server on the first
  # port that listens on localhost.
  # I'd welcome any suggestions for improvement here.
  SERVER_PORT=`${ADB} shell netstat | grep "127.0.0.1.*LISTEN" | awk -F "[ :]*" '{ print $6 }' | head -n 1`
  retries=0
  while test -z "$SERVER_PORT" && (( retries < $MAX_SERVER_RETRIES))
  do
echo "Server port not detected. Sleeping for ${SLEEP_TIME_BETWEEN_RETRIES}s."
    sleep ${SLEEP_TIME_BETWEEN_RETRIES}
    (( retries += 1 ))
    echo "Retry ${retries} of ${MAX_SERVER_RETRIES}."
    SERVER_PORT=`${ADB} shell netstat | grep "127.0.0.1.*LISTEN" | awk -F "[ :]*" '{ print $6 }' | head -n 1`
  done

if test -z "$SERVER_PORT"
  then
echo "Server port not detected. Please check your SL4A installation."
    exit 1
  fi

echo "Found server serving on port: ${SERVER_PORT}"
}


setup_remote_control_environment()
{
  echo "Forwarding to SL4A client requests to port: ${FORWARDED_PORT}"
  ${ADB} forward tcp:${FORWARDED_PORT} tcp:${SERVER_PORT}
  export AP_PORT=${FORWARDED_PORT}
}


sanity_checks
start_private_server
get_private_server_port
setup_remote_control_environment
echo "Starting python interpreter..."
$PYTHON_SHELL
echo "Remember to stop the SL4A server on your Android device."

Posted by 땡보
2012. 9. 17. 08:37

'Study > Reverse_engineering' 카테고리의 다른 글

[펌]SYBASE ASA DB log file error  (0) 2012.01.11
[분석중]삭제키  (0) 2011.12.28
[놀이]flickhomerun  (0) 2011.12.10
[ARM]자주 사용되는 ARM/THUMB OPCODE 정리  (0) 2011.09.29
[펌]IOS 안티 디버깅 기법  (0) 2011.09.28
Posted by 땡보
2012. 9. 15. 02:44

SELECT * FROM master..sysprocesses WHERE ipaddr = "129.100.254.242" AND suid = suser_id("pos")

Posted by 땡보
2012. 8. 25. 11:21

Link : http://www.reddit.com/r/Diablo/comments/qxyxm/diablo_3_windows_and_mac_download_links_all

위 링크에서 디아블로3 Mac용 다운로드 클라이언트 받아서 설치한 후 언어 한국으로 바꾸면 끝!!

Posted by 땡보
2012. 8. 20. 22:29

맥용 SSL VPN 터널링 도구

원문 : http://www.question-defense.com/2011/10/04/connect-to-fortinet-vpn-on-osx-download-forticlient-ssl-vpn-for-osx


forticlientsslvpn_macosx_4.0.2082.dmg


Posted by 땡보
2012. 8. 19. 17:58

원문 출처 : http://blog.simplism.kr/?p=1070


프로그래밍용 폰트 : http://www.lowing.org/fonts/


ttf-bitstream-vera-1.10.tar.bz2


압축풀고 나온 파일들을

$ sudo mv *.ttf /usr/share/fonts/truetype/
$ fc-cache -v

로 옮기고 터미널 재실행


또한 동일 출처에서 아래도 유용함~

$ sudo apt-get install nautilus-open-terminal
$ killall nautilus

'Study > linux' 카테고리의 다른 글

[Backtrack]ssh 설정  (0) 2013.08.06
[펌]우분투 APM 셋팅법  (0) 2013.08.04
[명령어]서비스 재시작  (0) 2013.08.04
[펌]Reverse Engineering Firmware: Linksys WAG120N  (1) 2013.05.17
Posted by 땡보
2012. 8. 10. 14:20


[원문] : http://cocoawithlove.com/2008/10/synthesizing-touch-event-on-iphone.html

Synthesizing a touch event on the iPhone

The iPhone lacks specific methods to create UIEvent and UITouch objects. I'll show you how to add this functionality so you can write programmatically driven user-interfaces.

Update #1: Added a "Device SDK" version that will link correctly outside of the "Simulator SDK".
Update #2: Two bugs have been fixed since the code was originally posted... the objects in the UIEvent member _keyedTouches are now NSSets and the _view and _window in UITouchare now retained.
Update #3: changes to the UITouch and UIEvent categories as well asperformTouchInView: to support SDK 2.2 changes.
Update #4: Support for SDK 3.0.

A warning before we begin...

The content of this post is for debugging and testing only. Do not submit this code in an application to the App Store. Doing so will likely result in:

  • A bad UI experience for your users.
  • An app that breaks on every OS update.
  • Rejection of your application.

Synthesized touches are never the right way to trigger actions in a real application. The only useful use for this post is in automated user testing (see my later post Automated User Interface Testing on the iPhone).

User-interface testing

When running application tests, it is helpful to be able to generate user events to test your user-interface. That way, you can run user-interface tests automatically instead of manually.

On Cocoa Senior (also known as "the Mac") we have methods like the gargantuan:

    mouseEventWithType:location:modifierFlags:timestamp:
      windowNumber:context:eventNumber:clickCount:pressure:

to generate events.

Cocoa Junior on the iPhone doesn't have any methods like this, so we must work out how to achieve it ourselves.

UITouch category

A basic touch event normally consists of three objects:

  • The UITouch object — which will be used for the touch down and touch up
  • A first UIEvent to wrap the touch down
  • A second UIEvent to wrap the touch up

Lets look first at creating the UITouch object. Since most of the fields in this object are private, we can't sublcass it or set them directly — everything must be done on a category. My category goes something like this:

@implementation UITouch (Synthesize)
 
- (id)initInView:(UIView *)view
{
    self = [super init];
    if (self != nil)
    {
        CGRect frameInWindow;
        if ([view isKindOfClass:[UIWindow class]])
        {
            frameInWindow = view.frame;
        }
        else
        {
            frameInWindow =
                [view.window convertRect:view.frame fromView:view.superview];
        }
          
        _tapCount = 1;
        _locationInWindow =
            CGPointMake(
                frameInWindow.origin.x + 0.5 * frameInWindow.size.width,
                frameInWindow.origin.y + 0.5 * frameInWindow.size.height);
        _previousLocationInWindow = _locationInWindow;
 
        UIView *target = [view.window hitTest:_locationInWindow withEvent:nil];
        _view = [target retain];
        _window = [view.window retain];
        _phase = UITouchPhaseBegan;
        _touchFlags._firstTouchForView = 1;
        _touchFlags._isTap = 1;
        _timestamp = [NSDate timeIntervalSinceReferenceDate];
    }
    return self;
}
 
- (void)changeToPhase:(UITouchPhase)phase
{
    _phase = phase;
    _timestamp = [NSDate timeIntervalSinceReferenceDate];
}
 
@end

This method builds a touch in the center of the specified UIView (window coordinates must be used).

You should note that this category includes the changeToPhase: method. This phase (set toUITouchPhaseBegan in the initInView: method) refers to the begin/drag/ended state of the touch operation. We need a method to change the state because the same UITouch object must be used for touch began and touch ended events (otherwise the whole windowing system crashes).

UIEvent category

The UIEvent object is mostly handled through an existing private method (_initWithEvent:touches:). There are two difficulties with this method though:

  • We must provide it a GSEvent object (or something very close to it)
  • We must allocate the object as a UITouchesEvent on SDK 3.0 and later but as a UIEvent on earlier versions.

Here's how all that will look:

@interface UIEvent (Creation)
- (id)_initWithEvent:(GSEventProxy *)fp8 touches:(id)fp12;
@end
 
@implementation UIEvent (Synthesize)
 
- (id)initWithTouch:(UITouch *)touch
{
    CGPoint location = [touch locationInView:touch.window];
    GSEventProxy *gsEventProxy = [[GSEventProxy alloc] init];
    gsEventProxy->x1 = location.x;
    gsEventProxy->y1 = location.y;
    gsEventProxy->x2 = location.x;
    gsEventProxy->y2 = location.y;
    gsEventProxy->x3 = location.x;
    gsEventProxy->y3 = location.y;
    gsEventProxy->sizeX = 1.0;
    gsEventProxy->sizeY = 1.0;
    gsEventProxy->flags = ([touch phase] == UITouchPhaseEnded) ? 0x1010180 : 0x3010180;
    gsEventProxy->type = 3001;   
     
    //
    // On SDK versions 3.0 and greater, we need to reallocate as a
    // UITouchesEvent.
    //
    Class touchesEventClass = objc_getClass("UITouchesEvent");
    if (touchesEventClass && ![[self class] isEqual:touchesEventClass])
    {
        [self release];
        self = [touchesEventClass alloc];
    }
     
    self = [self _initWithEvent:gsEventProxy touches:[NSSet setWithObject:touch]];
    if (self != nil)
    {
    }
    return self;
}
 
@end

You can see that most of the setup is simply concerned with filling in the fields of the GSEventProxyobject which is the pretend object that we substitute in place of the actual GSEvent object (which can't be easily allocated).

The fields and values used are determined simply by staring at real GSEvent structures in the debugger until the values for fields could be determined.

The definition of this object follows. You'll need to place it before the previous UIEvent category implemention.

@interface GSEventProxy : NSObject
{
@public
    unsigned int flags;
    unsigned int type;
    unsigned int ignored1;
    float x1;
    float y1;
    float x2;
    float y2;
    unsigned int ignored2[10];
    unsigned int ignored3[7];
    float sizeX;
    float sizeY;
    float x3;
    float y3;
    unsigned int ignored4[3];
}
@end
@implementation GSEventProxy
@end

Sending the event

There is no API to route the events to the appropriate view — so we will just invoke the methods directly on the view ourselves.

Using the above categories to create the UITouch and UIEvent objects, dispatching a touch event to a UIView looks like this:

- (void)performTouchInView:(UIView *)view
{
    UITouch *touch = [[UITouch alloc] initInView:view];
    UIEvent *eventDown = [[UIEvent alloc] initWithTouch:touch];
     
    [touch.view touchesBegan:[eventDown allTouches] withEvent:eventDown];
     
    [touch setPhase:UITouchPhaseEnded];
    UIEvent *eventUp = [[UIEvent alloc] initWithTouch:touch];
     
    [touch.view touchesEnded:[eventUp allTouches] withEvent:eventUp];
     
    [eventDown release];
    [eventUp release];
    [touch release];
}

Legality of use and risks

The approach used in this post constitutes using an undisclosed API — it is therefore illegal to submit applications to the App Store that use this approach, according to the iPhone SDK Agreement.

In terms of risks, this type of undisclosed API use has a high probability of breaking on every update to the iPhone OS — yet another reason why this code is for in-house developer use only.

If you use this code, only use it in a separate target for testing purposes only. Do not submit this code to the App Store.

Conclusion

You can download a copy of TouchSynthesis.m as part of the SelfTesting project (from my later post Automated User Interface Testing on the iPhone).

I have only tested this for performing touch events in UITableViewCells in aUINavigationController — navigating a hierarchy to verify that the hierarchy works. Of course, once you've programmatically navigated, you must also read back from the hierarchy to ensure that required features are present — but that's a post for a different time.

Working directly with the fields of a class is always a little risky. I'm sure there are UIViews that won't work well with this type of synthetic touch. Apple is also free to change the meaning of any fields at any time so this code is prone to break frequently.

Finally, remember to keep this type of testing code in a separate target so it isn't included in the application you submit to the App Store. I don't want to see your projects break or be rejected because you're trying to invoke use undisclosed APIs in your final application.

Share this post: reddit:Synthesizing a touch event on the iPhone stumbleupon:Synthesizing a touch event on the iPhone del.icio.us:Synthesizing a touch event on the iPhone digg:Synthesizing a touch event on the iPhone
Dr Nic 
Very cool seeing some "how to poke my app" testing tips.
Saturday, October 18, 2008, 22:02:25
– Like – Reply
Brad 
I have found that this technique works well for simulating clicks to an embedded web view.
Sunday, October 19, 2008, 11:16:40
– Like – Reply
Ross 
I've had difficulty making this work with embedded webviews -- it seems to expect there to be a real GSEventRef, how have you pulled this off Brad?
Thursday, October 30, 2008, 08:51:19
– Like – Reply
Cormac 
Hi, I'm currently trying to implement some automated UI test cases for an iPhone app I have recently written and as far as I can tell, you are the only person to have tried this (UITouch synthesis) and gotten it to work. 
 
I have tried your code and failed and I would be extremely grateful if you could suggest a cause, or better yet, supply me with a working example. I'm hoping you have a simple project you used when writing the article. :-) If I can synthesize a touch event, then it dramatically increased my testing code coverage. 
 
Here is where it all goes wrong for me: 
 
- (void)performTouchInView:(UIView *)view 

UITouch *touch = [[UITouch alloc] initInView:view phase:UITouchPhaseBegan]; 
UIEvent *eventDown = [[UIEvent alloc] initWithTouch:touch]; 
>>> [view touchesBegan:[NSSet setWithObject:touch] withEvent:eventDown]; 
 
When I call touchesBegan: on my view I get the following exception: 
 
*** -[UITouch countByEnumeratingWithState:objects:count:]: unrecognized selector sent to instance 0x100cc50 
 
For whatever reason, countByEnumeratingWithState:objects:count: (which belongs to NSFastEnumeration protocol, which is in turn adopted by NSSet) is being called on the UITouch. 
 
Once again, any help you can provide will be gratefully received. 
 
Kind regards, 
Cormac.
Tuesday, November 18, 2008, 02:37:03
– Like – Reply
 Matt Gallagher 
Hi Cormac, 
 
Revisiting this topic to provide an API for proper UI tests has been on my plate for a while. With luck, it'll be this week -- we'll see if I get there. Stay tuned.
Tuesday, November 18, 2008, 09:58:58
– Like – Reply
Cormac 
Matt, 
 
That's great news. I'll look forward to it. Thanks.
Tuesday, November 18, 2008, 17:43:48
– Like – Reply
Lars Bergstrom 
The issue is that the values added via CFDictionaryAddValue for the touch objects need to be the NSSet of the touch, not the touch object itself.
Wednesday, November 19, 2008, 01:37:33
– Like – Reply
 Matt Gallagher 
Thanks for pointing that out, Lars. 
 
Weird that it never caused a bug for me -- I guess it depends on the view upon which you invoke touchesBegan:withEvent:
Wednesday, November 19, 2008, 06:50:46
– Like – Reply
Cormac 
Lars, thanks for that. I tried your fix and it worked perfectly. Thanks for you both.
Thursday, November 20, 2008, 01:50:03
– Like – Reply
Phlix 
Are you sure of update #2? 
In UIEvent.h  we have _keyedTouches defined as a CFMutableDictionaryRef
Sunday, December 21, 2008, 04:20:43
– Like – Reply
 Matt Gallagher 
Hi Phlix. The variable _keyedTouches remains a dictionary. It is only the objects that it contains which have changed to an NSSet.
Sunday, December 21, 2008, 07:15:43
– Like – Reply
Alex 
Hi Matt:  Did you post the updated code anywhere?  My double click code is crashing randomly -- I copied and pasted what you have here and I think it is out of date.
Wednesday, March 18, 2009, 20:11:51
– Like – Reply
 Matt Gallagher 
Alex, the code here is only tested to work with single clicks. Multiple touches, double touches and drag operations all have some quirks that would need to be tested and debug to synthesize properly. I'm afraid this is work I haven't done so you'd have to address these problems yourself.
Sunday, March 22, 2009, 10:29:57
– Like – Reply
Alex 
Hi Matt.  thanks for the response.  I got this technique all working for me, i just had to read the posting very carefully.  double clicks, etc. all working. 
Sunday, March 22, 2009, 11:42:04
– Like – Reply
Andy 
Hi Alex, 
I've been trying to get drags working but am stumped, any source code would be much appreciated...
Wednesday, January 13, 2010, 20:22:05
– Like – Reply


'Study > mobile' 카테고리의 다른 글

음.. 뽀꼬빵  (0) 2013.12.22
[연습]포코팡 오토(?) POKOPANG AUTO~  (3) 2013.12.17
[android]change system date & time  (0) 2013.11.19
[Android]Monkeyrunner  (0) 2013.11.05
[펌]USB 드라이버가 없는 안드로이드 기기의 설치  (0) 2013.09.12
Posted by 땡보