¼·»ï¤Î³«È¯Wiki - ¥µ¥ó¥¯¤È·Ñ³¤ÎÊÙ¶¯²ñ
http://atnd.org/events/19963

ÊÙ¶¯²ñ¤ÇÇÛÉÛ¤¹¤ë»ñÎÁ¤Î᤭Âæ¤Ç¤¹¡£

¢¨ ´°À®ÈǤϤ³¤Á¤é ¢Í http://d.hatena.ne.jp/n7shi/20111130



thunk¤È¤Ï

  • ±Ññ¸ì¤È¤·¤Æ¤ÏÆä˰ÕÌ£¤¬¤Ê¤¤¡£
  • Algol 60¤Ç¥¢¥É¥ì¥¹¤òÃÙ±äɾ²Á¤¹¤ë¤¿¤á¤ËƳÆþ¡£
  • PE¤Ç¤âDLL¤«¤é¥¤¥ó¥Ý¡¼¥È¤·¤¿´Ø¿ô¤Î¥¢¥É¥ì¥¹¤¬¥µ¥ó¥¯¤ËÆþ¤ë¡£
  • 16¥Ó¥Ã¥È¥³¡¼¥É¤È32¥Ó¥Ã¥È¥³¡¼¥É¤ÎÊÑ´¹¤â¥µ¥ó¥¯¤È¸Æ¤Ð¤ì¤ë¡£
  • º£²ó¤Ï¼Â¹Ô»þ¤Ë¥¢¥É¥ì¥¹¤òÊÑ´¹¤¹¤ëµ¡¹½¤ò¤Þ¤È¤á¤Æ¥µ¥ó¥¯¤È¸Æ¤Ö¡£
  • ¥µ¥ó¥¯¤ÎÀ¸À®¤ÏOS¤äCPU¤Ë°Í¸¤¹¤ë¡£
    • º£²ó¤Ïi386(32bit x86)¤Ë¾ÇÅÀ¤ò¹Ê¤ë¡£
  • ¸Å¤¤API¤Ø¤Î¥³¡¼¥ë¥Ð¥Ã¥¯¤äÆȼ«¸À¸ì¤Î¼ÂÁõ¤Ë¤ÏÍ­ÍÑ¡£
    • ½ã¿è¤ÊC++¤ÎÏÈÆâ¤Ç¤Ï¤¢¤Þ¤ê»È¤¦Í¾ÃϤϤʤ¤¡£

¥¢¥»¥ó¥Ö¥é¤È¥¹¥¿¥Ã¥¯


ɬÍפȤʤëÈϰϤò´Êñ¤ËÀâÌÀ¡£

¥×¥í¥í¡¼¥°¤È¥¨¥Ô¥í¡¼¥°

´Ø¿ô¤ÎºÇ½é¤ÈºÇ¸å¤Ë¤¢¤ë¡¢
¥¹¥¿¥Ã¥¯¥Õ¥ì¡¼¥à¤Î³ÎÊݤʤɷè¤Þ¤Ã¤¿½èÍý¡£

int test(int a, int b) {
    return a + b;
}

Release¤Ç¥¢¥»¥ó¥Ö¥ê½ÐÎÏ

_test PROC
    ; ¥×¥í¥í¡¼¥°
    push ebp
    mov  ebp, esp
    ; ËÜÂÎ
    mov  eax, DWORD PTR 12[ebp]
    add  eax, DWORD PTR 8[ebp]
    ; ¥¨¥Ô¥í¡¼¥°
    pop  ebp
    ret  0
_test ENDP

ebp¤Ï´Ø¿ô¤Î¥¹¥¿¥Ã¥¯¥Õ¥ì¡¼¥à¤òÌÀ¼¨¤¹¤ë¥ì¥¸¥¹¥¿¡£
¥Ç¥Ð¥Ã¥°¤Î»þ¤Ë¥í¡¼¥«¥ëÊÑ¿ô¤Ê¤É¤¬ÇÄ°®¤·¤ä¤¹¤¯¤Ê¤ë¡£

¡Ö¥Õ¥ì¡¼¥à¥Ý¥¤¥ó¥¿¡¼¤Ê¤·¡×¤òÍ­¸ú¤Ë¤¹¤ë¡£
(gcc¤Ç¤Ï -fomit-frame-pointer)

_test PROC
    mov eax, DWORD PTR 12[esp-4]
    add eax, DWORD PTR 8[esp-4]
    ret  0
_test ENDP

ebp¤ò·Ðͳ¤»¤º¤Ëesp¤òľÀܻȤ¦¤è¤¦¤Ë¤Ê¤ë¡£
¥Ç¥£¥¹¥×¥ì¡¼¥¹¥á¥ó¥È¤¬ebp¤ò°Õ¼±¤·¤¿¤â¤Î¤Ë¤Ê¤Ã¤Æ¤¤¤ë¡£
  • 12[esp-4] ¢ª 8[esp]
  • 8[esp-4] ¢ª 4[esp]

¥¹¥¿¥Ã¥¯

¥¹¥¿¥Ã¥¯¤Ï°ì»þŪ¤Ê¾ðÊó¤ò³ÊǼ¤¹¤ë¤Î¤Ë»ÈÍѤ¹¤ë¥á¥â¥êÎΰè
¶ñÂÎŪ¤Ë¤Ï¥í¡¼¥«¥ëÊÑ¿ô¤ä¸Æ¤Ó½Ð¤·ÍúÎò¤Ê¤É¤¬Æþ¤Ã¤Æ¤¤¤ë

FIFO¥Ð¥Ã¥Õ¥¡¡ÊºÇ¸å¤ËÆþ¤ì¤¿¥Ç¡¼¥¿¤¬ºÇ½é¤Ë¼è¤ê½Ð¤µ¤ì¤ë¡Ë
push/popÌ¿Îá¤ÇÁàºî

push dword 1
push dword 2
push dword 3
pop eax
pop ebx
pop ecx

eax: 3
ebx: 2
ecx: 1

¥¹¥¿¥Ã¥¯¤Ïesp¤¬»Ø¤·¤Æ¤¤¤ë
Æþ¤ì¤ëÁ°¤Ë¸º¤é¤·¤Æ¡¢½Ð¤·¤¿¸å¤ËÁý¤ä¤¹

sub esp, 4
mov dword [esp], 1
sub esp, 4
mov dword [esp], 2
sub esp, 4
mov dword [esp], 3
mov eax, [esp]
add esp, 4
mov ebx, [esp]
add esp, 4
mov ecx, [esp]
add esp, 4

Îý½¬: esp=0x10¤È¤·¤ÆÆ°ºî¤ò¥È¥ì¡¼¥¹

´Ø¿ô¤Î´Êñ¤Ê¸Æ¤ÓÊý

; test(2, 3);
push 3
push 2
call test
add esp, 8
  • °ú¿ô¤Ï¸å¤í¤«¤épush¤¹¤ë
  • eax¤Ë·ë²Ì¤¬Æþ¤ë
  • push¤·¤¿Ê¬¤Î¥¹¥¿¥Ã¥¯¤Ï add esp, 8 ¤ÇÌᤷ¤Æ¤¤¤ë
  • pop¤ò»È¤ï¤Ê¤¤¤Î¤ÏÃͤò¼Î¤Æ¤ë¤«¤é
  • ¤³¤Î¤è¤¦¤Ëesp¤¬¤Á¤ç¤³¤Á¤ç¤³Æ°¤¯¤È¤­¡¢ebp¤Ç¤Î¸ÇÄê¤Ë°ÕÌ£¤¬½Ð¤ë

¤¢¤é¤«¤¸¤á°ú¿ô¤ËɬÍפÊʬ¥¹¥¿¥Ã¥¯¤ò³ÎÊݤ¹¤ë¼êË¡¤â¤¢¤ë

sub esp, 8
mov [esp+4], 3
mov [esp], 2
call test
add esp, 8

gcc¤Ç¤Ï´Ø¿ôÁ´ÂΤǰú¿ô¤Ë»È¤¦¥¹¥¿¥Ã¥¯¤ò³ÎÄꤵ¤»¤¿¾å¤Ç¡¢
¥×¥í¥í¡¼¥°¤Ç¤¢¤é¤«¤¸¤á¥¹¥¿¥Ã¥¯¤ò³ÎÊݤ¹¤ë¥³¡¼¥É¤òÅǤ¯¡£
¤½¤Î¤¿¤á¥¢¥»¥ó¥Ö¥ê¤ò½ÐÎϤµ¤»¤Æ¤âpush¤¬½Ð¤Æ¤³¤Ê¤¤¡£

°ú¿ô

´Ø¿ô¤ò¸Æ¤Ó½Ð¤¹callÌ¿Îá¤ÏÌá¤êÀè¤ò¥¹¥¿¥Ã¥¯¤ËÀѤà
  • call test == push eip; jmp test¡Êµ¼»÷¥³¡¼¥É¡Ë
  • ret == pop edx; jmp edx
  • CPU¤Ë¤è¤Ã¤Æ¤Ïµ¼»÷¥³¡¼¥ÉÁêÅö¤ÎÌ¿Îá¤òÌÀ¼¨Åª¤Ë½ñ¤¯¤â¤Î¤¬¤¢¤ë
  • ¾ÜºÙ¤Ïºä°æ¤µ¤ó¤¬Ëܤò¼¹É®Ãæ
http://kozos.jp/books/asm/

°ú¿ô¤òÀѤó¤Ç¸Æ¤Ó½Ð¤·¤¿¾ì¹ç¤Î¥¹¥¿¥Ã¥¯¹½Â¤

push 3
push 2
call test

esp+0: Ìá¤êÀè
esp+4: 2
esp+8: 3

¤½¤Î¤¿¤á¸Æ¤Ó½Ð¤·Àè¤Ç°ú¿ô¤ò [esp+4], [esp+8] ¤È¤·¤Æ¼èÆÀ¤Ç¤­¤ë¡£
°ú¿ô¤ò­¤·¤ÆÊÖ¤¹´Ø¿ô¤Ï°Ê²¼¤ÎÄ̤ꡣ

test:
    mov eax, [esp+4]
    add eax, [esp+8]
    ret

¥¤¥ó¥é¥¤¥ó¥¢¥»¥ó¥Ö¥é

_declspec(naked): ¥×¥í¥í¡¼¥°¤È¥¨¥Ô¥í¡¼¥°¤Î¾Êά¡ÊVC++ÀìÍÑ¡Ë

#include <stdio.h>

int test1(int a, int b) {
    return a + b;
}

_declspec(naked) int test2(int a, int b) {
    _asm {
        mov eax, 4[esp]
        add eax, 8[esp]
        ret
    }
}

int main() {
    printf("test1(2, 3): %d\n", test1(2, 3));
    printf("test2(2, 3): %d\n", test2(2, 3));
}

gcc¤Ë¤Ïnaked¤È¤¤¤¦attribute¤¬¤¢¤ë¤¬¡¢x86¤Ë¤Ï̤Âбþ
´Ø¿ô´Ý¤´¤È¥¤¥ó¥é¥¤¥ó¥¢¥»¥ó¥Ö¥é¤Ç½ñ¤¯¡ÊVC++¤Ç¤Ï¤Ç¤­¤Ê¤¤¡Ë

#include <stdio.h>

int test1(int a, int b) {
    return a + b;
}

extern "C" int test2(int, int);
asm(
"_test2:\n"
"    mov eax, dword ptr [esp+4]\n"
"    add eax, dword ptr [esp+8]\n"
"    ret\n");

int main() {
    printf("test1(2, 3): %d\n", test1(2, 3));
    printf("test2(2, 3): %d\n", test2(2, 3));
}

¥¢¥»¥ó¥Ö¥é¤òIntel·Á¼°¤Ç½ñ¤¤¤Æ¤¤¤ë¤¿¤á¥ª¥×¥·¥ç¥ó¤¬É¬Í×
g++ -masm=intel 03.cpp

test2¤Ëextern "C"¤òÉÕ¤±¤Æ¤¤¤ë¤Î¤Ï¥Þ¥ó¥°¥ê¥ó¥°Âкö
ÉÕ¤±¤Ê¤¤¾ì¹ç¤Ï¤³¤ó¤Ê´¶¤¸

int test2(int, int);
asm(
"__Z5test2ii:\n"
"    mov eax, dword ptr [esp+4]\n"
"    add eax, dword ptr [esp+8]\n"
"    ret\n");

¥Þ¥ó¥°¥ê¥ó¥°µ¬Â§¤ÎÊѲ½¤ËÂбþ¤Ç¤­¤Ê¤¤¤Î¤ÇÈò¤±¤¿¡£
*** ¤ª¤Þ¤±

¥Ç¥Þ¥ó¥°¥ë¤ÎÎã¡ÊÀèƬ¤Î_¤òÍî¤È¤·¤Æ¤«¤éÅϤ¹¡Ë


JIT


¼Â¹Ô»þ¤Ë¥Þ¥·¥ó¥³¡¼¥É¤òÀ¸À®¤·¤Æ¸Æ¤Ó½Ð¤¹¤Î¤¬JIT

NX

ÀΤÏñ¤Ë¥á¥â¥ê¤Ë¥³¡¼¥É¤ò½ñ¤­¹þ¤à¤À¤±¤Ç½ÐÍè¤Æ¤¤¤¿

#include <stdio.h>

unsigned char testf[] = {
    0x8b, 0x44, 0x24, 0x04, // mov eax, [esp+4]
    0x03, 0x44, 0x24, 0x08, // add eax, [esp+8]
    0xc3 // ret
};

int main() {
    auto test = reinterpret_cast<int(*)(int, int)>(&testf);
    printf("test(2, 3): %d\n", test(2, 3));
}

º£¤Ï¥á¥â¥êÊݸî¡ÊNX¥Ó¥Ã¥È¡Ë¤¬Æ¯¤¯¤¿¤á¤³¤Î¥³¡¼¥É¤ÏÍî¤Á¤ë¡£
¥Ò¡¼¥×¤ä¥¹¥¿¥Ã¥¯¤Ç¤Î¥³¡¼¥É¼Â¹Ô¤âƱÍÍ¡£
¢¨ÁÛÄê³°¤Î²Õ½ê¤Ç¥³¡¼¥É¤òÆ°¤«¤¹¤Î¤Ï¥Þ¥ë¥¦¥§¥¢¤Î¾ïÅå¼êÃÊ¡£
*** NXÂкö

ÌÀ¼¨Åª¤Ë¼Â¹Ô²Äǽ°À­¤òÉÕÍ¿¤·¤¿¥Ú¡¼¥¸¤ò³ÎÊݤ·¤Æ¥³¡¼¥É¤ò¥³¥Ô¡¼¤¹¤ë¡£

https://gist.github.com/1225880 (raw.cpp)

#include <windows.h>
#include <stdio.h>
#include <string.h>

unsigned char testf[] = {
    0x8b, 0x44, 0x24, 0x04, // mov eax, [esp+4]
    0x03, 0x44, 0x24, 0x08, // add eax, [esp+8]
    0xc3 // ret
};

