« 夏なので… | メイン | Windows XPをインストールしたら、まずやること »

ubicast Bloggerの設定が保存できない件

以前、1.1.25のときに
My DocumentsやApplication Dataをサーバーにリダイレクトしていると、保存に失敗するよん。
と報告したのだが、
反応無いし、1.1.40でも直ってないので、ちょい詳しく報告してみる。

調べてみると、CreateDirectoryというWin32 APIがエラーを返していることが、直接の原因らしい。
引数に渡しているのはヌル文字列L""なので、当然か。

呼び出し部分のコードはこんな感じ。
bloggeru.exeモジュールは0x00420000にロードされている。

0042BC20  mov         eax,2804h
0042BC25  call        004FB960
0042BC2A  mov         eax,dword ptr ds:[00604C74h]
0042BC2F  push        ebx 
0042BC30  mov         ebx,dword ptr [esp+280Ch]
0042BC37  push        ebp 
0042BC38  push        esi 
0042BC39  push        edi 
0042BC3A  push        ebx 
0042BC3B  mov         dword ptr [esp+2814h],eax
0042BC42  call        dword ptr ds:[5114F0h]
0042BC48  test        eax,eax
0042BC4A  je          0042BC75
0042BC4C  lea         eax,[esp+810h]
0042BC53  push        eax 
0042BC54  push        0FFFh
0042BC59  call        dword ptr ds:[51017Ch]
0042BC5F  push        ebx 
0042BC60  lea         ecx,[esp+814h]
0042BC67  push        ecx 
0042BC68  call        dword ptr ds:[51150Ch]
0042BC6E  lea         ebx,[esp+810h]
0042BC75  mov         ebp,dword ptr ds:[5101F8h]
0042BC7B  mov         edi,ebx
0042BC7D  lea         ecx,[ecx]
0042BC80  mov         ax,word ptr [edi]
0042BC83  cmp         ax,5Ch
0042BC87  je          0042BCA2
0042BC89  lea         esp,[esp]
0042BC90  test        ax,ax
0042BC93  je          0042BCA2
0042BC95  mov         ax,word ptr [edi+2]
0042BC99  add         edi,2
0042BC9C  cmp         ax,5Ch
0042BCA0  jne         0042BC90
0042BCA2  mov         esi,edi
0042BCA4  sub         esi,ebx
0042BCA6  sar         esi,1
0042BCA8  lea         edx,[esi+1]
0042BCAB  push        edx 
0042BCAC  push        ebx 
0042BCAD  lea         eax,[esp+18h]
0042BCB1  push        eax 
0042BCB2  call        ebp 
0042BCB4  lea         eax,[esp+esi*2+10h]
0042BCB8  mov         word ptr [eax],0
0042BCBD  cmp         word ptr [eax-2],3Ah
0042BCC2  je          0042BCE3
0042BCC4  lea         ecx,[esp+10h]
0042BCC8  push        ecx 
0042BCC9  call        dword ptr ds:[511500h]
0042BCCF  test        eax,eax
0042BCD1  jne         0042BCE3
0042BCD3  push        eax 
0042BCD4  lea         edx,[esp+14h]
0042BCD8  push        edx 
0042BCD9  call        dword ptr ds:[510180h]
0042BCDF  test        eax,eax
0042BCE1  je          0042BCEE
0042BCE3  cmp         word ptr [edi],0
0042BCE7  je          0042BD07
0042BCE9  add         edi,2
0042BCEC  jmp         0042BC80
0042BCEE  pop         edi 
0042BCEF  pop         esi 
0042BCF0  pop         ebp 
0042BCF1  xor         eax,eax
0042BCF3  pop         ebx 
0042BCF4  mov         ecx,dword ptr [esp+2800h]
0042BCFB  call        004FB88D
0042BD00  add         esp,2804h
0042BD06  ret             
0042BD07  mov         ecx,dword ptr [esp+2810h]
0042BD0E  pop         edi 
0042BD0F  pop         esi 
0042BD10  pop         ebp 
0042BD11  mov         eax,1
0042BD16  pop         ebx 
0042BD17  call        004FB88D
0042BD1C  add         esp,2804h
0042BD22  ret             

このままだと見づらいので、Cっぽく手動変換。

0042BC20  mov         eax,2804h
0042BC25  call        004FB960
0042BC2A  mov         eax,dword ptr ds:[00604C74h]
0042BC2F  push        ebx 
0042BC30  mov         ebx,dword ptr [esp+280Ch]
0042BC37  push        ebp 
0042BC38  push        esi 
0042BC39  push        edi 

if (PathIsRelative(wzPath))

0042BC3A  push        ebx 
0042BC3B  mov         dword ptr [esp+2814h],eax
0042BC42  call        dword ptr ds:[5114F0h]
0042BC48  test        eax,eax
0042BC4A  je          0042BC75

