Windows7 では、WebDAVをネットワークドライブとして割り当てることができました。
「ネットワークドライブとWebDAV over SSL」
ですが、WindowsXP(SP3)では失敗してしまいました。
XPでは、ネットワークドライブの割り当てに、WebDAVは使えないようです。
XPではWebフォルダ(ネットワークプレース?)を作成することで解決できるようです・・・が、肝心のネットワークプレースをWindowsAPIを使って作成方法がマイクロソフトからは公開されてないみたいです。
すみません、Windowsのネットワーク関係のことがよく分かってません。ので、まるでトンチンカンなことを書いてるかもしません。備忘録なので、ご注意を。)
ネットワークプレースの仕組み自体はカンタン。。。というか、ネットワークプレース自体がフォルダーリンクなので、
- ディレクトリを作成
- 作ったディレクトリの中に target という名のショートカットを作成
- そのショートカットにリードオンリー属性をつける。
- 下記内容のDesktop.ini(要システム・隠し属性)ファイルを作成
[.ShellClassInfo]
CLSID2={0AFACED1-E828-11D1-9187-B532F1E9575D}
Flags=2
- ディレクトリにリードオンリー属性に。
これだけ。ショートカットはIShellLink/IPersistFile インターフェイスで作れます。
だだ、この方法では WebDAV(https/http)のネットワークプレースは作れません。
理由は至極当然で、上記(2)のWebDAVのアドレスへのショートカットが原因で、具体的には、https/http などのURIリンク先を単純にIShellLink::SetPath()に渡しても、ショートカットファイル自体は作れても、エクスプローラからWebフォルダとしては認識されません。
リンク先が、HTTP/HTTPSのURLではなく、FTP(ftp://server_name/directory/)や共有フォルダ(\\server_name\folder)のURIならうまくいきます。
このHTTP/HTTPSへのショートカットファイルは、普通のショートカットファイルではなく、どうやら特殊な(非公開の)方法で作られる必要があるようです。
もしかしたら公式のMSDNドキュメントに記述されているのかもしれません。が、結構検索かけて探してみたけどわかりませんでした。ご存じの方は教えて欲しいです (--;;;
WebDAV APIというのがあって、DavAddConnectionなどのようなAPIはありますが、Vista以降用のもののようですし、そもそも DavAddConnectionなどのAPIはSSL接続用、というようなことが書かれてますので、ちょっと違うみたいです。
で、もうちょっとグーグル先生に粘って聞いてみると・・・マイクロソフトのユーザーフォーラム?でそれらしき情報がありました。
【How to create web folders programmatically using Windows Script Host】
英文を要約すると、target.lnk そのもののバイト配列を用意してファイルに書き込むという、かなり力技で強引な(^^;;解決方法が提示されてます。
エクスプローラシェルでWebフォルダを作った後、そのtarget.lnkを解析したみたいですね。
この情報を元に、整理してC/C++で書き直して見ました。
#pragma comment(lib,"shell32.lib")
#define URI_LIMIT_SIZE 1024
#include <windows.h>
#include <strsafe.h>
#include <shlobj.h>
/*
pURI : WebDAVへのhttp/httpsから始まるURLアドレス
pDir : ネットワークプレースを作成するディレクトリ
pName : ネットワークプレースの名前
*/
HRESULT CreateURILinkByEmbedByteArray(PCTSTR pURI,PCTSTR pDir,PCTSTR pName)
{
HRESULT hres = S_OK;
TCHAR szPath[MAX_PATH] = {0};
TCHAR szDir[MAX_PATH] = {0};
WCHAR szName[URI_LIMIT_SIZE] = {0};
WCHAR szURI[URI_LIMIT_SIZE] = {0};
HANDLE hFile = NULL;
DWORD dwLen = 0;
BYTE part1[] =
{ 0x4c,0x00,0x00,0x00,0x01,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,
0x00,0x00,0x00,0x46,0x81,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0x14,0x00,
0x1f,0x50,0xe0,0x4f,0xd0,0x20,0xea,0x3a,0x69,0x10,0xa2,0xd8,0x08,0x00,0x2b,0x30,
0x30,0x9d,0x14,0x00,0x2e,0x00,0x00,0xdf,0xea,0xbd,0x65,0xc2,0xd0,0x11,0xbc,0xed,
0x00,0xa0,0xc9,0x0a,0xb5,0x0f,0xa4,0x00,0x4c,0x50,0x00,0x01,0x42,0x57,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,
0x00,0x00};
BYTE part2[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
BYTE nameLen[] = {0x00, 0x00};
BYTE uriLen[] = {0x00, 0x00};
int cbLen = lstrlen(pName);
part1[0x4d] = part1[0x77] = (cbLen <= 44) ? 0x00 : 0x01;
nameLen[0] = cbLen % 0x100;
nameLen[1] = cbLen / 0x100;
//ワイド文字に変換。ユニコードでビルドする場合は、単にコピーするだけ。
#ifdef UNICODE
StringCchCopy(szURI,URI_LIMIT_SIZE,pURI);
StringCchCopy(szName,MAX_PATH,pName);
#else
MultiByteToWideChar(CP_ACP,0,pURI,-1,szURI,URI_LIMIT_SIZE);
MultiByteToWideChar(CP_ACP,0,pName,-1,szName,MAX_PATH);
#endif
cbLen = lstrlen(pURI);
uriLen[0] = cbLen % 0x100;
uriLen[1] = cbLen / 0x100;
//ディレクトリの作成
StringCchPrintf(szDir,
MAX_PATH,
TEXT("%s%s%s"),
pDir,
(szDir[lstrlen(szDir) - 1] != TEXT('\\')) ? TEXT("\\") : TEXT(""),
pName);
SHCreateDirectoryEx(NULL,szDir,NULL);
//target.lnkのパスを生成
StringCchPrintf(szPath,MAX_PATH,TEXT("%s\\%s"),szDir,TEXT("target.lnk"));
//シェルリンク・ファイルへの書込み
hFile = CreateFile(szPath,
GENERIC_WRITE,
0,
NULL,
CREATE_NEW,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(hFile == INVALID_HANDLE_VALUE || GetLastError() == ERROR_ALREADY_EXISTS)
{
hres = E_FAIL;
goto cleanup;
}
//埋め込み
WriteFile(hFile,reinterpret_cast<PVOID>(part1),sizeof(part1),&dwLen,NULL);
WriteFile(hFile,reinterpret_cast<PVOID>(nameLen),2,&dwLen,NULL);
WriteFile(hFile,reinterpret_cast<PVOID>(szName),sizeof(WCHAR) * (lstrlenW(szName) + 1),&dwLen,NULL);
WriteFile(hFile,reinterpret_cast<PVOID>(uriLen),2,&dwLen,NULL);
WriteFile(hFile,reinterpret_cast<PVOID>(szURI),sizeof(WCHAR) * (lstrlenW(szURI) + 1),&dwLen,NULL);
WriteFile(hFile,reinterpret_cast<PVOID>(part2),sizeof(part2),&dwLen,NULL);
CloseHandle(hFile);
//ファイルにRO属性を設定
SetFileAttributes(szPath,FILE_ATTRIBUTE_READONLY);
//ディレクトリにRO属性
SetFileAttributes(szDir,FILE_ATTRIBUTE_READONLY);
cleanup:
return hres;
}
一応、会社で使っているWindows XP SP3ではネットワークプレースをプログラムから作成できました。
が!、当然ながら、Windows7では、うまくいきません(笑)
Windows7/Vista から仕様が変わったようです。当たり前か(^^;;;
う~ん・・・なんかこう、すんなり旨い方法がないものだろうか・・・。