fc2ブログ

lltoa(インラインアセンブラ版)

64ビット符号付き整数(LONGLONG)を文字列に変換する関数。
無駄にアセンブラで実装。
必要に駆られて作ったけど要らなくなってしまい消すのも勿体無いのでメモ。
速度よりサイズ重視。まだ改良の余地はありげ。
# バッファに反転コピー辺りはストリング命令使えばもっと良くなるはず

肝は負数は反転して正数にしてしまうのと64bit整数の割り算で商が32bitを超える場合の対処法で、最初に上位32bitを割っておいてその商を別に保存し、余りを上位32bitに設定しなおして再度割ってやるとオーバーフローせずに32bitに収まり、別に保存した上位32bitと計算結果の商の下位32bitで64bitの商が弾き出せます。

というわけで以下コード。

void lltoa(LONGLONG value, char *string)
{
char tmp[20];
_asm {
; edi データ保存
; esi 割る数(10)
; ecx:ebx value
// 絶対値取得
lea edi, tmp
mov esi, 10
mov ecx, dword ptr[value+4]
mov ebx, dword ptr[value]
or ecx, ecx
jge LTA1
mov eax, ecx
mov edx, ebx
neg eax
neg edx
sbb eax, 0
mov ecx, eax
mov ebx, edx
mov eax, string
mov [eax], '-'
inc string
// 商余Get
LTA1: mov eax, ecx
xor edx, edx
div esi
mov ecx, eax ; 商上位32bit
mov eax, ebx
div esi
mov ebx, eax ; 商下位32bit
add edx, '0' ; 余
mov [edi], dl
inc edi
test ecx,ecx
jne LTA1
test ebx,ebx
jne LTA1
// バッファに反転コピー
lea ebx, tmp
mov esi, string
LTA2: dec edi
mov al, [edi]
mov [esi], al
inc esi
cmp edi, ebx
jne LTA2
mov [esi], 0
}
}
スポンサーサイト



自作PathCompactPath

Win32APIのPathCompactPathは長いファイル名を表示する際に表示領域から
はみ出してしまった分を...に置き換えて省略してくれる便利なAPIですが
SHLWAPI.DLLに実装されているのでIEが古いと使えません。
そこで自作して同じ機能の物を作成。

これ、実は結構簡単。キモはDrawTextEx。
引数にDT_PATH_ELLIPSISとDT_MODIFYSTRINGとDT_CALCRECTを指定すると
省略されたパスを取得できます。
DT_PATH_ELLIPSISはパスを省略させるフラグで
DT_MODIFYSTRINGは省略されたパスを保存するフラグで
DT_CALCRECTは描写を抑えるフラグになります。
これを組み合わせる事で省略されたパスを取得できます。

なぜDrawTextでは無くDrawTextExなのかというと
DrawTextの2番目の引数に変換するパスを渡す訳ですが
これLPCTSTR、つまりconst指定なので本来ならココに指定したバッファは
変更されてはいけないはずなんです。でも無理矢理変換してしまうようですが。
# これは完全に実装ミスだよなぁ。
それがDrawTextExだとconst指定ではないので安心です。

それを踏まえてコードを書くと以下のような感じです。
BOOL MyPathCompactPath(HDC hDC, LPTSTR lpszPath, UINT dx)
{
int nRes;
RECT rc = { 0, 0, dx, 0 };
nRes = ::DrawTextEx(hDC, lpszPath, -1, &rc,
DT_PATH_ELLIPSIS |
DT_MODIFYSTRING |
DT_CALCRECT, NULL);
return (nRes != 0);
}

 
オマケでPathSetDlgItemPathの代用
bool MyPathSetDlgItemPath(HWND hDlg, int id, LPCSTR pszPath)
{
char* lpsz = new char[::lstrlen(pszPath) + 4];
::lstrcpy(lpsz, pszPath);
HWND hItemWnd = ::GetDlgItem(hDlg, id);
HDC hDC = ::GetDC(hItemWnd);
HGDIOBJ hFont = (HGDIOBJ)::SendMessage(hItemWnd, WM_GETFONT,
0, 0);
HGDIOBJ hOldFont = ::SelectObject(hDC, hFont);
RECT rc;
int nRes;
::GetClientRect(hItemWnd, &rc);
nRes = ::DrawTextEx(hDC, lpsz, -1, &rc,
DT_PATH_ELLIPSIS |
DT_MODIFYSTRING |
DT_CALCRECT, NULL);
::SelectObject(hDC, hOldFont);

::ReleaseDC(hItemWnd, hDC);
::SetWindowText(hItemWnd, lpsz);
delete [] lpsz;
return (nRes != 0);
}

ポイントとしてデバイスコンテキストにきちんとフォントを設定してやらないと
きちんとコントロールに収まらないのでその辺を処理してます。
それからDrawTextExでDT_PATH_ELLIPSISフラグを設定すると
最大で4バイト長くなる場合が有るのでそのぶん多く確保してます。

新規記事の投稿


月別アーカイブ
カテゴリー
リンク
ブログ内検索
RSSフィード