int main() {
    auto page = VirtualAlloc(nullptr, sizeof(testf), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    memcpy(page, testf, sizeof(testf));
    auto test = reinterpret_cast<int(*)(int, int)>(page);
    printf("test(2, 3): %d\n", test(2, 3));
    VirtualFree(page, 0, MEM_RELEASE);
}
*** ´Ø¿ô¥Ý¥¤¥ó¥¿·¿¤Î¥³¥Ä¤ß¤¿¤¤¤Ê¤â¤Î¡£

int test(int, int);

¤³¤Î´Ø¿ô¤Î¥Ý¥¤¥ó¥¿·¿¤Ï°Ê²¼¤ÎÄ̤ꡣ

int (*)(int, int)

̾Á°¤ÎÉôʬ¤¬ (*) ¤Ë¤Ê¤Ã¤Æ¤¤¤ë¡£
¾å¤ÎÎã¤Ç¤Ï¤³¤Î·¿¤¬reinterpret_cast¤Ç»È¤ï¤ì¤Æ¤¤¤ë¡£

Xbyak

¥Þ¥·¥ó¥³¡¼¥É¤Ï¤É¤¦¤ä¤Ã¤ÆÀ¸À®¤¹¤ë¤Î¤«¡©
¥é¥¤¥Ö¥é¥ê¤ò»È¤¦¤È¼ê·Ú¡£
  • Xbyak(¥«¥¤¥Ó¥ã¥Ã¥¯)

herumi¤µ¤ó¤Ë¤è¤ë¥¤¥ó¥é¥¤¥ó¥¢¥»¥ó¥Ö¥é´¶³Ð¤ÇJIT¤Ç¤­¤ë¥é¥¤¥Ö¥é¥ê

http://homepage1.nifty.com/herumi/soft/xbyak.html

¥Ø¥Ã¥À¤òinclude¤¹¤ë¤À¤±¤Ç»ÈÍѲÄǽ

https://gist.github.com/1225880 (xbyak.cpp)

#include <stdio.h>
#include "xbyak/xbyak.h"

struct TestFunc : public Xbyak::CodeGenerator {
    TestFunc() {
        mov(eax, ptr[esp+4]);
        add(eax, ptr[esp+8]);
        ret();
    }
};

int main() {
    TestFunc testf;
    auto test = reinterpret_cast<int(*)(int, int)>(
        const_cast<Xbyak::uint8 *>(testf.getCode()));
    printf("test(2, 3): %d\n", test(2, 3));
}

¥Ð¥¤¥Ê¥ê¤ò³Îǧ¤¹¤ë¤¿¤á¤Ë¥À¥ó¥×¤·¤Æ¤ß¤ë¡£


¤³¤Î¼ê¤Î¥é¥¤¥Ö¥é¥ê¤Ï GNU lightning ¤Ê¤É¿§¡¹¤¢¤ë¡£
°Ê²¼¤Îµ­»ö¤Ë¤Þ¤È¤á¤é¤ì¤Æ¤¤¤ë¡£

Brainf*ck¤Ç³Ø¤Ö¥¹¥¯¥ê¥×¥È¸À¸ì½èÍý·Ï¹â®²½¡£
http://d.hatena.ne.jp/hogelog/20100914/p1

¸Æ¤Ó½Ð¤·µ¬Ìó


´Ø¿ô¤Ç°ú¿ô¤äÌá¤êÃͤò¤É¤Î¤è¤¦¤ËÅϤ¹¤«¤È¤¤¤¦µ¬Â§

cdecl
  • C declare
  • ÉáÄ̤ËÄêµÁ¤·¤¿´Ø¿ô¤Ï¤¹¤Ù¤Æ¤³¤ì: int test(int, int);
  • VC++¤Ç¤Ï¥ª¥×¥·¥ç¥ó¤Ç¥Ç¥Õ¥©¥ë¥È¤òÊѹ¹¤Ç¤­¤ë: C/C++ ¢ª ¾ÜºÙÀßÄê
  • °ú¿ô¤Ï¸å¤í¤«¤é¥¹¥¿¥Ã¥¯¤ËÀѤߡ¢Ìá¤êÃͤÏeax¤ÇÊÖ¤¹
  • ¥¹¥¿¥Ã¥¯¤Ï¸Æ¤Ó½Ð¤·Â¦¤ÇÌ᤹
  • º£¤Þ¤Ç°úÍѤ·¤¿Îã¤âcdecl

; test(2, 3);
push 3
push 2
call _test
add esp, 8

_test:
mov eax, [esp+4] add eax, [esp+8] ret

stdcall
  • standard call
  • Win32API¤Îɸ½à¸Æ¤Ó½Ð¤·µ¬Ìó¡£
  • °ú¿ô¤Ï¸å¤í¤«¤é¥¹¥¿¥Ã¥¯¤ËÀѤߡ¢Ìá¤êÃͤÏeax¤ÇÊÖ¤¹
  • ¥¹¥¿¥Ã¥¯¤Ï¸Æ¤Ó½Ð¤µ¤ì¤¿Â¦¤ÇÌ᤹¡£
    • x86¤Ç¤Ïret¤Ë°ú¿ô¤òÅϤ·¤Æ¥¹¥¿¥Ã¥¯¤òÌ᤹¤³¤È¤¬¤Ç¤­¤ë¡£

; test(2, 3);
push 3
push 2
call _test

_test:
mov eax, [esp+4] add eax, [esp+8] ret 8
  • °ú¿ô¤¬¥¼¥í¤Î¤È¤­¤Ïcdecl¤ÈƱ¤¸
  • ²ÄÊÑĹ°ú¿ô¤¬»È¤¨¤Ê¤¤
    • Win32API¤Îwsprintf()¤Ïcdecl
    • w¤ÏWindows¤Ç¥ï¥¤¥É¤Ç¤Ï¤Ê¤¤¡£printf¤Î¥ï¥¤¥ÉÈǤÏswprintf()¤ÇÊÌʪ¡£
*** ´Ø¿ô¥Ý¥¤¥ó¥¿

¥Ý¥¤¥ó¥¿¤Î¥¢¥¹¥¿¡¼¤ÎÁ°¤Ë¸Æ¤Ó½Ð¤·µ¬Ìó¤ò½ñ¤¯¡£

int(_stdcall *p)(int, int) = test;

´Êñ¤Ê³ÎǧÊýË¡¤È¤·¤Æ¡¢·¿¿äÏÀ¤µ¤»¤Æ¥Ä¡¼¥ë¥Á¥Ã¥×¤Ë½Ð¤¹ÊýË¡¤¬¤¢¤ë¡£

auto p = test;

¾åÎã¤Îp¤Ë¥Þ¥¦¥¹¥Ý¥¤¥ó¥¿¤òÅö¤Æ¤Æ¥Ä¡¼¥ë¥Á¥Ã¥×¤ò³Îǧ¤¹¤ë¡£

fastcall
  • ½èÍý·Ï¤Ë¤è¤Ã¤Æµ¬Ì󤬰ۤʤ롣VC++¤Ègcc¤ÏƱ¤¸¡£
  • Borland·Ï¤Ç¤Ï¤è¤¯»È¤ï¤ì¤Æ¤¤¤¿¡£
  • VC++¤Ç¤ÏºÇ½é¤Î2¤Ä¤Î°ú¿ô¤òECX, EDX¡¢»Ä¤ê¤ò¥¹¥¿¥Ã¥¯¤ÇÅϤ¹¡£
  • ¥¹¥¿¥Ã¥¯¤Ï¸Æ¤Ó½Ð¤µ¤ì¤¿Â¦¤ÇÌ᤹¡£

; test(2, 3);
mov edx, 3
mov ecx, 2
call _test

_test:
mov eax, ecx add eax, edx ret
  • °ú¿ô¤¬¥¼¥í¤Î¤È¤­¤Ïcdecl¤ÈƱ¤¸
  • ²ÄÊÑĹ°ú¿ô¤¬»È¤¨¤Ê¤¤
  • °ú¿ô¤ò¥ì¥¸¥¹¥¿ÅϤ·¤¹¤ë¤Î¤ÏRISC¤äx64¤Ë»÷¤Æ¤¤¤ë

thiscall
  • ¥¤¥ó¥¹¥¿¥ó¥¹¥á¥ó¥Ð´Ø¿ô¤Î¸Æ¤Ó½Ð¤·µ¬Ìó
  • ½èÍý·Ï¤Ë¤è¤Ã¤Æµ¬Ì󤬰ۤʤë
  • VC++¤Ç¤Ïthis¥Ý¥¤¥ó¥¿¤òECX¡¢°ú¿ô¤ò¥¹¥¿¥Ã¥¯¤ÇÅϤ¹¡£
  • ¥¹¥¿¥Ã¥¯¤Ï¸Æ¤Ó½Ð¤µ¤ì¤¿Â¦¤ÇÌ᤹¡£²ÄÊÑĹ°ú¿ô¤Ï¸Æ¤Ó½Ð¤·¤¿Â¦¤ÇÌ᤹¡£

; reinterpret_cast<Test *>(2)->test(3);
mov ecx, 2
push 3
call ?test@Test@@QAEHH@Z

; struct Test { int test(int a) { return a; } };
?test@Test@@QAEHH@Z:
mov eax, [esp+4] ret 4
  • g++¤ÏºÇ½é¤Î°ú¿ô¤È¤·¤Æthis¤òÅϤ¹cdecl
  • int Test::foo(int a) ­ð int foo(Test *this, int a)
  • ¸å½Ò¤Îthiscall¤ËÂФ¹¤ë¥µ¥ó¥¯¤ÏÊ̤˼ÂÁõ¤¹¤ëɬÍפ¬¤¢¤ë

; reinterpret_cast<Test *>(2)->test(3);
push 3
push 2
call __ZN4Test4testEi
add esp, 8

; struct Test { int test(int a) { return a; } };
__ZN4Test4testEi:
mov eax, [esp+8] ret

ÌäÂê

[Ìä] stdcall¤Î´Ø¿ô¤ò¥µ¥ó¥¯¤Çcdecl¤ËÊÑ´¹¤·¤Æ¤¯¤À¤µ¤¤¡£
¶ñÂÎŪ¤Ë¤Ï¡¢°Ê²¼¤ÎConv¤òXbyak¤Ç¼ÂÁõ¤·¤Æ¤¯¤À¤µ¤¤¡£

#include <stdio.h>
#include "xbyak/xbyak.h"

void call(int(*p)(int, int), int a, int b) {
    printf("%d\n", p(a, b));
}

int _stdcall test(int a, int b) { return a + b; }

int main() {
    Conv c(test);
    auto f = reinterpret_cast<int(*)(int, int)>(
        const_cast<Xbyak::uint8 *>(c.getCode()));
    call(f, 2, 3);
}

²óÅúÎã

struct Conv : public Xbyak::CodeGenerator {
    Conv(int(_stdcall *p)(int, int)) {
        push(ptr[esp+8]);
        push(ptr[esp+8]);
        call(p);
        ret();
    }
};

´Ø¿ô·¿


C++¤Ç´Ø¿ô¤ò·¿¤È¤·¤Æ°·¤¦ÊýË¡¤Ê¤É¡£

´Ø¿ô¥Ý¥¤¥ó¥¿

´Ø¿ô¤òÅϤ·¤Æ¸Æ¤Ö¡£

#include <stdio.h>

void test(int a) {
    printf("%d\n", a);
}

int main() {
    auto f = test;
    f(1);
}

static¥á¥ó¥Ð¤âƱ¤¸¤è¤¦¤Ë°·¤¨¤ë¡£

#include <stdio.h>

struct Test {
    static void show(int n) {
        printf("%d\n", n);
    }
};

int main() {
    auto f = Test::show;
    f(1);
}

·¿¤¬Æ±¤¸¤Ê¤Î¤Ç¡¢Æ±¤¸´Ø¿ô¤ËÅϤ·¤Æ¸Æ¤Ó½Ð¤»¤ë¡£

#include <stdio.h>

void test(int a) {
    printf("%d\n", a);
}

struct Test {
    static void show(int n) {
        printf("%d\n", n);
    }
};

void call(void (*f)(int), int a) {
    f(a);
}

int main() {
    call(test, 1);
    call(Test::show, 1);
}

¥á¥ó¥Ð´Ø¿ô¥Ý¥¤¥ó¥¿

¹½Ê¸¤¬Ìñ²ð¡£

#include <stdio.h>

struct Test {
    int n;
    Test(int n) : n(n) {}
    void show() {
        printf("%d\n", n);
    }
};

int main() {
    Test t(1);
    auto f = &Test::show;
    (t.*f)();
}

auto¤¬¤Ê¤¤¤ÈÈó¾ï¤ËÌÌÅÝ¡£

void (Test::*f)() = &Test::show;

Èó¥á¥ó¥Ð´Ø¿ô¤Î¥Ý¥¤¥ó¥¿¤ò¼è¤ë¤È¤­¤Ë¤Ï & ¤¬¾Êά¤Ç¤­¤ë¤¬¡¢
¥á¥ó¥Ð´Ø¿ô¤Ç¤Ï¾Êά¤Ç¤­¤Ê¤¤¡£
²¼¤ÎÎã¤Ç¤Ïf1¤Èf2¤ÏƱ¤¸¡£

void test();
struct Test { void test(); } t;

¡û auto f1 = test;
¡û auto f2 = &test;
¡ß auto f3 = Test::test;
¡û auto f4 = &Test::test;

¸Æ¤Ó½Ð¤·»þ¤Î»²¾ÈÇí¤¬¤·¤Ë¤Ä¤¤¤Æ¤âƱÍÍ¡£
¤È¤¤¤¦¤è¤êC++¤Ç¤Ï .* ¤Ç1¤Ä¤Î±é»»»Ò¤Ë¤Ê¤Ã¤Æ¤¤¤ë¤·¡¢
¤½¤¦¤Ç¤Ê¤¤¤È¤¿¤À¤Î¥á¥ó¥Ð¥¢¥¯¥»¥¹¤È¶èÊ̤¬ÉÕ¤«¤Ê¤¤¡£

¡û f2();
¡û (*f2)();
¡ß (t.f4)();
¡û (t.*f4)();

static¤Î̵ͭ¤Ç¸ß´¹À­¤¬¤Ê¤¯¤Ê¤ë¡£·¿¤â¥¯¥é¥¹¤Ë°Í¸¤¹¤ë¡£

https://gist.github.com/1273084

#include <stdio.h>

struct Test1 {
    int n;
    Test1(int n) : n(n) {}
    void show() {
        printf("%d\n", n);
    }
};

struct Test2 {
    int n;
    Test2(int n) : n(n) {}
    void show() {
        printf("%d\n", n);
    }
};

struct Test3 {
    static void show() {
        printf("?\n");
    }
};

void show() {
    printf("!\n");
}

void call(void (*f)()) { f(); }

int main() {
    Test1 t1(1);
    Test2 t2(2);
    auto f1 = &Test1::show;
    auto f2 = &Test2::show;
    auto f3 = &Test3::show;
    auto f4 = &show;
    (t1.*f1)();
    (t2.*f2)();
    (*f3)();
    (*f4)();
    call(f3);
    call(f4);
}

f1 != f2 != (f3 == f4)
  • ¥¤¥ó¥¹¥¿¥ó¥¹¥á¥ó¥Ð¤È¥¯¥é¥¹¥á¥ó¥Ð¤Ï°·¤¤¤¬°Û¤Ê¤ë¡£
  • ¥¯¥é¥¹¥á¥ó¥Ð¡Êstatic¡Ë¤ÈÈó¥á¥ó¥Ð¤ÏƱ¤¸°·¤¤¡£Æ±¤¸¤è¤¦¤Ëcall()¤ËÅϤ»¤ë¡£
  • ¥¤¥ó¥¹¥¿¥ó¥¹¥á¥ó¥Ð¤Ï·¿¤Ë¥¯¥é¥¹Ì¾¤¬Æþ¤ë¤¿¤á¡¢f1¤Èf2¤Ï·¿¤¬°Û¤Ê¤ë¡£

¤È¤ê¤¢¤¨¤ºÆ±¤¸·¿¤È¤·¤Æ°·¤¦¤Ë¤Ï¤É¤¦¤¹¤ë¤«¡£

´Ø¿ô¥ª¥Ö¥¸¥§¥¯¥È

´Ø¿ô¤Î¤è¤¦¤Ë¿¶Éñ¤¦¥¯¥é¥¹¡£

#include <stdio.h>

struct Test {
    int n;
    Test(int n) : n(n) {}
    void operator()() {
        printf("%d\n", n);
    }
};

int main() {
    Test t(1);
    t();
}

C++11¤Ç¤Ï¥é¥à¥À¼°¤Ë¤è¤ê´Êñ¤Ë´Ø¿ô¥ª¥Ö¥¸¥§¥¯¥È¤¬ºî¤ì¤ë¡£
°Ê²¼¤Ît¤Ï¥é¥à¥À¼°¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿´Ø¿ô¥ª¥Ö¥¸¥§¥¯¥È¡£

#include <stdio.h>

int main() {
    int n = 1;
    auto t = [n] { printf("%d\n", n); };
    t();
}

ɸ½à¥é¥¤¥Ö¥é¥ê¤Ë¤Ï std::function ¤È¤¤¤¦
´Ø¿ô¥Ý¥¤¥ó¥¿¤Î¤è¤¦¤Ë»È¤¦´Ø¿ô¥ª¥Ö¥¸¥§¥¯¥È¤¬¤¢¤ë¡£
std::bind()¤ä¥é¥à¥À¼°¤Ê¤É¤Ç¥á¥ó¥Ð´Ø¿ô¤òÅϤ»¤ë¡£

¤³¤ì¤ò»È¤¦¤È¥á¥ó¥Ð¡¦Èó¥á¥ó¥Ð¤òÅý¹ç¤·¤Æ°·¤¨¤ë¤è¤¦¤Ë¤Ê¤ë¡£

https://gist.github.com/1273115

#include <functional>
#include <stdio.h>

struct Test1 {
    int n;
    Test1(int n) : n(n) {}
    void show() {
        printf("%d\n", n);
    }
};

struct Test2 {
    int n;
    Test2(int n) : n(n) {}
    void show() {
        printf("%d\n", n);
    }
};

struct Test3 {
    static void show() {
        printf("?\n");
    }
};

void show() {
    printf("!\n");
}

void call(const std::function<void()> &f) {
    f();
}

int main() {
    Test1 t1(1);
    Test2 t2(2);
    auto f1 = std::bind(&Test1::show, &t1);
    auto f2 = [&] { t2.show(); };
    auto f3 = Test3::show;
    auto f4 = show;
    call(f1);
    call(f2);
    call(f3);
    call(f4);
}
*** ¤ª¤Þ¤±

Èæ³Ó¤Î¤¿¤áF#¤Ë°Ü¿¢¡£

type Test1(n) =
    member x.show() = printfn "%d" n

type Test2(n) =
    member x.show() = printfn "%d" n

type Test3 =
    static member show() = printfn "?"

let show() = printfn "!"

let call f = f()

let t1 = new Test1(1)
let t2 = new Test2(2)
let d1 = t1.show
let d2 = fun() -> t2.show()
let d3 = Test3.show
let d4 = show
call d1
call d2
call d3
call d4

d1, d2, d3, d4¤Ï¤¹¤Ù¤ÆƱ¤¸·¿: unit->unit

¥µ¥ó¥¯


C++¤È¸Å¤¤API¤Î¶¶ÅϤ·¤È¤·¤Æ¼Â¹Ô»þ¥³¡¼¥ÉÀ¸À®¤òÍøÍѤ¹¤ë¡£

JIT¤Ë¤è¤ë¥é¥Ã¥Ñ¡¼

¥³¡¼¥É¤¬C++¤ÇÊĤ¸¤Æ¤¤¤ë¤Ê¤é´Ø¿ô¥ª¥Ö¥¸¥§¥¯¥È¤Ç½¼Ê¬¡£
¤·¤«¤·OS¤ÎAPI¤Ç´Ø¿ô¥Ý¥¤¥ó¥¿·¿¤¬»ØÄꤵ¤ì¤Æ¤¤¤ë¾ì¹ç¤Ê¤É¡¢
´Ø¿ô¥ª¥Ö¥¸¥§¥¯¥È¤ò¤½¤Î¤Þ¤Þ»È¤¨¤Ê¤¤¥±¡¼¥¹¤¬¤¢¤ë¡£

JIT¤Ç¥é¥Ã¥Ñ¡¼¤òºî¤Ã¤Æ¤·¤Þ¤¨¤Ð²ò·è¡ª

https://gist.github.com/1225997

#include <stdio.h>
#include "xbyak/xbyak.h"

template <class T>
struct Delegate : public Xbyak::CodeGenerator {
    Delegate(T *t, void (T::*p)()) {
        mov(ecx, reinterpret_cast<intptr_t>(t));
        jmp(*reinterpret_cast<void **>(&p));
    }

    void (*getPtr())() {
        return reinterpret_cast<void (*)()>(
            const_cast<Xbyak::uint8 *>(getCode()));
    }
};

struct Test1 {
    int n;
    Test1(int n) : n(n) {}
    void show() {
        printf("%d\n", n);
    }
};

struct Test2 {
    int n;
    Test2(int n) : n(n) {}
    void show() {
        printf("%d\n", n);
    }
};

struct Test3 {
    static void show() {
        printf("?\n");
    }
};

void show() {
    printf("!\n");
}

void call(void (*f)()) { f(); }

int main() {
    Test1 t1(1);
    Test2 t2(2);
    Delegate<Test1> d1(&t1, &Test1::show);
    Delegate<Test2> d2(&t2, &Test2::show);
    call(d1.getPtr());
    call(d2.getPtr());
    call(Test3::show);
    call(show);
}
  • ¥á¥ó¥Ð´Ø¿ô¥Ý¥¤¥ó¥¿¤Ë¥¤¥ó¥¹¥¿¥ó¥¹¤òËä¤á¹þ¤ó¤Ç´Ø¿ô¥Ý¥¤¥ó¥¿¤ËÊÑ´¹¡£
  • ¤³¤ÎJIT¥é¥Ã¥Ñ¡¼¤¬º£²ó¤Î¥á¥¤¥ó¥Æ¡¼¥Þ¤Ç¤¢¤ë¥µ¥ó¥¯¡£
  • gcc¤Ç¤Ïthiscall¤¬°Û¤Ê¤ë¤¿¤á¤½¤Î¤Þ¤Þ¤Ç¤ÏÆ°¤«¤Ê¤¤¡£
*** ´Ø¿ô¥Ý¥¤¥ó¥¿¤òÊÖ¤¹´Ø¿ô

void (*getPtr())();
  • getPtr() ¤¬´Ø¿ô̾¤È°ú¿ô¤Ç¡¢¤½¤ì°Ê³°¤Î void (*)() ¤¬Ìá¤êÃͤη¿¡£
  • void (*f)() ¤ÏÊÑ¿ô¤Ç¡¢f¤ÎÉôʬ¤Ë°ú¿ô¤òÉÕ¤±¤¿¤é´Ø¿ô¡£

°ú¿ô¤¬¤¢¤ë¾ì¹ç

VC++¤Îthiscall¤Ç¤Ï¸Æ¤Ó½Ð¤·À褬°ú¿ô¤Î¥¹¥¿¥Ã¥¯¤òÊÒÉÕ¤±¤ë¤¿¤á¡¢
¥µ¥ó¥¯¤Ç¤Ïcdecl¤È¤ÎÊÑ´¹¤¬É¬ÍפȤʤ롣

https://gist.github.com/1273062

#include <stdio.h>
#include "xbyak/xbyak.h"

template <class T, class TA1>
struct Thunk : public Xbyak::CodeGenerator {
    Thunk(T *t, void (T::*p)(TA1)) {
        mov(ecx, reinterpret_cast<intptr_t>(t));
        push(ptr[esp+4]);
        call(*reinterpret_cast<void **>(&p));
        ret();
    }

    void (*getPtr())(TA1) {
        return reinterpret_cast<void (*)(TA1)>(
            const_cast<Xbyak::uint8 *>(getCode()));
    }
};

struct Test {
    int n;
    Test(int n) : n(n) {}
    void show(int n2) {
        printf("%d, %d\n", n, n2);
    }
};

void show(int n) {
    printf("%d\n", n);
}

void call(void (*f)(int), int n) { f(n); }

int main() {
    Test t(1);
    Thunk<Test, int> thunk(&t, &Test::show);
    call(thunk.getPtr(), 2);
    call(show, 3);
}

void (*getPtr())(TA1)
  • getPtr()¤¬´Ø¿ô̾¤È°ú¿ô
  • ¤½¤ì°Ê³°¤Î void (*)(TA1) ¤¬Ìá¤êÃͤη¿

ÉôʬŬÍÑ

¥µ¥ó¥¯¤Ë°ú¿ô¤òËä¤á¹þ¤á¤ÐÉôʬŬÍѤ¬²Äǽ¡£

#include <stdio.h>
#include "xbyak/xbyak.h"

struct Bind : public Xbyak::CodeGenerator {
    Bind(int(*f)(int, int), int a) {
        push(a);
        push(ptr[esp+8]);
        call(reinterpret_cast<void *>(f));
        add(esp, 8);
        ret();
    }

    int(*getPtr())(int) {
        return reinterpret_cast<int(*)(int)>(
            const_cast<Xbyak::uint8 *>(getCode()));
    }
};

int add(int a, int b) { return a + b; }

void call(int(*p)(int), int a) {
    printf("%d\n", p(a));
}

int main() {
    Bind inc(add, 1);
    call(inc.getPtr(), 2);
}

¤·¤«¤·¤³¤ì¤Ï¤ä¤í¤¦¤È»×¤¨¤Ð½ÐÍè¤ë¡¢ÄøÅ٤Υͥ¿¡£
std::bind¤ÇÉôʬŬÍѤ·¤Æ¤«¤é¥µ¥ó¥¯¤ËÆþ¤ì¤¿Êý¤¬¥¹¥Þ¡¼¥È¡£

#include <functional>
#include <stdio.h>
#include "xbyak/xbyak.h"

template <class T, class TA1, class TR>
struct Thunk : public Xbyak::CodeGenerator {
    Thunk(T *f) {
        mov(ecx, reinterpret_cast<intptr_t>(f));
        push(ptr[esp+4]);
        auto p = &T::operator();
        call(*reinterpret_cast<void **>(&p));
        ret();
    }

    TR(*getPtr())(TA1) {
        return reinterpret_cast<TR(*)(TA1)>(
            const_cast<Xbyak::uint8 *>(getCode()));
    }
};

int add(int a, int b) { return a + b; }

void call(int(*p)(int), int a) {
    printf("%d\n", p(a));
}

int main() {
    std::function<int(int)> inc =
        std::bind(add, std::placeholders::_1, 1);
    Thunk<decltype(inc), int, int> thunk(&inc);
    call(thunk.getPtr(), 2);
}

¤³¤Î¤è¤¦¤Ë²Äǽ¤Ê¸Â¤êC++¤ÎÈÏ°ÏÆâ¤Ç°·¤Ã¤Æ¡¢¥µ¥ó¥¯¤ÏºÇ½ª¼êÃÊ¡£

¥¯¥í¡¼¥¸¥ã

¥­¥ã¥×¥Á¥ã¤òÉôʬŬÍѤÇɽ¸½¤¹¤ì¤Ð¡¢¥µ¥ó¥¯¤Ç¥¯¥í¡¼¥¸¥ã¤¬ºî¤ì¤ë¡£

https://gist.github.com/1226147

#include <functional>
#include <stdio.h>
#include "xbyak/xbyak.h"

void call(void (*f)()) { f(); }

int main() {
    int a = 1;
    struct _ : public Xbyak::CodeGenerator {
        _(int *a) {
            push(reinterpret_cast<intptr_t>(a));
            call(reinterpret_cast<void *>(run));
            add(esp, 4);
            ret();
        }

        static void run(int &a) {
            printf("%d\n", a++);
        }
    } closure(&a);
    auto f = reinterpret_cast<void (*)()>(
        const_cast<Xbyak::uint8 *>(closure.getCode()));
    f();
    f();
    call(f);
}

¤³¤ì¤ÏÆȼ«¤Ë¸À¸ì¤òºî¤ë¾ì¹ç¤Ï»È¤¨¤ë¼êË¡¤À¤È»×¤¦¤¬¡¢
¸À¸ì»ÅÍͤǥ¯¥í¡¼¥¸¥ã¤ò»ý¤ÄC++11¤Ç´º¤¨¤Æ¤ä¤ë°ÕÌ£¤ÏÇö¤¤¡£

ÉáÄ̤ËC++¤Çºî¤Ã¤¿¥¯¥í¡¼¥¸¥ã¤ò¥µ¥ó¥¯¤ÇÊñ¤ó¤ÀÊý¤¬¥·¥ó¥×¥ë¡£

https://gist.github.com/1273073

#include <functional>
#include <stdio.h>
#include "xbyak/xbyak.h"

template <class T>
struct Thunk : public Xbyak::CodeGenerator {
    Thunk(T *f) {
        mov(ecx, reinterpret_cast<intptr_t>(f));
        auto p = &T::operator();
        jmp(*reinterpret_cast<void **>(&p));
    }

    void (*getPtr())() {
        return reinterpret_cast<void (*)()>(
            const_cast<Xbyak::uint8 *>(getCode()));
    }
};

void call(void (*f)()) { f(); }

int main() {
    int a = 1;
    auto f = [&] { printf("%d\n", a++); };
    f();
    f();
    Thunk<decltype(f)> thunk(&f);
    auto f2 = thunk.getPtr();
    f2();
    call(f2);
}

Win32API


[Ìä] Windows¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¤Î¿÷·Á¤ò²þ¤¤·¤Æ¡¢°Ê²¼¤ò¥á¥ó¥Ð´Ø¿ô¤Ë¤·¤Æ¤¯¤À¤µ¤¤¡£

ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

¢­

class Window {
public:
ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE hInstance, int nCmdShow); LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
};
  • ¥á¥ó¥Ð¤ÏŬµ¹Äɲ䷤Ƥ¯¤À¤µ¤¤¡£
  • CALLBACK¤Ïstdcall¤ò°ÕÌ£¤·¤Þ¤¹¡£