{
    GetCurrentDirectoryW(wzTemp);

0042BC4C  lea         eax,[esp+810h]
0042BC53  push        eax 
0042BC54  push        0FFFh
0042BC59  call        dword ptr ds:[51017Ch] 

    PathAppendW(wzTemp, wzPath);

0042BC5F  push        ebx 
0042BC60  lea         ecx,[esp+814h]
0042BC67  push        ecx 
0042BC68  call        dword ptr ds:[51150Ch] 

    wzPath = wzTemp;

0042BC6E  lea         ebx,[esp+810h]

    LPWSTR *wcsPtr = wzPath;

0042BC75  mov         ebp,dword ptr ds:[5101F8h]
0042BC7B  mov         edi,ebx
0042BC7D  lea         ecx,[ecx]

    while (true)
    {
        if (*wcsPtr != L'\\')

0042BC80  mov         ax,word ptr [edi]
0042BC83  cmp         ax,5Ch
0042BC87  je          0042BCA2
0042BC89  lea         esp,[esp] 

        {
            while (*wcsPtr != L'\0')

0042BC90  test        ax,ax
0042BC93  je          0042BCA2 

            {
                if (*++wcsPtr == L'\\')
                {
                    break;
                }
            }

0042BC95  mov         ax,word ptr [edi+2]
0042BC99  add         edi,2
0042BC9C  cmp         ax,5Ch
0042BCA0  jne         0042BC90 

        }
        int cchFolder = wcsPtr - wzPath;

042BCA2  mov         esi,edi
0042BCA4  sub         esi,ebx
0042BCA6  sar         esi,1 

        lstrcpynW(wzBuf, wzPath, cchFolder + 1);

0042BCA8  lea         edx,[esi+1]
0042BCAB  push        edx 
0042BCAC  push        ebx 
0042BCAD  lea         eax,[esp+18h]
0042BCB1  push        eax 
0042BCB2  call        ebp  

        wzBuf[cchFolder] = L'\0';

0042BCB4  lea         eax,[esp+esi*2+10h]
0042BCB8  mov         word ptr [eax],0 

        if (wzBuf[cchFolder - 1] != L':')

0042BCBD  cmp         word ptr [eax-2],3Ah
0042BCC2  je          0042BCE3 

        {
            if (!PathFileExistsW(wzBuf))

0042BCC4  lea         ecx,[esp+10h]
0042BCC8  push        ecx 
0042BCC9  call        dword ptr ds:[511500h]
0042BCCF  test        eax,eax
0042BCD1  jne         0042BCE3 

            {
                if (!CreateDirectoryW(wzBuf, 0))
                    goto LError;
            }

0042BCD3  push        eax 
0042BCD4  lea         edx,[esp+14h]
0042BCD8  push        edx 
0042BCD9  call        dword ptr ds:[510180h]
0042BCDF  test        eax,eax
0042BCE1  je          0042BCEE 

        }
        if (*wcsPtr == L'\0')
            goto LExit;

0042BCE3  cmp         word ptr [edi],0
0042BCE7  je          0042BD07 

        wcsPtr++;
    }

0042BCE9  add         edi,2
0042BCEC  jmp         0042BC80

:LError

0042BCEE  pop         edi 
0042BCEF  pop         esi 
0042BCF0  pop         ebp 
0042BCF1  xor         eax,eax
0042BCF3  pop         ebx 
0042BCF4  mov         ecx,dword ptr [esp+2800h]
0042BCFB  call        004FB88D
0042BD00  add         esp,2804h
0042BD06  ret             

:LExit

0042BD07  mov         ecx,dword ptr [esp+2810h]
0042BD0E  pop         edi 
0042BD0F  pop         esi 
0042BD10  pop         ebp 
0042BD11  mov         eax,1
0042BD16  pop         ebx 
0042BD17  call        004FB88D
0042BD1C  add         esp,2804h
0042BD22  ret             

たぶんソースはこんな感じ。

hoge(LPWSTR wzPath)
{
    WCHAR wzTemp[MAX_PATH];

    if (PathIsRelative(wzPath))
    {
        GetCurrentDirectoryW(wzTemp);
        PathAppendW(wzTemp, wzPath);
        wzPath = wzTemp;
    }

    LPWSTR wcsPtr = wzPath;

    while (true)
    {
        WCHAR wzBuf[MAX_PATH];

        if (*wcsPtr != L'\\')
        {
            while (*wcsPtr != L'\0')
            {
                if (*++wcsPtr == L'\\')
                {
                    break;
                }
            }
        }

        int cchFolder = wcsPtr - wzPath;
        lstrcpynW(wzBuf, wzPath, cchFolder + 1);
        wzBuf[cchFolder] = L'\0';

        if (wzBuf[cchFolder - 1] != L':')
        {
            if (!PathFileExistsW(wzBuf))
            {
                if (!CreateDirectoryW(wzBuf, 0))
                    goto LError;
            }
        }

        if (*wcsPtr == L'\0')
            goto LExit;

        wcsPtr++;
    }

LError:
//略
LExit:
//略
}

たとえばMy Documentsが、
    サーバー名:MyServer
    共有名:Users
    フォルダー:me\マイ ドキュメント
にリダイレクトされていると、
wzPathにはL"\\\\MyServer\\Users\\me\\マイ ドキュメント\\マイエントリー"とかいう文字列が渡されてくる。

するとこの関数は、
    L""
    L"\\"
    L"\\\\MyServer"
    L"\\\\MyServerr\\Users"
    L"\\\\MyServerr\\Users\\me"
    L"\\\\MyServerr\\Users\\me\\マイドキュメント"
    L"\\\\MyServerr\\Users\\me\\マイドキュメント\\マイ エントリー"
というフォルダーを順に調べて、無ければ作ろうとするのだが、
最初のL""でCreateDirectoryWがエラーを返すという訳だ。
最後のやつ以外をdebuggerでスキップしてやれば、無事に保存できた。

フォルダーのリダイレクトは、自宅に限らず企業(私の勤務先を含め)では普通に使われている機能ではなかろうか?
全社員のデータをサーバーに集めておけば、まとめてバックアップが取れるのです。