²óÅúÎã

https://gist.github.com/1226294

--- win32thunk.cpp.orig
+++ win32thunk.cpp
@@ -3,6 +3,7 @@
 
 #include "stdafx.h"
 #include "win32thunk.h"
+#include "xbyak/xbyak.h"
 
 #define MAX_LOADSTRING 100
 
@@ -12,11 +13,25 @@
 TCHAR szWindowClass[MAX_LOADSTRING];			// ¥á¥¤¥ó ¥¦¥£¥ó¥É¥¦ ¥¯¥é¥¹Ì¾
 
 // ¤³¤Î¥³¡¼¥É ¥â¥¸¥å¡¼¥ë¤Ë´Þ¤Þ¤ì¤ë´Ø¿ô¤ÎÀë¸À¤òžÁ÷¤·¤Þ¤¹:
-ATOM				MyRegisterClass(HINSTANCE hInstance);
-BOOL				InitInstance(HINSTANCE, int);
-LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
 INT_PTR CALLBACK	About(HWND, UINT, WPARAM, LPARAM);
 
+template <class T, class TA1, class TA2, class TA3, class TA4, class TR>
+struct StdCallThunk : public Xbyak::CodeGenerator {
+    void init(T *t, TR(T::*p)(TA1, TA2, TA3, TA4)) {
+        mov(ecx, reinterpret_cast<intptr_t>(t));
+        jmp(*reinterpret_cast<void **>(&p));
+    }
+};
+
+class Window {
+protected:
+    StdCallThunk<Window, HWND, UINT, WPARAM, LPARAM, LRESULT> wndProc;
+public:
+    ATOM MyRegisterClass(HINSTANCE hInstance);
+    BOOL InitInstance(HINSTANCE hInstance, int nCmdShow);
+    LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+};
+
 int APIENTRY _tWinMain(HINSTANCE hInstance,
                      HINSTANCE hPrevInstance,
                      LPTSTR    lpCmdLine,
@@ -32,10 +47,11 @@
 	// ¥°¥í¡¼¥Ð¥ëʸ»úÎó¤ò½é´ü²½¤·¤Æ¤¤¤Þ¤¹¡£
 	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
 	LoadString(hInstance, IDC_WIN32THUNK, szWindowClass, MAX_LOADSTRING);
-	MyRegisterClass(hInstance);
+	Window win;
+	win.MyRegisterClass(hInstance);
 
 	// ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¤Î½é´ü²½¤ò¼Â¹Ô¤·¤Þ¤¹:
-	if (!InitInstance (hInstance, nCmdShow))
+	if (!win.InitInstance (hInstance, nCmdShow))
 	{
 		return FALSE;
 	}
@@ -70,14 +86,16 @@
 //    Àµ¤·¤¤·Á¼°¤Î¾®¤µ¤¤¥¢¥¤¥³¥ó¤ò¼èÆÀ¤Ç¤­¤ë¤è¤¦¤Ë¤¹¤ë¤Ë¤Ï¡¢
 //    ¤³¤Î´Ø¿ô¤ò¸Æ¤Ó½Ð¤·¤Æ¤¯¤À¤µ¤¤¡£
 //
-ATOM MyRegisterClass(HINSTANCE hInstance)
+ATOM Window::MyRegisterClass(HINSTANCE hInstance)
 {
+	wndProc.init(this, &Window::WndProc);
+
 	WNDCLASSEX wcex;
 
 	wcex.cbSize = sizeof(WNDCLASSEX);
 
 	wcex.style			= CS_HREDRAW | CS_VREDRAW;
-	wcex.lpfnWndProc	= WndProc;
+	wcex.lpfnWndProc	= (WNDPROC)wndProc.getCode();
 	wcex.cbClsExtra		= 0;
 	wcex.cbWndExtra		= 0;
 	wcex.hInstance		= hInstance;
@@ -101,7 +119,7 @@
 //        ¤³¤Î´Ø¿ô¤Ç¡¢¥°¥í¡¼¥Ð¥ëÊÑ¿ô¤Ç¥¤¥ó¥¹¥¿¥ó¥¹ ¥Ï¥ó¥É¥ë¤òÊݸ¤·¡¢
 //        ¥á¥¤¥ó ¥×¥í¥°¥é¥à ¥¦¥£¥ó¥É¥¦¤òºîÀ®¤ª¤è¤Óɽ¼¨¤·¤Þ¤¹¡£
 //
-BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
+BOOL Window::InitInstance(HINSTANCE hInstance, int nCmdShow)
 {
    HWND hWnd;
 
@@ -131,7 +149,7 @@
 //  WM_DESTROY	- Ãæ»ß¥á¥Ã¥»¡¼¥¸¤òɽ¼¨¤·¤ÆÌá¤ë
 //
 //
-LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+LRESULT Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
 	int wmId, wmEvent;
 	PAINTSTRUCT ps;

°Ñ¾ù


¥¤¥Ù¥ó¥È¥Ï¥ó¥É¥é¤ò´Ø¿ô¥ª¥Ö¥¸¥§¥¯¥È²½¤·¤Æ°Ñ¾ù¥â¥Ç¥ë²½¡£
  • ¥Ï¥ó¥É¥ë¤Ï¤¢¤Á¤³¤Á¤Ç»È¤¦¤Î¤Ç¡¢Window¥¯¥é¥¹¤Îpublic¥á¥ó¥Ð¤ËÄɲá£
  • Window::InitInstance()¤Ç¥í¡¼¥«¥ëÊÑ¿ô¤ÎÀë¸À¤òºï½ü¡£

¤³¤ì¤Ç¼«Æ°Åª¤Ë¥á¥ó¥Ð¤ÎÊý¤ËÂåÆþ¤µ¤ì¤ë¡£

--- win32thunk.cpp.orig
+++ win32thunk.cpp
@@ -27,6 +27,7 @@
 protected:
     StdCallThunk<Window, HWND, UINT, WPARAM, LPARAM, LRESULT> wndProc;
 public:
+    HWND hWnd;
     ATOM MyRegisterClass(HINSTANCE hInstance);
     BOOL InitInstance(HINSTANCE hInstance, int nCmdShow);
     LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
@@ -121,8 +122,6 @@
 //
 BOOL Window::InitInstance(HINSTANCE hInstance, int nCmdShow)
 {
-   HWND hWnd;
-
    hInst = hInstance; // ¥°¥í¡¼¥Ð¥ëÊÑ¿ô¤Ë¥¤¥ó¥¹¥¿¥ó¥¹½èÍý¤ò³ÊǼ¤·¤Þ¤¹¡£
 
    hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,

Command


WM_COMMAND¤ò°Ñ¾ù²½

¤¢¤Þ¤ê½¤Àµ¤·¤Ê¤¤¥Ø¥Ã¥À¤Ïstdafx.h¤Ë²¡¤·¹þ¤à¤È¥Ó¥ë¥É¤¬Â®¤¯¤Ê¤ë¡£

 // TODO: ¥×¥í¥°¥é¥à¤ËɬÍפÊÄɲåإåÀ¡¼¤ò¤³¤³¤Ç»²¾È¤·¤Æ¤¯¤À¤µ¤¤¡£
+#include <list>
+#include <functional>
+#include "xbyak/xbyak.h"

Window¥¯¥é¥¹¤Îpublic¥á¥ó¥Ð¤ËÄɲÃ

¢¨list¤ËÆþ¤ì¤ë¤³¤È¤Ç¥Þ¥ë¥Á¥­¥ã¥¹¥È¤ò²Äǽ¤Ë¤·¤Æ¤¤¤ë¡£

    std::list<std::function<bool(int, int)>> Command;

Window::WndProc¤ÇÂбþ

¢¨for each¤ÏVC++¤ÎÆȼ«³ÈÄ¥¤Ê¤Î¤Ç¡¢Å¬µ¹½¤Àµ¤·¤Æ¤¯¤À¤µ¤¤¡£

    case WM_COMMAND:
        for each (auto f in Command)
            if (f(LOWORD(wParam), HIWORD(wParam)))
                return 0;
        return DefWindowProc(hWnd, message, wParam, lParam);

¥¤¥Ù¥ó¥È¤òÀßÄê

    win.Command.push_back([&](int id, int e)->bool {
        // ÁªÂò¤µ¤ì¤¿¥á¥Ë¥å¡¼¤Î²òÀÏ:
        switch (id)
        {
        case IDM_ABOUT:
            DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), win.hWnd, About);
            return true;
        case IDM_EXIT:
            DestroyWindow(win.hWnd);
            return true;
        }
        return false;
    });

Paint


WM_PAINT¤ò°Ñ¾ù²½

Window¥¯¥é¥¹¤Îpublic¥á¥ó¥Ð¤ËÄɲÃ

    std::list<std::function<void(HDC)>> Paint;

Window::WndProc¤ÇÂбþ

    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        // TODO: ÉÁ²è¥³¡¼¥É¤ò¤³¤³¤ËÄɲ䷤Ƥ¯¤À¤µ¤¤...
        for each (auto f in Paint) f(hdc);
        EndPaint(hWnd, &ps);
        break;

¥¤¥Ù¥ó¥È¤òÀßÄê

    win.Paint.push_back([&](HDC hdc) {
        auto oldPen = (HPEN)SelectObject(hdc, GetStockObject(BLACK_PEN));
        auto oldBrush = (HBRUSH)SelectObject(hdc, GetStockObject(GRAY_BRUSH));
        Rectangle(hdc, 10, 10, 40, 40);
        SelectObject(hdc, oldPen);
        SelectObject(hdc, oldBrush);
    });

»Í³Ñ¤¬É½¼¨¤µ¤ì¤ë¡£

¥Þ¥¦¥¹¥¤¥Ù¥ó¥È


¥Þ¥¦¥¹¥Ü¥¿¥ó´Ø·¸¤Î¥á¥Ã¥»¡¼¥¸¤ò°Ñ¾ù²½¡£

stdafx.h¤ËÄɲÃ

#include <windowsx.h>

Window¥¯¥é¥¹¤Îpublic¥á¥ó¥Ð¤ËÄɲÃ

    std::list<std::function<void(int, int, int, WPARAM)>> MouseDown, MouseUp;
    std::list<std::function<void(int, int, WPARAM)>> MouseMove;

Window¥¯¥é¥¹¤Îprotected¥á¥ó¥Ð¤ËÄɲÃ

    void OnMouseDown(int button, WPARAM wParam, LPARAM lParam) {
        int x = GET_X_LPARAM(lParam), y = GET_Y_LPARAM(lParam);
        for each (auto f in MouseDown) f(button, x, y, wParam);
    }
    void OnMouseUp(int button, WPARAM wParam, LPARAM lParam) {
        int x = GET_X_LPARAM(lParam), y = GET_Y_LPARAM(lParam);
        for each (auto f in MouseUp) f(button, x, y, wParam);
    }

Window::WndProc¤ÇÂбþ

    case WM_LBUTTONDOWN: OnMouseDown(1, wParam, lParam); break;
    case WM_RBUTTONDOWN: OnMouseDown(2, wParam, lParam); break;
    case WM_MBUTTONDOWN: OnMouseDown(3, wParam, lParam); break;
    case WM_XBUTTONDOWN: OnMouseDown(3 + HIWORD(wParam), LOWORD(wParam), lParam); break;
    case WM_LBUTTONUP: OnMouseUp(1, wParam, lParam); break;
    case WM_RBUTTONUP: OnMouseUp(2, wParam, lParam); break;
    case WM_MBUTTONUP: OnMouseUp(3, wParam, lParam); break;
    case WM_XBUTTONUP: OnMouseUp(3 + HIWORD(wParam), LOWORD(wParam), lParam); break;
    case WM_MOUSEMOVE:
        for each (auto f in MouseMove)
            f(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), wParam);
        break;

¥³¡¼¥É¤ÎÀ°Íý


¤³¤³¤Þ¤Ç¤Î¥½¡¼¥¹¡£

https://gist.github.com/1273003

¤Á¤ç¤Ã¤ÈŤ¤¤Î¤Ç¡¢¥½¡¼¥¹¤òʬ³ä¤·¤ÆÀ°Íý¡£

https://gist.github.com/1274679

Window.h

#pragma once

#include <list>
#include <functional>
#include <string>
#include <windows.h>
#include "xbyak/xbyak.h"

template <class T, class TA1, class TA2, class TA3, class TA4, class TR>
struct StdCallThunk : public Xbyak::CodeGenerator {
    void init(T *t, TR(T::*p)(TA1, TA2, TA3, TA4)) {
        mov(ecx, reinterpret_cast<intptr_t>(t));
        jmp(*reinterpret_cast<void **>(&p));
    }
};

typedef std::basic_string<TCHAR> tstring;

class Window {
protected:
    HINSTANCE hInst;
    tstring windowClass;
    StdCallThunk<Window, HWND, UINT, WPARAM, LPARAM, LRESULT> wndProc;
    void OnMouseDown(int button, WPARAM wParam, LPARAM lParam);
    void OnMouseUp(int button, WPARAM wParam, LPARAM lParam);

public:
    HWND hWnd;
    ATOM MyRegisterClass(HINSTANCE hInstance, const tstring &windowClass);
    BOOL InitInstance(const tstring &title, int nCmdShow);
    LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

    std::list<std::function<bool(int, int)>> Command;
    std::list<std::function<void(HDC)>> Paint;
    std::list<std::function<void(int, int, int, WPARAM)>> MouseDown, MouseUp;
    std::list<std::function<void(int, int, WPARAM)>> MouseMove;
};

Window.cpp

#include "stdafx.h"
#include "resource.h"

void Window::OnMouseDown(int button, WPARAM wParam, LPARAM lParam) {
    int x = GET_X_LPARAM(lParam), y = GET_Y_LPARAM(lParam);
    for each (auto f in MouseDown) f(button, x, y, wParam);
}

void Window::OnMouseUp(int button, WPARAM wParam, LPARAM lParam) {
    int x = GET_X_LPARAM(lParam), y = GET_Y_LPARAM(lParam);
    for each (auto f in MouseUp) f(button, x, y, wParam);
}

//
//  ´Ø¿ô: Window::MyRegisterClass()
//
//  ÌÜŪ: ¥¦¥£¥ó¥É¥¦ ¥¯¥é¥¹¤òÅÐÏ¿¤·¤Þ¤¹¡£
//
//  ¥³¥á¥ó¥È:
//
//    ¤³¤Î´Ø¿ô¤ª¤è¤Ó»È¤¤Êý¤Ï¡¢'RegisterClassEx' ´Ø¿ô¤¬Äɲ䵤줿
//    Windows 95 ¤è¤êÁ°¤Î Win32 ¥·¥¹¥Æ¥à¤È¸ß´¹¤µ¤»¤ë¾ì¹ç¤Ë¤Î¤ßɬÍפǤ¹¡£
//    ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¤¬¡¢´ØÏ¢ÉÕ¤±¤é¤ì¤¿
//    Àµ¤·¤¤·Á¼°¤Î¾®¤µ¤¤¥¢¥¤¥³¥ó¤ò¼èÆÀ¤Ç¤­¤ë¤è¤¦¤Ë¤¹¤ë¤Ë¤Ï¡¢
//    ¤³¤Î´Ø¿ô¤ò¸Æ¤Ó½Ð¤·¤Æ¤¯¤À¤µ¤¤¡£
//
ATOM Window::MyRegisterClass(HINSTANCE hInstance, const tstring &windowClass)
{
    hInst = hInstance;
    this->windowClass = windowClass;

    wndProc.init(this, &Window::WndProc);

    WNDCLASSEX wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = (WNDPROC)wndProc.getCode();
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32THUNK));
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCE(IDC_WIN32THUNK);
    wcex.lpszClassName  = windowClass.c_str();
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassEx(&wcex);
}

//
//   ´Ø¿ô: Window::InitInstance(HINSTANCE, int)
//
//   ÌÜŪ: ¥¤¥ó¥¹¥¿¥ó¥¹ ¥Ï¥ó¥É¥ë¤òÊݸ¤·¤Æ¡¢¥á¥¤¥ó ¥¦¥£¥ó¥É¥¦¤òºîÀ®¤·¤Þ¤¹¡£
//
//   ¥³¥á¥ó¥È:
//
//        ¤³¤Î´Ø¿ô¤Ç¡¢¥°¥í¡¼¥Ð¥ëÊÑ¿ô¤Ç¥¤¥ó¥¹¥¿¥ó¥¹ ¥Ï¥ó¥É¥ë¤òÊݸ¤·¡¢
//        ¥á¥¤¥ó ¥×¥í¥°¥é¥à ¥¦¥£¥ó¥É¥¦¤òºîÀ®¤ª¤è¤Óɽ¼¨¤·¤Þ¤¹¡£
//
BOOL Window::InitInstance(const tstring &title, int nCmdShow)
{
    hWnd = CreateWindow(windowClass.c_str(), title.c_str(), WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInst, NULL);

    if (!hWnd)
    {
        return FALSE;
    }

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    return TRUE;
}

//
//  ´Ø¿ô: Window::WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  ÌÜŪ:  ¥á¥¤¥ó ¥¦¥£¥ó¥É¥¦¤Î¥á¥Ã¥»¡¼¥¸¤ò½èÍý¤·¤Þ¤¹¡£
//
//  WM_COMMAND  - ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó ¥á¥Ë¥å¡¼¤Î½èÍý
//  WM_PAINT    - ¥á¥¤¥ó ¥¦¥£¥ó¥É¥¦¤ÎÉÁ²è
//  WM_DESTROY  - Ãæ»ß¥á¥Ã¥»¡¼¥¸¤òɽ¼¨¤·¤ÆÌá¤ë
//
//
LRESULT Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;

    switch (message)
    {
    case WM_COMMAND:
        for each (auto f in Command)
            if (f(LOWORD(wParam), HIWORD(wParam)))
                return 0;
        return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        // TODO: ÉÁ²è¥³¡¼¥É¤ò¤³¤³¤ËÄɲ䷤Ƥ¯¤À¤µ¤¤...
        for each (auto f in Paint) f(hdc);
        EndPaint(hWnd, &ps);
        break;
    case WM_LBUTTONDOWN: OnMouseDown(1, wParam, lParam); break;
    case WM_RBUTTONDOWN: OnMouseDown(2, wParam, lParam); break;
    case WM_MBUTTONDOWN: OnMouseDown(3, wParam, lParam); break;
    case WM_XBUTTONDOWN: OnMouseDown(3 + HIWORD(wParam), LOWORD(wParam), lParam); break;
    case WM_LBUTTONUP: OnMouseUp(1, wParam, lParam); break;
    case WM_RBUTTONUP: OnMouseUp(2, wParam, lParam); break;
    case WM_MBUTTONUP: OnMouseUp(3, wParam, lParam); break;
    case WM_XBUTTONUP: OnMouseUp(3 + HIWORD(wParam), LOWORD(wParam), lParam); break;
    case WM_MOUSEMOVE:
        for each (auto f in MouseMove)
            f(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), wParam);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

win32thunk.cpp (¥×¥í¥¸¥§¥¯¥È̾¤Ë¤è¤ê°Û¤Ê¤ë)

// win32thunk.cpp : ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¤Î¥¨¥ó¥È¥ê ¥Ý¥¤¥ó¥È¤òÄêµÁ¤·¤Þ¤¹¡£
//

#include "stdafx.h"
#include "win32thunk.h"

static tstring LoadTString(HINSTANCE hInstance, UINT uID) {
    const int buflen = 256;
    TCHAR buf[buflen];
    LoadString(hInstance, uID, buf, buflen);
    return buf;
}

// ¤³¤Î¥³¡¼¥É ¥â¥¸¥å¡¼¥ë¤Ë´Þ¤Þ¤ì¤ë´Ø¿ô¤ÎÀë¸À¤òžÁ÷¤·¤Þ¤¹:
INT_PTR CALLBACK        About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY _tWinMain(HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPTSTR    lpCmdLine,
    int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: ¤³¤³¤Ë¥³¡¼¥É¤òÁÞÆþ¤·¤Æ¤¯¤À¤µ¤¤¡£
    MSG msg;
    HACCEL hAccelTable;

    Window win;
    win.MyRegisterClass(hInstance, LoadTString(hInstance, IDC_WIN32THUNK));
    win.Command.push_back([&](int id, int e)->bool {
        // ÁªÂò¤µ¤ì¤¿¥á¥Ë¥å¡¼¤Î²òÀÏ:
        switch (id)
        {
        case IDM_ABOUT:
            DialogBox(hInstance, MAKEINTRESOURCE(IDD_ABOUTBOX), win.hWnd, About);
            return true;
        case IDM_EXIT:
            DestroyWindow(win.hWnd);
            return true;
        }
        return false;
    });
    win.Paint.push_back([&](HDC hdc) {
        auto oldPen = (HPEN)SelectObject(hdc, GetStockObject(BLACK_PEN));
        auto oldBrush = (HBRUSH)SelectObject(hdc, GetStockObject(GRAY_BRUSH));
        Rectangle(hdc, 10, 10, 40, 40);
        SelectObject(hdc, oldPen);
        SelectObject(hdc, oldBrush);
    });

    // ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¤Î½é´ü²½¤ò¼Â¹Ô¤·¤Þ¤¹:
    if (!win.InitInstance(LoadTString(hInstance, IDS_APP_TITLE), nCmdShow))
    {
        return FALSE;
    }

    hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32THUNK));

    // ¥á¥¤¥ó ¥á¥Ã¥»¡¼¥¸ ¥ë¡¼¥×:
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}

// ¥Ð¡¼¥¸¥ç¥ó¾ðÊó¥Ü¥Ã¥¯¥¹¤Î¥á¥Ã¥»¡¼¥¸ ¥Ï¥ó¥É¥é¡¼¤Ç¤¹¡£
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}

¿§¡¹¤ÈÆͤùþ¤ß¤É¤³¤í¤Ï¤¢¤ë¤È»×¤¤¤Þ¤¹¤¬¡¢
º£²ó¤Ï¥¯¥é¥¹¥é¥¤¥Ö¥é¥ê¤òºî¤ë¤Î¤¬ÌÜŪ¤Ç¤Ï¤Ê¤¤¤Î¤Ç¡¢
ŬÅö¤Ë¸«Ä̤·¤òÎɤ¯¤¹¤ëÄøÅÙ¤Ëα¤á¤Æ¤¤¤Þ¤¹¡£

ÌäÂê


[Ìä] ÉÁ²è¤µ¤ì¤Æ¤¤¤ë»Í³Ñ¤ò¥É¥é¥Ã¥°¤ÇÆ°¤«¤»¤ë¤è¤¦¤Ë¤·¤Æ¤¯¤À¤µ¤¤¡£

¥Ò¥ó¥È
  • ºÆÉÁ²èÍ×µá: InvalidateRect(hWnd, nullptr, true);
²óÅúÎã

https://gist.github.com/1226666

    POINT pb = { 10, 10 };
    win.Paint.push_back([&](HDC hdc) {
        auto oldPen = (HPEN)SelectObject(hdc, GetStockObject(BLACK_PEN));
        auto oldBrush = (HBRUSH)SelectObject(hdc, GetStockObject(GRAY_BRUSH));
        Rectangle(hdc, pb.x, pb.y, pb.x + 40, pb.y + 40);
        SelectObject(hdc, oldPen);
        SelectObject(hdc, oldBrush);
    });

    bool sel = false;
    POINT pd, pb2;
    win.MouseDown.push_back([&](int btn, int x, int y, WPARAM) {
        if (pb.x <= x && x <= pb.x + 40 && pb.y <= y && y <= pb.y + 40) {
            pd.x = x;
            pd.y = y;
            pb2 = pb;
            sel = true;
        }
    });
    win.MouseMove.push_back([&](int x, int y, WPARAM) {
        if (sel) {
            pb.x = pb2.x + (x - pd.x);
            pb.y = pb2.y + (y - pd.y);
            InvalidateRect(win.hWnd, nullptr, true);
        }
    });
    win.MouseUp.push_back([&](int, int, int, WPARAM) { sel = false; });

·Ñ³


¼¡¤Î¤è¤¦¤Ê´Ø¿ô¤¬¤¢¤Ã¤¿¤È¤¹¤ë¡£

int test() {
    return 1;
    return 2;
    return 3;
}

Ä̾ºÇ½é¤Îreturn°Ê¹ß¤ÏÅþã¤Ç¤­¤Ê¤¤¥³¡¼¥É¤È¤·¤Æ°·¤ï¤ì¤ë¡£
¤³¤ì¤¬¤â¤·¡¢¸Æ¤Ð¤ì¤ëÅ٤˼¡¤Ë¿Ê¤à¤È¤·¤¿¤é¤É¤¦¤À¤í¤¦¤«¡£

printf("%d\n", test()); // 1
printf("%d\n", test()); // 2
printf("%d\n", test()); // 3

¤³¤Î¤è¤¦¤Ê¥â¥Ç¥ë¤ò¡Ö·Ñ³¡×¤È¸Æ¤Ó¡¢
·Ñ³¤ò´Þ¤à´Ø¿ô¤ò¥³¥ë¡¼¥Á¥ó¤È¸Æ¤Ö¡£

ñ½ã¤Ë¼ÂÁõ¤·¤¿¤À¤±¤À¤È¡¢°ìÅÙ¤·¤«¸Æ¤Ù¤Ê¤¯¤Ê¤Ã¤Æ¤·¤Þ¤¦¡£
¢¨¾å¤ÎÎã¤Ç¤ÏÆóÅÙ¤È1¤¬ÊÖ¤»¤Ê¤¯¤Ê¤ë¡£

¤½¤Î¤¿¤á´Ø¿ô¤ËÂФ¹¤ë¥¤¥ó¥¹¥¿¥ó¥¹¤È¤¤¤¦¹Í¤¨Êý¤òƳÆþ¤¹¤ë¡£
°Ê²¼¤Ïµ¼»÷¥³¡¼¥É¡£

auto t1 = new test;
printf("%d\n", t1()); // 1
printf("%d\n", t1()); // 2
auto t2 = new test;
printf("%d\n", t2()); // 1

C#¤Ç¤Ïyield¤È¤·¤Æ·Ñ³¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤ë¡£
yield¤ò´Þ¤à¥á¥½¥Ã¥É¤Ï¥¤¥ó¥¹¥¿¥ó¥¹¤òÊÖ¤¹¡£

using System;
using System.Collections.Generic;

class Test
{
    static IEnumerable<int> test()
    {
        yield return 1;
        yield return 2;
        yield return 3;
    }

    static void Main()
    {
        var t1 = test().GetEnumerator();
        if (t1.MoveNext()) Console.WriteLine(t1.Current);
        if (t1.MoveNext()) Console.WriteLine(t1.Current);
        var t2 = test().GetEnumerator();
        if (t2.MoveNext()) Console.WriteLine(t2.Current);
    }
}

Python¤Ç¤Ï¥¸¥§¥Í¥ì¡¼¥¿¤È¸Æ¤Ð¤ì¤Æ¤¤¤ë¡£

def test():
    yield 1
    yield 2
    yield 3

t1 = test()
print t1.next()
print t1.next()
t2 = test()
print t2.next()

C#/Python¤È¤â¤Ë¼Â¹Ô·ë²Ì¤Ï°Ê²¼¤ÎÄ̤ꡣ


·Ñ³¤ò¤É¤¦¼ÂÁõ¤¹¤ë¤«¤ò¸«¤Æ¤¤¤¯¡£

setjmp/longjmp


setjmp/longjmp¤Ç¥¹¥¿¥Ã¥¯¤ò´¬¤­Ì᤹Îã¡£

#include <stdio.h>
#include <setjmp.h>

jmp_buf jb;

int main() {
    if (setjmp(jb) == 0) {
        printf("setjmp\n");
        printf("test\n");
        longjmp(jb, 1);
        printf("never reach here\n");
    }
    printf("longjmp done.\n");
}
  • °ì¸«²áµî¤ËÌá¤Ã¤¿¤è¤¦¤Ë¸«¤¨¤ë¡£
  • ¥ì¥¸¥¹¥¿¤òÌᤷ¤Æ³¹Ô¤¹¤ë¤À¤±¤Ç¡¢¾õÂÖ¤¬Êݸ¤µ¤ì¤Æ¤¤¤ë¤ï¤±¤Ç¤Ï¤Ê¤¤¡£

¼¡¤ÎÎã¤Ç¤Ï¤¿¤Þ¤¿¤Þ°ú¿ô¤Î¥¢¥É¥ì¥¹¤¬°ìÃפ·¤¿¤¿¤á¤¹¤êÂؤï¤ë¡£

#include <stdio.h>
#include <setjmp.h>

jmp_buf jb;

void test1(const char *s) {
    setjmp(jb);
    printf("&s: %p, s: %p; %s\n", &s, s, s);
}

void test2(int a) {
    printf("&a: %p, a: %d\n", &a, a);
    longjmp(jb, 0);
}

int main() {
    test1("test");
    test2(0);
    printf("end\n");
}

&s: 0013FE98, s: 00415758; test
&a: 0013FE98, a: 0
&s: 0013FE98, s: 00000000; (null)
end
  • a¤ÎÃͤ¬¤½¤Î¤Þ¤Þs°·¤¤¤µ¤ì¤Æ³¹Ô¡£
  • main()¤ÎÃæ¤Îή¤ì¤Ë¤Ï±Æ¶Á¤·¤Ê¤¤¡£
    • ²áµî¤ËÌá¤Ã¤¿¤ï¤±¤Ç¤Ï¤Ê¤¤¤Î¤¬¤ï¤«¤ë¤È»×¤¦¡£
  • ͽ´ü¤·¤Ê¤¤Æ°ºî¤ò°ú¤­µ¯¤³¤¹²ÄǽÀ­¤¬¤¢¤ë¤¿¤á´í¸±¡£
    • ²¼°Ì¹½Â¤¤«¤é¾å°Ì¤ËÌá¤ë¤è¤¦¤Ê»È¤¤Êý¤¬¿ä¾©¤µ¤ì¤ë¡£

RAII

RAII¤Ï½èÍý·Ï°Í¸

#include <stdio.h>
#include <setjmp.h>

jmp_buf jb;

class Test {
    const char *s;
public:
    Test(const char *s) : s(s) {}
    ~Test() { printf("%s\n", s); }
};

void test() {
    Test t1("t1");
    longjmp(jb, 1);
}

int main() {
    Test t2("t2");
    if (setjmp(jb) == 0) {
        Test t3("t3");
        test();
    }
}

[VC++]
t1
t3
t2

[g++]
t2

¤³¤Î°ã¤¤¤Ï·Ñ³¤ò°·¤¦¾å¤ÇÌñ²ð¡£

¥³¥ë¡¼¥Á¥ó
  • ½èÍý¤òÅÓÃæ¤ÇÈ´¤±¤ÆǤ°Õ¤ËºÆ³«¤Ç¤­¤ë¹½Â¤¤ò¥³¥ë¡¼¥Á¥ó¤È¸Æ¤Ö¡£
  • setjmp/longjmp¤ò¸ò¸ß¤Ë¸Æ¤Ù¤Ð¥³¥ë¡¼¥Á¥ó¤¬¼ÂÁõ¤Ç¤­¤ë¡£

#include <stdio.h>
#include <setjmp.h>

jmp_buf jb1, jb2;
int i;

void test() {
    for (i = 1; i <= 10; i++)
        if (setjmp(jb2) == 0)
            longjmp(jb1, i);
    longjmp(jb1, -1);
}

int main() {
    int value = setjmp(jb1);
    if (value == 0)
        test();
    else if (value > 0) {
        printf("%d\n", value);
        longjmp(jb2, 1);
    }
}
  • Windows¤Ç¤Ï¥Õ¥¡¥¤¥Ð¡¼¤È¤·¤ÆOS¤Ç¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤ë¡£
  • ¥¹¥¿¥Ã¥¯¤¬Ê̤˳ÎÊݤµ¤ì¤ë¤¿¤á¥í¡¼¥«¥ëÊÑ¿ô¤äRAII¤ÎÌäÂê¤â¤Ê¤¤¡£
  • OS¤Îµ¡Ç½¤ò»È¤¦¤È¸¶Íý¤ÎÀâÌÀ¤Ë¤Ê¤é¤Ê¤¤¤Î¤Çº£²ó¤Ï»ÈÍѤ·¤Ê¤¤¡£
  • °ìöȴ¤±¤¿½èÍý¤ËÌá¤ë¤³¤È¤ò¡Ö·Ñ³¡×¤È¸Æ¤Ö¡£
    • test()Æâ¤Çsetjmp(jb2)¤È¤·¤ÆÊݸ¤·¤¿¥³¥ó¥Æ¥­¥¹¥È¤ËÌá¤Ã¤Æ¤¤¤ë¡£
*** ¥í¡¼¥«¥ëÊÑ¿ô
  • ·Ñ³¤·¤¿ºÝ¤Ë¥í¡¼¥«¥ëÊÑ¿ô¤ÏÉüµ¢¤·¤Ê¤¤¡£
  • i¤ò¥í¡¼¥«¥ëÊÑ¿ô¤Ë¤¹¤ë¤È¸íÆ°ºî¤¹¤ë¡£

 #include <setjmp.h>

 jmp_buf jb1, jb2;
-int i;

 void test() {
+    int i;
     for (i = 1; i <= 10; i++)
         if (setjmp(jb2) == 0)
             longjmp(jb1, i);
  • ¥í¡¼¥«¥ëÊÑ¿ô¤Ç¤¹¤é¼º¤ï¤ì¤ë¤¿¤á¡¢RAII¤ÏÏÀ³°¡£
  • ´Ø¿ô¤«¤é¤ÎÌá¤êÀè¤âÊݸ¤µ¤ì¤Ê¤¤¤¿¤á¡¢test()¤ÎºÇ¸å¤Ïlongjmp()¤ÇÈ´¤±¤ë¡£
*** C#

C#¤ÇƱ¤¸¤â¤Î¤ò½ñ¤¤¤ÆÈæ³Ó¡£

class Program
{
    static IEnumerable<int> test()
    {
        for (int i = 1; i <= 10; i++)
            yield return i;
    }

    static void Main(string[] args)
    {
        foreach (var i in test())
            Console.WriteLine(i);
    }
}

¼«Á°¼ÂÁõ

¾¯¤·¤º¤Ä³ÈÄ¥¤·¤Æ¤¤¤¯¤¿¤á¤Ë¡¢¤Þ¤º¤Ï¼«Á°¼ÂÁõ¤·¤Æ¤ß¤ë¡£

https://gist.github.com/1257249

#include <stdio.h>

typedef struct {
    unsigned long eip, esp, ebp, ebx, edi, esi;
} myjmp_buf;

_declspec(naked) int mysetjmp(myjmp_buf *jbuf) {
    _asm {
        mov edx, [esp+4]
        mov eax, [esp]
        mov [edx   ], eax
        mov [edx+ 4], esp
        mov [edx+ 8], ebp
        mov [edx+12], ebx
        mov [edx+16], edi
        mov [edx+20], esi
        xor eax, eax
        ret
    }
}

_declspec(naked) void mylongjmp(myjmp_buf *jbuf, int value) {
    _asm {
        mov eax, [esp+ 8]
        mov edx, [esp+ 4]
        mov ecx, [edx   ]
        mov esp, [edx+ 4]
        mov ebp, [edx+ 8]
        mov ebx, [edx+12]
        mov edi, [edx+16]
        mov esi, [edx+20]
        mov [esp], ecx
        ret
    }
}

myjmp_buf jb;

int main() {
    if (mysetjmp(&jb) == 0) {
        printf("setjmp\n");
        printf("test\n");
        mylongjmp(&jb, 1);
        printf("never reach here\n");
    }
    printf("longjmp done.\n");
}

¥ì¥¸¥¹¥¿¤ò¹½Â¤ÂΤËÊݸ¤·¤Æ¤¤¤ë¤À¤±¡£

RAII¤Ï̵»ë¤·¤Æ¤¤¤ë¤Î¤Çg++¤ÈƱ¤¸·ë²Ì¤È¤Ê¤ë¡£

¥Á¥å¡¼¥Ë¥ó¥°
  • setjmp/longjmp¤Ç¤Î¥¹¥¿¥Ã¥¯¤Î¾ÃÈñ¤ò¸º¤é¤¹¤¿¤áfastcall²½¡£
  • ¥á¥â¥ê¥¢¥¯¥»¥¹¤ò¸º¤é¤¹¤¿¤áret¤òjmp¤Ë½ñ¤­´¹¤¨¡£
  • ¤¤¤­¤Ê¤êpop¤ÇÌá¤êÀè¤ò¼èÆÀ¤·¤Æ¤«¤éesp¤òÊݸ¤·¤Æ¤ª¤¯¡£

typedef struct {
    unsigned long eip, esp, ebp, ebx, edi, esi;
} myjmp_buf;

_declspec(naked) int _fastcall mysetjmp(myjmp_buf *jbuf) {
    _asm {
        pop edx
        mov [ecx   ], edx
        mov [ecx+ 4], esp
        mov [ecx+ 8], ebp
        mov [ecx+12], ebx
        mov [ecx+16], edi
        mov [ecx+20], esi
        xor eax, eax
        jmp edx
    }
}

_declspec(naked) void _fastcall mylongjmp(myjmp_buf *jbuf, int value) {
    _asm {
        mov eax, edx
        mov esp, [ecx+ 4]
        mov ebp, [ecx+ 8]
        mov ebx, [ecx+12]
        mov edi, [ecx+16]
        mov esi, [ecx+20]
        jmp dword ptr [ecx]
    }
}

¥¹¥¿¥Ã¥¯Ç˲õ

ñ½ã¤Ësetjmp/longjmp¤ÇÃæÃǤ·¤¿½èÍý¤òºÆ³«¤¹¤ë¤È
¥¹¥¿¥Ã¥¯¤¬Ç˲õ¤µ¤ì¤ë¤¿¤á¥í¡¼¥«¥ëÊÑ¿ô¤äÌá¤êÀ褬ÉÔÄê¡£

#include <stdio.h>

myjmp_buf jb1, jb2;
int i, *p;

void test() {
    for (i = 1; i <= 10; i++)
        if (mysetjmp(&jb2) == 0) {
            for (p = (int *)jb2.esp; p < (int *)jb1.esp; p++)
                printf("%p: %p\n", p, *p);
            mylongjmp(&jb1, i);
        }
    mylongjmp(&jb1, -1);
}

int main() {
    int value = mysetjmp(&jb1);
    if (value == 0)
        test();
    else if (value > 0) {
        printf("%d\n", value);
        mylongjmp(&jb2, 1);
    }
}

¥¹¥¿¥Ã¥¯¤Î¾ÃÈñ¤òÍÞ¤¨¤ë¤¿¤áRelease¥Ó¥ë¥É¤Ç³Îǧ¡£


¥¹¥¿¥Ã¥¯¤¬Ç˲õ¤µ¤ì¤Æ¤¤¤ë¡£

¥¹¥¿¥Ã¥¯ÂàÈò¡¦Éü¸µ

Éü¸µÍѥХåե¡¤òÄɲá£

typedef struct {
    unsigned long eip, esp, ebp, ebx, edi, esi;
    void *stack;
    int length;
} myjmp_buf;

_declspec(naked) int _fastcall mysetjmp(myjmp_buf *jbuf) {
    _asm {
        pop edx
        mov [ecx   ], edx
        mov [ecx+ 4], esp
        mov [ecx+ 8], ebp
        mov [ecx+12], ebx
        mov [ecx+16], edi
        mov [ecx+20], esi
        xor eax, eax
        mov [ecx+24], eax
        mov [ecx+28], eax
        jmp edx
    }
}

_declspec(naked) void _fastcall mylongjmp(myjmp_buf *jbuf, int value) {
    _asm {
        mov eax, edx
        mov edx, ecx
        mov esp, [edx+ 4]
        mov edi, esp
        mov esi, [edx+24]
        mov ecx, [edx+28]
        cld
        rep movsb
        mov ebp, [edx+ 8]
        mov ebx, [edx+12]
        mov edi, [edx+16]
        mov esi, [edx+20]
        jmp dword ptr [edx]
    }
}

¥¹¥¿¥Ã¥¯ÂàÈòÍÑ´Ø¿ô¡£

#include <string.h>
#include <vector>

void save_stack(std::vector<char> *dest, unsigned long last, myjmp_buf *callee) {
    callee->length = last - callee->esp;
    dest->resize(callee->length);
    callee->stack = &(*dest)[0];
    memcpy(callee->stack, (void *)callee->esp, callee->length);
}

¥µ¥ó¥×¥ë¤ò²þ¤¡£

#include <stdio.h>

myjmp_buf jb1, jb2;
std::vector<char> stack;
int i, *p;

void test() {
    for (i = 1; i <= 10; i++)
        if (mysetjmp(&jb2) == 0) {
            save_stack(&stack, jb1.esp, &jb2);
            for (p = (int *)jb2.esp; p < (int *)jb1.esp; p++)
                printf("%p: %p\n", p, *p);
            mylongjmp(&jb1, i);
        }
    mylongjmp(&jb1, -1);
}

int main() {
    int value = mysetjmp(&jb1);
    if (value == 0)
        test();
    else if (value > 0) {
        printf("%d\n", value);
        mylongjmp(&jb2, 1);
    }
}

¥¹¥¿¥Ã¥¯¤¬Àµ¾ï¤ËÊݸ¤µ¤ì¤Æ¤¤¤ë¤³¤È¤ò³Îǧ¡£


¥í¡¼¥«¥ëÊÑ¿ô¤ò»È¤Ã¤Æ¤âÂç¾æÉס£

 myjmp_buf jb1, jb2;
 std::vector<char> stack;
-int i, *p;
+int *p;
 
 void test() {
-    for (i = 1; i <= 10; i++)
+    for (int i = 1; i <= 10; i++)
         if (mysetjmp(&jb2) == 0) {
             save_stack(&stack, jb1.esp, &jb2);
             for (p = (int *)jb2.esp; p < (int *)jb1.esp; p++)

¼Â¹Ô·ë²Ì


Ìá¤êÀ褬ÊÝ»ý¤µ¤ì¤ë¤è¤¦¤Ë¤Ê¤Ã¤¿¤¿¤á¡¢½ªÎ»ÄÌÃΤÏÉÔÍס£
¸Æ¤Ó½Ð¤·¸µ¤Ç¤­¤Á¤ó¤È·Ñ³¤µ¤ì¤ë¡£

https://gist.github.com/1259601

#include <stdio.h>

myjmp_buf jb1, jb2;
std::vector<char> stack;

void test() {
    for (int i = 1; i <= 10; i++)
        if (mysetjmp(&jb2) == 0) {
            save_stack(&stack, jb1.esp, &jb2);
            mylongjmp(&jb1, i);
        }
}

int main() {
    int value = mysetjmp(&jb1);
    if (value == 0) {
        test();
        printf("end\n");
    } else if (value > 0) {
        printf("%d\n", value);
        mylongjmp(&jb2, 1);
    }
}

¼Â¹Ô·ë²Ì


¥µ¥Ý¡¼¥È¥¯¥é¥¹


¥Ð¥Ã¥Õ¥¡¤òÁê¸ß¤Ë¸Æ¤Ó¹ç¤¦¤Î¤Ïʬ¤«¤ê¤Ë¤¯¤¤¤Î¤Ç´Êά²½¤ò»î¤ß¤ë¡£

https://gist.github.com/1271852

#include <functional>
#include <vector>

template <class T> class Coroutine {
    myjmp_buf caller, callee;
    std::vector<char> stack;
    std::function<void()> f;
    int status;

public:
    T value;
    Coroutine() : status(0) {}
    Coroutine(const decltype(f) &f) : f(f), status(0) {}
    void operator=(const decltype(f) &f) { this->f = f; }

    bool operator()() {
        if (mysetjmp(&caller)) return true;
        switch (status) {
        case 0:
            status = 1;
            f();
            status = 3;
            break;
        case 2:
            mylongjmp(&callee, 1);
        }
        return false;
    }

    T yield(T value) {
        this->value = value;
        if (mysetjmp(&callee) == 0) {
            status = 2;
            save_stack(&stack, caller.esp, &callee);
            mylongjmp(&caller, 1);
        }
        return this->value;
    }
};

¤³¤ì¤ò»È¤Ã¤ÆÎã¤ò½ñ¤­Ä¾¤¹¤È°Ê²¼¤ÎÄ̤ꡣ

#include <stdio.h>

Coroutine<int> cr;

void test() {
    for (int i = 0; i <= 5; i++)
        cr.yield(i);
}

int main() {
    cr = test;
    while (cr())
        printf("%d\n", cr.value);
    printf("end\n");
}

°ÊÁ°¤Ïlongjmp¤ÇÃͤòÅϤ·¤Æ¤¤¤¿¤¿¤á0¤¬ÆÃÊÌ°·¤¤¤µ¤ì¤Æ¤¤¤¿¤¬¡¢
ÃͤȾõÂÖ¤òʬΥ¤·¤¿¤¿¤¿¤á0¤âÌäÂê¤Ê¤¯ÅϤ»¤ë¤è¤¦¤Ë¤Ê¤Ã¤¿¡£

yield

Àè¤Û¤É¤Î¼ÂÁõ¤Ï»öÁ°¤ËCoroutine¤Î¥¤¥ó¥¹¥¿¥ó¥¹¤òÄêµÁ¤·¤Æ¡¢
yield¤¬¤½¤Î¥¤¥ó¥¹¥¿¥ó¥¹¤ËÇû¤é¤ì¤Æ¤¤¤ë¡£
¤³¤ì¤Ç¤Ï³Ê¹¥°­¤¤¤Î¤Çyield()¤òʸ̮°Í¸¤ÇÆÈΩ¤µ¤»¤Æ¤ß¤ë¡£

https://gist.github.com/1271857

#include <functional>
#include <vector>
#include <stack>

class CoroutineBase {
public:
    virtual ~CoroutineBase() {}
};

static std::stack<CoroutineBase *> coroutines;

template <class T> class Coroutine : public CoroutineBase {
    myjmp_buf caller, callee;
    std::vector<char> stack;
    std::function<void()> f;
    int status;

public:
    T value;
    Coroutine() : status(0) {}
    Coroutine(const decltype(f) &f) : f(f), status(0) {}
    void operator=(const decltype(f) &f) { this->f = f; }

    bool operator()() {
        if (mysetjmp(&caller)) return true;
        switch (status) {
        case 0:
            status = 1;
            coroutines.push(this);
            f();
            coroutines.pop();
            status = 3;
            break;
        case 2:
            coroutines.push(this);
            mylongjmp(&callee, 1);
        }
        return false;
    }

    T yield(T value) {
        if (coroutines.top() == this) {
            coroutines.pop();
            status = 2;
            this->value = value;
            if (mysetjmp(&callee) == 0) {
                save_stack(&stack, caller.esp, &callee);
                mylongjmp(&caller, 1);
            }
        }
        return this->value;
    }
};

template <class T> T yield(T value) {
    auto cr = dynamic_cast<Coroutine<T> *>(coroutines.top());
    return cr ? cr->yield(value) : T();
}

¤³¤ì¤ò»È¤¨¤ÐÈó¾ï¤Ë¤¹¤Ã¤­¤ê½ñ¤±¤ë¡£

#include <stdio.h>

void test() {
    for (int i = 0; i <= 5; i++)
        yield(i);
}

int main() {
    Coroutine<int> cr = test;
    while (cr())
        printf("%d\n", cr.value);
    printf("end\n");
}

RAII

RAII¤â»È¤¨¤ë¡£

https://gist.github.com/1258016

#include <stdio.h>

class Test {
    const char *s;
public:
    Test(const char *s) : s(s) {}
    ~Test() { printf("%s\n", s); }
};

void test() {
    Test t("test()");
    for (int i = 0; i <= 5; i++)
        yield(i);
}

int main() {
    Test t("main()");
    Coroutine<int> cr = test;
    while (cr())
        printf("%d\n", cr.value);
    printf("end\n");
}

¼Â¹Ô·ë²Ì


ÌäÂêÅÀ

°ã¤¦³¬Áؤ«¤é¸Æ¤Ö¤Èͽ´ü¤·¤Ê¤¤·ë²Ì¤È¤Ê¤ë¡£
Debug¤Ç¤ÏɽÌ̲½¤·¤Ê¤¤¤Î¤ÇRelease¤Ç¥Ó¥ë¥É¡£

https://gist.github.com/1273598

#include <stdio.h>

void test() {
    for (int i = 0; i <= 5; i++)
        yield(i);
    printf("test: done\n");
}

Coroutine<int> cr = test;

void test2() {
    if (cr()) printf("test2: %d\n", cr.value);
}

int main() {
    if (cr()) printf("main: %d\n", cr.value);
    test2();
    if (cr()) printf("main: %d\n", cr.value);
}

¸Æ¤Ó½Ð¤·¸µ¤Î¥¹¥¿¥Ã¥¯¤Ë°Í¸¤¹¤ë¤¿¤á¡¢
test2()¤«¤é¸Æ¤Ð¤ì¤¿¥³¥ë¡¼¥Á¥ó¤ÏÀµ¾ï¤ËÆ°ºî¤·¤Ê¤¤¡£
  • ¿Þ¼¨

¤Á¤Ê¤ß¤Ëf¤ò´Ø¿ô¥Ý¥¤¥ó¥¿¤ËÊѹ¹¤¹¤ë¤ÈDebug¥Ó¥ë¥É¤Ç¤âÍî¤Á¤ë¡£
¤¿¤À¤·Íî¤Á¤ë¥¿¥¤¥ß¥ó¥°¤Ï¿¾¯°Û¤Ê¤ë¡£

 template <class T> class Coroutine : public CoroutineBase {
     myjmp_buf caller, callee;
     std::vector<char> stack;
-    std::function<void()> f;
+    void (*f)();
     int status;
 
 public:

¥¹¥¿¥Ã¥¯¤Î´ÉÍý


¥³¥ë¡¼¥Á¥ó¤¬»ÈÍѤ¹¤ë¥¹¥¿¥Ã¥¯¤ò¤½¤Î¤Þ¤ÞÀѤà¤Î¤Ç¤Ï¤Ê¤¯¡¢
ÆÃÄê¤ÎÎΰè¤Ë¼è¤Ã¤Æ´ÉÍý¤¹¤ë¤³¤È¤ÇÌäÂê¤ò²ò·è¤¹¤ë¡£
  • Ä̾¥¹¥¿¥Ã¥¯¤Ï1ËÜ
  • ¥Õ¥¡¥¤¥Ð¡¼¤ä¥¹¥ì¥Ã¥É¤Ç¥¹¥¿¥Ã¥¯¤ò¿·ÀߤǤ­¤ë
    • ¼«Á°¼ÂÁõ¤Ç¸¶Íý¤òõ¤ë¤Î¤¬ÌÜŪ¤Î¤¿¤áº£²ó¤Ï»ÈÍѤ·¤Ê¤¤

¥¹¥¿¥Ã¥¯¤Î¾å¸Â

̵¸ÂºÆµ¢¤Ç¥¹¥¿¥Ã¥¯¤Î¸Â³¦¤òõ¤ë¡£

#include <stdio.h>

void test() {
    int a;
    printf("\r&a: %p ", &a);
    fflush(stdout);
    test();
}

int main() {
    int a;
    printf("&a: %p\n", &a);
    test();
    return 0;
}

¼Â¹Ô·ë²Ì¤Ï°Ê²¼¤ÎÄ̤ꡣ
¢¨´Ä¶­¤Ë¤è¤Ã¤ÆÃͤϰۤʤë¤È»×¤ï¤ì¤ë¡£

  • 0x13ff78 - 0x44d4c = 0xfb22c ­ð 1004.5KB

¥¹¥¿¥Ã¥¯¤Î¸Â³¦¤¬Ìó1MB¤À¤È¤¤¤¦¤³¤È¤¬Ê¬¤«¤ë¡£
¤³¤ÎÃͤÏPE¥Ø¥Ã¥À¤Ë½ñ¤¤¤Æ¤¢¤ë¡£
  • IMAGE_OPTIONAL_HEADER32::SizeOfStackReserve

VC++2010¤Î¥Ç¥Õ¥©¥ë¥ÈÃͤÏ0x100000(1MB)¡£

ÉÔ´°Á´¤Ê½¤Àµ

¥¹¥¿¥Ã¥¯¤ò¤¢¤ëÄøÅÙ¶õ¤±¤Æ¥³¥ë¡¼¥Á¥ó¤ò¼Â¹Ô¤¹¤ë¡£
¶õ¤±¤¿¥¹¥¿¥Ã¥¯¤ÎÀèƬ¤ò¥á¥ó¥Ð¤Ë»Ä¤·¤Æ¤ª¤¯¡£

     std::vector<char> stack;
     std::function<void()> f;
     int status;
+    unsigned long last;
 
 public:
     T value;
     Coroutine() : status(0) {}
     Coroutine(const decltype(f) &f) : f(f), status(0) {}
     void operator=(const decltype(f) &f) { this->f = f; }
 
     bool operator()() {
+        if (status == 0) _alloca(32 * 1024);
         if (mysetjmp(&caller)) return true;
         switch (status) {
         case 0:
+            last = caller.esp;
             status = 1;
             coroutines.push(this);
             f();

¥í¡¼¥«¥ë¤ËµðÂç¤ÊÇÛÎó¤ò³ÎÊݤ·¤Ê¤¤¸Â¤ê¡¢
32KB¤â¥¹¥¿¥Ã¥¯¤ò¾ÃÈñ¤¹¤ë¤³¤È¤Ï¾¯¤Ê¤¤¤È»×¤¦¡£

Ç°¤Î¤¿¤á·Ñ³»þ¤Ë¥¹¥¿¥Ã¥¯¤òÆͤ­ÇˤäƤ¤¤Ê¤¤¤«¥Á¥§¥Ã¥¯¤¹¤ë¡£

             status = 3;
             break;
         case 2:
+            if (caller.esp < callee.esp)
+                return false;
             coroutines.push(this);
             mylongjmp(&callee, 1);
         }

¶õ¤±¤¿¥¹¥¿¥Ã¥¯¤òÊݸ¤¹¤ë¤È̵Â̤ʤΤǡ¢
¥á¥ó¥Ð¤Ë»Ä¤·¤¿¥¹¥¿¥Ã¥¯¤Î¥¢¥É¥ì¥¹¤ò»È¤¦¡£

             status = 2;
             this->value = value;
             if (mysetjmp(&callee) == 0) {
-                save_stack(&stack, caller.esp, &callee);
+                save_stack(&stack, last, &callee);
                 mylongjmp(&caller, 1);
             }
         }

ÌäÂêÅÀ¤È¤·¤ÆÁ°·Ç¤·¤¿¥³¡¼¥É¤¬°ì¸«Àµ¾ï¤ËÆ°¤¯¡£


¥³¥ë¡¼¥Á¥óÆâ¤Î¥ë¡¼¥×¤Î¾å¸Â¤ò5¤«¤é0¤Ë¤¹¤ë¤È°Û¾ïÆ°ºî¤¹¤ë¡£

https://gist.github.com/1273606

 #include <stdio.h>
 
 void test() {
-    for (int i = 0; i <= 5; i++)
+    for (int i = 0; i <= 0; i++)
         yield(i);
     printf("test: done\n");
 }

¥³¥ë¡¼¥Á¥ó¤òÈ´¤±¤ë¤È¤­¤Ë¥¹¥¿¥Ã¥¯¤¬²õ¤ì¤ë¡£


½¤Àµ

¥³¥ë¡¼¥Á¥ó¤ò¸Æ¤ó¤Ç¤¤¤ëÉôʬ¤ò¸«¤ë¤È¡¢
½ªÎ»»þ¤Ï¤½¤Î¤Þ¤Þή¤ìÍî¤Á¤ë¤³¤È¤ò´üÂÔ¤·¤Æ¤¤¤ë¡£

case 0:
    status = 1;
    coroutines.push(this);
    f();
    coroutines.pop();
    status = 3;
    break;

Ê̤γ¬Áؤ«¤é¸Æ¤Ö¤ÈÉüµ¢»þ¤Îebp¤¬¿©¤¤°ã¤¦¤¿¤á¡¢
¥í¡¼¥«¥ëÊÑ¿ô¤¬Àµ¾ï¤Ë»²¾È¤Ç¤­¤º¤Ë¥¨¥é¡¼¤È¤Ê¤ë¡£
  • ¿Þ¼¨

¥³¥ë¡¼¥Á¥ó¤ò¥é¥Ã¥Ñ¡¼·Ðͳ¤Ç¸Æ¤ó¤Ç½ªÎ»ÄÌÃΤ¹¤ì¤Ð²ò·è¡£
  • ¿Þ¼¨

https://gist.github.com/1271829

     int status;
     unsigned long last;
 
+    void exec() {
+        f();
+        mylongjmp(&caller, 2);
+    }
+
 public:
     T value;
     Coroutine() : status(0) {}
     Coroutine(const decltype(f) &f) : f(f), status(0) {}
     void operator=(const decltype(f) &f) { this->f = f; }
 
     bool operator()() {
         if (status == 0) _alloca(32 * 1024);
-        if (mysetjmp(&caller)) return true;
+        switch (mysetjmp(&caller)) {
+        case 1:
+            return true;
+        case 2:
+            coroutines.pop();
+            status = 3;
+            return false;
+        }
         switch (status) {
         case 0:
             last = caller.esp;
             status = 1;
             coroutines.push(this);
-            f();
-            coroutines.pop();
-            status = 3;
-            break;
+            exec();
         case 2:
             if (caller.esp < callee.esp)
                 return false;

¥³¡¼¥É¤ÎÀ°Íý


º£¤Þ¤Ç½¤Àµ¤âƱ»þ¤Ë¹Ô¤¦¤¿¤á1¤Ä¤Î¥½¡¼¥¹¤ËÁ´Éô½ñ¤¤¤Æ¤¤¤¿¡£
½¤Àµ¤¬Íî¤ÁÃ夤¤¿¤Î¤Ç¥½¡¼¥¹¤òʬ³ä¤·¤ÆÀ°Íý¡£

https://gist.github.com/1274612

Coroutine.h

#pragma once

#include <vector>
#include <functional>
#include <stack>

typedef struct {
    unsigned long eip, esp, ebp, ebx, edi, esi;
    void *stack;
    int length;
} myjmp_buf;

extern int _fastcall mysetjmp(myjmp_buf *jbuf);
extern void _fastcall mylongjmp(myjmp_buf *jbuf, int value);
extern void save_stack(std::vector<char> *dest, unsigned long last, myjmp_buf *callee);

class CoroutineBase {
public:
    virtual ~CoroutineBase();
};

extern std::stack<CoroutineBase *> coroutines;

template <class T> class Coroutine : public CoroutineBase {
    myjmp_buf caller, callee;
    std::vector<char> stack;
    std::function<void()> f;
    int status;
    unsigned long last;

    void exec() {
        f();
        mylongjmp(&caller, 2);
    }

public:
    T value;
    Coroutine() : status(0) {}
    Coroutine(const decltype(f) &f) : f(f), status(0) {}
    void operator=(const decltype(f) &f) { this->f = f; }

    bool operator()() {
        if (status == 0) _alloca(32 * 1024);
        switch (mysetjmp(&caller)) {
        case 1:
            return true;
        case 2:
            coroutines.pop();
            status = 3;
            return false;
        }
        switch (status) {
        case 0:
            last = caller.esp;
            status = 1;
            coroutines.push(this);
            exec();
        case 2:
            if (caller.esp < callee.esp)
                return false;
            coroutines.push(this);
            mylongjmp(&callee, 1);
        }
        return false;
    }

    T yield(T value) {
        if (coroutines.top() == this) {
            coroutines.pop();
            status = 2;
            this->value = value;
            if (mysetjmp(&callee) == 0) {
                save_stack(&stack, last, &callee);
                mylongjmp(&caller, 1);
            }
        }
        return this->value;
    }
};

template <class T> T yield(T value) {
    auto cr = dynamic_cast<Coroutine<T> *>(coroutines.top());
    return cr ? cr->yield(value) : T();
}

Coroutine.cpp

#include "Coroutine.h"

_declspec(naked) int _fastcall mysetjmp(myjmp_buf *jbuf) {
    _asm {
        pop edx
        mov [ecx   ], edx
        mov [ecx+ 4], esp
        mov [ecx+ 8], ebp
        mov [ecx+12], ebx
        mov [ecx+16], edi
        mov [ecx+20], esi
        xor eax, eax
        mov [ecx+24], eax
        mov [ecx+28], eax
        jmp edx
    }
}

_declspec(naked) void _fastcall mylongjmp(myjmp_buf *jbuf, int value) {
    _asm {
        mov eax, edx
        mov edx, ecx
        mov esp, [edx+ 4]
        mov edi, esp
        mov esi, [edx+24]
        mov ecx, [edx+28]
        cld
        rep movsb
        mov ebp, [edx+ 8]
        mov ebx, [edx+12]
        mov edi, [edx+16]
        mov esi, [edx+20]
        jmp dword ptr [edx]
    }
}

void save_stack(std::vector<char> *dest, unsigned long last, myjmp_buf *callee) {
    callee->length = last - callee->esp;
    dest->resize(callee->length);
    callee->stack = &(*dest)[0];
    memcpy(callee->stack, (void *)callee->esp, callee->length);
}

std::stack<CoroutineBase *> coroutines;

CoroutineBase::~CoroutineBase() {}

¥µ¥ó¥×¥ë


¾¯¤·¶Å¤Ã¤¿»È¤¤Êý¤ò¾Ò²ð¡£

¿½Å¥³¥ë¡¼¥Á¥ó

·¿¤¬¼Â¹Ô»þȽÄê¤Î¤¿¤á¡¢·¿»ØÄê¤ò´Ö°ã¤¨¤ë¤ÈÆ°¤«¤Ê¤¤¤Î¤ÇÃí°Õ¡£

#include <iostream>
#include <string>
#include "Coroutine.h"

using namespace std;

void test1() {
    yield<string>("abc");
    yield<string>("1234");
    yield<string>("finish!");
}

void test2() {
    Coroutine<string> cr = test1;
    while (cr()) {
        auto s = cr.value;
        cout << s << ": ";
        yield<int>(s.size());
    }
}

int main() {
    Coroutine<int> cr = test2;
    while (cr())
        cout << cr.value << endl;
}


°ú¿ô

¥³¥ë¡¼¥Á¥ó¤Î·Ñ³»þ¤Ë°ú¿ô¡ÊÁêÅö¡Ë¤òÅϤ¹ÊýË¡¡£

value¤ò½ñ¤­´¹¤¨¤ë¤Èyield¤Ç¤½¤ÎÃͤ¬Ìᤵ¤ì¤ë¡£
¢¨¤¢¤é¤«¤¸¤á¤³¤ì¤¬¤Ç¤­¤ë¤è¤¦¤Ë¹Íθ¤·¤¿»ÅÍÍ¡£

#include <iostream>
#include "Coroutine.h"

using namespace std;

void test() {
    int n = 0;
    for (;;) n = yield(++n);
}

int main() {
    Coroutine<int> cr = test;
    if (cr()) cout << cr.value << endl;
    if (cr()) cout << cr.value << endl;
    cr.value = 5;
    if (cr()) cout << cr.value << endl;
}


¤³¤ì°Ê³°¤ÎÊýË¡¤ò¤¤¤¯¤Ä¤«¾Ò²ð¤¹¤ë¡£

¥¯¥í¡¼¥¸¥ã

¥¯¥í¡¼¥¸¥ã¤Ç¥í¡¼¥«¥ëÊÑ¿ô¤ò¥­¥ã¥×¥Á¥ã¡£

#include <iostream>
#include "Coroutine.h"

using namespace std;

int main() {
    int n = 0;
    Coroutine<int> cr = [&] {
        for (;;) yield(++n);
    };
    if (cr()) cout << cr.value << endl;
    if (cr()) cout << cr.value << endl;
    n = 5;
    if (cr()) cout << cr.value << endl;
}


¥á¥ó¥Ð

¥á¥ó¥ÐÊÑ¿ô¤ò½ñ¤­´¹¤¨¤ëÊýË¡¡£



´Ø¿ô¥ª¥Ö¥¸¥§¥¯¥È

´Ø¿ô¥ª¥Ö¥¸¥§¥¯¥È¤òÅϤ¹¤È¥¤¥ó¥¹¥¿¥ó¥¹¤¬ºî¤é¤ì¤Æ¡¢
°ú¿ô¤È¤·¤Æ¥á¥ó¥Ð¤ò¤¤¤¸¤ëÌÜŪ¤ÏãÀ®¤Ç¤­¤Ê¤¤¡£
¤¢¤Þ¤ê»È¤¤Æ»¤Ï¤Ê¤¤¤¬¡¢¥Ï¥Þ¤ë²ÄǽÀ­¤¬¤¢¤ë¤¿¤á¾Ò²ð¡£

¤¢¤ë°ÕÌ£¥¸¥§¥Í¥ì¡¼¥¿¤Ã¤Ý¤¤¡£
¤·¤«¤·³°Éô¤«¤éÃͤòÁàºî¤Ç¤­¤Ê¤¤¤Ê¤é¡¢
ñ½ã¤Ë¥í¡¼¥«¥ëÊÑ¿ô¤Ç¥«¥¦¥ó¥È¤·¤¿Êý¤¬Îɤ¤¡£

#include <iostream>
#include "Coroutine.h"

using namespace std;

int main() {
    struct Test {
        int n;
        Test() : n(0) {}
        void operator()() {
            for (;;) yield(++n);
        }
    } test;
    Coroutine<int> cr1 = test;
    if (cr1()) cout << "cr1: " << cr1.value << endl;
    if (cr1()) cout << "cr1: " << cr1.value << endl;
    Coroutine<int> cr2 = test;
    if (cr2()) cout << "cr2: " << cr2.value << endl;
    if (cr2()) cout << "cr2: " << cr2.value << endl;
    cout << "test.n: " << test.n << endl;
}


¤Þ¤È¤á

  • ¤¢¤é¤«¤¸¤á¥í¡¼¥«¥ëÍѤ˥¹¥¿¥Ã¥¯¤ò¼è¤Ã¤Æ¤ª¤¤¤Æ¤â¡¢
¥³¥ë¡¼¥Á¥ó¤«¤é¤Î´Ø¿ô¸Æ¤Ó½Ð¤·¤Ç¥¹¥¿¥Ã¥¯¤¬Ç˲õ¤µ¤ì¤ë¶²¤ì¤¬¤¢¤ë¡£
  • ¤½¤â¤½¤â¥¹¥¿¥Ã¥¯¤ò´¬¤­Ìᤷ¤¿»þÅÀ¤ÇÃͤÎÊݸ¤ò´üÂÔ¤·¤Æ¤Ï¤¤¤±¤Ê¤¤¡£
  • ¥Ò¡¼¥×¤Ê¤É¤Ë¥í¡¼¥«¥ë¥¹¥¿¥Ã¥¯¤ò¼è¤Ã¤Æ¤âƱÍͤÎÌäÂê
  • OSµ¡Ç½¤È¤·¤Æ¤Î¥Õ¥¡¥¤¥Ð¡¼¤ò»È¤¨¤ÐÊ̤˥¹¥¿¥Ã¥¯¤¬³ÎÊݤǤ­¤Æ¼«Æ°¿­Ä¥¤µ¤ì¤ë
    • ²¼²ó¤ê¤¬Windows¤Ë°Í¸¤¹¤ë¤¿¤áº£²ó¤ÏOS¥Õ¥¡¥¤¥Ð¡¼¤ò»È¤ï¤Ê¤¤
  • ¥¹¥ì¥Ã¥É¤Ç¤âÊ̤νê¤Ë¥¹¥¿¥Ã¥¯¤¬³ÎÊݤµ¤ì¤Æ¼«Æ°¿­Ä¥¤µ¤ì¤ë¡£
    • ¥¹¥ì¥Ã¥É¤òƱ´üŪ¤Ë¸Æ¤Ó½Ð¤»¤Ð¥Õ¥¡¥¤¥Ð¡¼¤È¤Û¤ÜÅù²Á
    • GUI¤Ê¤É¥¹¥ì¥Ã¥É°Í¸¤Î½èÍý¤Ç¥¹¥ì¥Ã¥É´Ö¸Æ¤Ó½Ð¤·¤¬É¬ÍפˤʤêÌÌÅÝ
  • ´¬¤­Ìᤷ¤ò»È¤ï¤Ê¤¤¥³¥ë¡¼¥Á¥ó¤¬ÍýÁÛŪ
  • ¸À¸ìµ¡Ç½¤È¤·¤Æ¼ÂÁõ¤Ç¤­¤ë¤Ê¤é¡¢¥í¡¼¥«¥ëÊÑ¿ô¤Ï¥á¥â¥ê¾å¤ÎǤ°Õ¤Ë¼è¤Ã¤Æ¡¢
¤½¤ì¤è¤ê²¼¤Ø¤Î¸Æ¤Ó½Ð¤·¤Ï¸½¹Ô¤Î¥¹¥¿¥Ã¥¯¤ò¾ÃÈñ¤µ¤»¤ë¤Î¤¬¥¹¥Þ¡¼¥È¡£

¥¤¥Ù¥ó¥È¤ÎľÎó²½


¥µ¥ó¥¯¤È°Ñ¾ù¤òƳÆþ¤·¤¿Win32¤Ë·Ñ³¤òÁȤ߹ç¤ï¤»¤ë¡£

¥¤¥Ù¥ó¥È¥É¥ê¥Ö¥ó¤Ç¾õÂÖ¤òÊÝ»ý¤·¤Æ¤¤¤ëÉôʬ¤Î¿Þ¼¨¡£
°ìÏ¢¤Îή¤ì¤¬Ê¬ÃǤµ¤ì¤Æ¤¤¤ë¡£

¡ù¢ª{}
¡ù¢ª{}
¡ù¢ª{}

¥¤¥Ù¥ó¥È´Ö¤Ç¾õÂÖ¤ò¶¦Í­¤¹¤ë¤¿¤á¥Õ¥é¥°¤ÎÎबɬÍפȤʤ롣
¥Ñ¥Ã¥·¥Ö¡Ê¥×¥Ã¥·¥å·¿¡Ë¤Ê¥³¡¼¥É¡£

¤³¤ì¤ò¥¢¥¯¥Æ¥£¥Ö¡Ê¥×¥ë·¿¡Ë¤Ê·Á¤ËÊÑ´¹¤¹¤ë¤È¡¢
¾õÂÖ¤Ïʬ´ô¤ä¥í¡¼¥«¥ëÊÑ¿ô¤Ë²¡¤·¹þ¤à¤³¤È¤¬¤Ç¤­¤ë¡£

·Ñ³¤Ï¤Ê¤ë¤Ù¤¯¥é¥¤¥Ö¥é¥ê¦¤Ë±£¤¹¤È»È¤¤¤ä¤¹¤¯¤Ê¤ë¡£

¥×¥í¥¸¥§¥¯¥È¤ËÄɲÃ


Á°²ó¤ÎÌäÂê¤Ç»ÈÍѤ·¤¿Win32¥×¥í¥°¥é¥à¤ò³ÈÄ¥¤¹¤ë¡£

Coroutine.h¤ÈCoroutine.cpp¤ò¥×¥í¥¸¥§¥¯¥È¤ËÄɲá£

stdafx.h¤ËÄɲá£

 // TODO: ¥×¥í¥°¥é¥à¤ËɬÍפÊÄɲåإåÀ¡¼¤ò¤³¤³¤Ç»²¾È¤·¤Æ¤¯¤À¤µ¤¤¡£
 #include <list>
 #include <functional>
 #include <string>
 #include "xbyak/xbyak.h"
 #include "Window.h"
+#include "Coroutine.h"

Coroutine.cpp¤Ç¤Ïstdafx.h¤òinclude¤¹¤ë¡£

- #include "Coroutine.h"
+ #include "stdafx.h"

¤³¤ì¤ÇCoroutine¥¯¥é¥¹¤ÎÄɲäϴ°Î»¡£

·Ñ³¤òÁȤ߹þ¤à


¥É¥é¥Ã¥°¤ò¥³¥ë¡¼¥Á¥ó¤Ç´Æ»ë¡£

https://gist.github.com/1275118

    int mx, my;
    Coroutine<bool> cr = [&] {
        for (;;) {
            yield(false);
            int x = mx, y = my, px = pb.x, py = pb.y;
            while (yield(true)) {
                pb.x = px + (mx - x);
                pb.y = py + (my - y);
                InvalidateRect(win.hWnd, nullptr, true);
            }
        }
    };
    cr();
    win.MouseDown.push_back([&](int btn, int x, int y, WPARAM) {
        if (pb.x <= x && x <= pb.x + 40 && pb.y <= y && y <= pb.y + 40) {
            mx = x;
            my = y;
            if (!cr.value) cr();
        }
    });
    win.MouseMove.push_back([&](int x, int y, WPARAM) {
        if (cr.value) {
            mx = x;
            my = y;
            cr();
        }
    });
    win.MouseUp.push_back([&](int btn, int x, int y, WPARAM) {
        if (cr.value) {
            cr.value = false;
            cr();
        }
    });

¥É¥é¥Ã¥°¤Î°ìÈ̲½


¤â¤¦¾¯¤·¥³¡¼¥É¤òÀ°Íý¤¹¤ë¡£

https://gist.github.com/1275258

Coroutine¥¯¥é¥¹¤ò³ÈÄ¥¤·¤Æ´¬¤­Ì᤻¤ë¤è¤¦¤Ë¤¹¤ë¡£

     Coroutine() : status(0) {}
     Coroutine(const decltype(f) &f) : f(f), status(0) {}
     void operator=(const decltype(f) &f) { this->f = f; }
+    void reset() { if (status == 3) status = 0; }
 
     bool operator()() {
         if (status == 0) _alloca(32 * 1024);

¥Ï¥ó¥É¥é¤È¤Î¶¨Ä´Æ°ºî¤òÃê½Ð¤·¤Æ¥¯¥é¥¹²½¤¹¤ë¡£
´¬¤­Ìᤷ¤òÍøÍѤ·¤Æ̵¸Â¥ë¡¼¥×¤òÇÓ½ü¤·¤Æ¤¤¤ë¡£

class DragHandler {
    Coroutine<bool> cr;
    std::function<void()> handler;

public:
    int x, y;

    DragHandler(Window *win) {
        win->MouseMove.push_back([&](int x, int y, WPARAM) {
            if (cr.value) { this->x = x; this->y = y; cr(); }
        });
        win->MouseUp.push_back([&](int button, int x, int y, WPARAM) {
            if (cr.value) { cr.value = false; cr(); }
        });
    }

    void operator=(const decltype(handler) &h) {
        cr = handler = h;
        cr.value = false;
    }

    void start(int x, int y) {
        this->x = x;
        this->y = y;
        if (!cr.value) { cr.reset(); cr(); }
    }
};

¤³¤ì¤ò»È¤Ã¤Æ¥Ï¥ó¥É¥é¤ò½ñ¤­Ä¾¤¹¡£

    DragHandler dh(&win);
    win.MouseDown.push_back([&](int btn, int x, int y, WPARAM) {
        if (pb.x <= x && x <= pb.x + 40 && pb.y <= y && y <= pb.y + 40)
            dh.start(x, y);
    });
    dh = [&] {
        int x = dh.x, y = dh.y, px = pb.x, py = pb.y;
        while (yield(true)) {
            pb.x = px + (dh.x - x);
            pb.y = py + (dh.y - y);
            InvalidateRect(win.hWnd, nullptr, true);
        }
    };

¥µ¥ó¥¯¡¦°Ñ¾ù¡¦·Ñ³¤ò»È¤Ã¤¿¥¤¥Ù¥ó¥È¥Ï¥ó¥É¥ê¥ó¥°¤¬´°À®¡£
¤³¤ì¤¬º£²óÄ󼨤·¤¿¤«¤Ã¤¿¥â¥Ç¥ë¡£

­²ó¤ê¤«¤éºî¤Ã¤Æ¤¤¤¿¤Î¤Ç·ë¹½Ä¹¤¤Æ»¤Î¤ê¤À¤Ã¤¿¤±¤É¡¢
¤Ç¤­¤¿¤â¤Î¤òÍøÍѤ¹¤ë¤À¤±¤Ê¤é¥·¥ó¥×¥ë¤À¤È»×¤¦¡£

Ê£¿ô¹àÌÜ


Ê£¿ô¤Î¹àÌܤò°·¤¨¤ë¤è¤¦¤Ë¤·¤Æ¤ß¤ë¡£

https://gist.github.com/1275467

    struct Rect {
        int x, y, w, h;
        inline int r() { return x + w; }
        inline int b() { return y + h; }
        Rect(int x, int y, int w, int h): x(x), y(y), w(w), h(h) {}
        bool contains(int px, int py) {
            return x <= px && px < r() && y <= py && py < b();
        }
    };
    std::vector<Rect> rects;
    rects.push_back(Rect(10, 10, 40, 40));
    rects.push_back(Rect(60, 60, 40, 40));
    win.Paint.push_back([&](HDC hdc) {
        auto oldPen = (HPEN)SelectObject(hdc, GetStockObject(BLACK_PEN));
        auto oldBrush = (HBRUSH)SelectObject(hdc, GetStockObject(GRAY_BRUSH));
        for (auto it = rects.begin(); it != rects.end(); it++)
            Rectangle(hdc, it->x, it->y, it->r(), it->b());
        SelectObject(hdc, oldPen);
        SelectObject(hdc, oldBrush);
    });

    DragHandler dh(&win);
    decltype(rects.rbegin()) sel;
    win.MouseDown.push_back([&](int btn, int x, int y, WPARAM) {
        for (auto it = rects.rbegin(); it != rects.rend(); it++) {
            if (it->contains(x, y)) {
                sel = it;
                dh.start(x, y);
                break;
            }
        }
    });
    dh = [&] {
        int x = dh.x, y = dh.y, rx = sel->x, ry = sel->y;
        while (yield(true)) {
            sel->x = rx + (dh.x - x);
            sel->y = ry + (dh.y - y);
            InvalidateRect(win.hWnd, nullptr, true);
        }
    };

¤Á¤é¤Ä¤­¤¬·ã¤·¤¤¤¬¡¢Âкö¤Ë¤Ï¥À¥Ö¥ë¥Ð¥Ã¥Õ¥¡¤¬É¬Íס£
º£²ó¤Ï¥µ¥ó¥¯¤È·Ñ³¤¬¥á¥¤¥ó¤Ê¤Î¤ÇÀâÌÀ¤Ï¸«Á÷¤ë¡£

ÌäÂê


[Ìä] ¿Þ·Á¤Î±¦²¼¤ò¤Ä¤Þ¤à¤È¥ê¥µ¥¤¥º¤Ç¤­¤ë¤è¤¦¤Ë¤·¤Æ¤ß¤Æ¤¯¤À¤µ¤¤¡£
²óÅúÎã

    DragHandler dh(&win), dh2(&win);
    decltype(rects.rbegin()) sel;
    win.MouseDown.push_back([&](int btn, int x, int y, WPARAM) {
        for (auto it = rects.rbegin(); it != rects.rend(); it++) {
            if (it->contains(x, y)) {
                sel = it;
                if (it->r() - x <= 5 && it->b() - y <= 5)
                    dh2.start(x, y);
                else
                    dh.start(x, y);
                break;
            }
        }
    });
    dh = [&] {
        int x = dh.x, y = dh.y, rx = sel->x, ry = sel->y;
        while (yield(true)) {
            sel->x = rx + (dh.x - x);
            sel->y = ry + (dh.y - y);
            InvalidateRect(win.hWnd, nullptr, true);
        }
    };
    dh2 = [&] {
        int x = dh2.x, y = dh2.y, rw = sel->w, rh = sel->h;
        while (yield(true)) {
            sel->w = rw + (dh2.x - x);
            sel->h = rh + (dh2.y - y);
            InvalidateRect(win.hWnd, nullptr, true);
        }
    };

½ª¤ï¤ê¤Ë


º£²ó·ÇºÜ¤·¤¿¥µ¥ó¥×¥ë¥³¡¼¥É¤Ï¤¹¤Ù¤ÆCC0¤ÇÄ󶡤·¤Þ¤¹¡£

º£²ó¤ä¤Ã¤¿¤è¤¦¤ÊÆâÍƤòÊÙ¶¯¤¹¤ë¤Ë¤Ï¡¢
´û¸¤Î¥³¥ó¥Ñ¥¤¥é¤Î½ÐÎϤòÅð¤ß¸«¤·¤Ê¤¬¤é¡¢
¼«Ê¬¤Ç¥³¥ó¥Ñ¥¤¥é¤òºî¤Ã¤Æ¤ß¤ë¤Î¤¬Îɤ¤¤È»×¤¤¤Þ¤¹¡£

»²¹Í»ñÎÁ


¥µ¥ó¥¯

  • WTL/ATL¤Î¥á¥Ã¥»¡¼¥¸¥Þ¥Ã¥×¼Â¸½¤Î¤·¤¯¤ß
http://hp.vector.co.jp/authors/VA022575/c/msgmap.h...

¥³¥ë¡¼¥Á¥ó
  • libconcurrent
http://code.google.com/p/libconcurrent/wiki/Projec...
    • @sharow¤µ¤ó¤Ë¤è¤ë¥³¥ë¡¼¥Á¥ó¥é¥¤¥Ö¥é¥ê¡£³Æ¼ï¼ÂÁõ¤Î¥ê¥ó¥¯½¸¤¬¤¢¤ë¡£
  • [C#][programming]C# ¤Î yield return ¤Î»È¤¤Æ»
http://d.hatena.ne.jp/u_1roh/20080302/1204471238
    • ¥¤¥Ù¥ó¥È¥Ï¥ó¥É¥é¤È¥³¥ë¡¼¥Á¥ó¤Ë´Ø¤¹¤ëµÄÏÀ