set DCOM_MODULES=dcomcnfgを追加します。 プラットフォームをリビルドして、 ダウンロード/初期化でCEPCをデバッグ実行しておきます。 以後の作業は基本的にCEPCをデバッグ実行したまま行います。
extern "C" BOOL WINAPI NTLMSetUserInfo(LPTSTR, LPTSTR); ... case IDM_HELP_ABOUT: NTLMSetUserInfo(L"Adinistrator", L"PASSWORD"); DialogBox(hInst, ....また、設定…でデバッグのリンクのライブラリに c:\myproj\mycepc\WINCE410\CEPC\cesysgen\oak\lib\x86\debug\ntlmssp.lib を加えます。パスは適当に読み替えてください。
Platform builderでCEPCをデバッグ状態で実行していることを確認し、 eVCのPlatform Managerの構成でKITLトランスポートCESHサーバとなっていることを確認した後、 ビルド、実行し、ABOUTボックスを出すと、NTLMユーザが登録されます。
実際のパスワードはHKEY_LOCAL_MACHINE\Comm\Security\UserAccounts\Administrator にNTという160バイトのデータとして格納されます。 格納されているのはパスワードのLANMANハッシュ値(DES)とNTハッシュ値(MD4)なので、 生パスワードがそのまま書かれているわけではないです。
HKCR
{
Hello1.Class1.1 = s 'Hello1.Class1 Class'
{
CLSID = s '{091D8751-4E65-4B7C-8AC8-0C92B8FB43E9}'
}
Hello1.Class1 = s 'Hello1.Class1 Class'
{
CLSID = s '{091D8751-4E65-4B7C-8AC8-0C92B8FB43E9}'
CurVer = s 'Hello1.Class1.1'
}
NoRemove CLSID
{
ForceRemove {091D8751-4E65-4B7C-8AC8-0C92B8FB43E9} = s 'Hello1.Class1 Class'
{
ProgID = s 'Hello1.Class1.1'
val AppID = s '{E85159E6-07C1-4C91-B9E3-724E9A8A1D3D}'
VersionIndependentProgID = s 'Hello1.Class1'
ForceRemove 'Programmable'
InprocServer32 = s '%MODULE%'
{
val ThreadingModel = s 'Apartment'
}
'TypeLib' = s '{E85159E6-07C1-4C91-B9E3-724E9A8A1D3D}'
}
}
NoRemove AppID
{
{E85159E6-07C1-4C91-B9E3-724E9A8A1D3D} = s 'Hello1 Component'
{
val DllSurrogate = s ''
}
}
}
次にメソッドSumを追加します。
ClassViewからIClass1をポイントし、右クリックでメソッドの追加を選び、
メソッド名にSum、パラメータに int x, int y, [out,retval] int* sum
を入力します。
追加された関数CClass1::Sumに以下のように入力します。
STDMETHODIMP CClass1::Sum(int x, int y, int* sum)
{
// TODO: この位置にインプリメント用のコードを追加してください
*sum= x+y;
return S_OK;
}
書き換えたら、CEPCがデバッグ状態で実行されていることを確認し、ビルドします。
ビルドすると、Hello1.dllが作成され、自動的にCEPC:\Windowsに転送され、
さらにHello1.dllのDllRegisterServerが呼び出されます。
つまり、上記で指定したレジストリが反映されます。
代理親を指定しているので、Hello1.dllをデバッグ実行しておく必要はありません。
この追加した内容はHKCR\AppID\{E85159E6-07C1-4C91-B9E3-724E9A8A1D3D}の、 LaunchPermissionとAccessPermission値に設定されます。 プログラムからこれを設定する場合はDCOMAccessControlオブジェクトのIAccessControlを使います。
HKEY_CLASSES_ROOT\Hello1.Class1\CLSID = {091D8751-4E65-4B7C-8AC8-0C92B8FB43E9}
なお、クライアント側でのProgID(Hello1.Class1)とサーバCEPC側でのProgIDは違っていてもかまいません。あくまでCLSIDが一致していればいいです。
で、以前のVBクライアントのコードを修正し、
ボタンのイベントに以下のように記述します。
Private Sub Command1_Click()
Dim a As Object
Set a = CreateObject("Hello1.Class1", "192.168.0.10")
MsgBox a.Sum(10, 10)
End Sub
CEPCは標準では自分のマシン名を持たず、WINSに登録したりしませんので、
IPアドレスによる指定が必要です。
デバッグ実行しているCEPCのIPアドレスを調べるには
HKLM\Comm\VMINI1\Parms\TCPIPでも覗いてください。では実行してボタンを押してみましょう。エラーなく終了しましたか? オブジェクトを作成できないとか書き込みエラーが出る場合は、 セキュリティではねられている場合がほとんどです。 NTLMSetUserInfoを実行したか、 そのユーザとパスワードでクライアントはログインしているか、 Hello1.dllを登録したか、 dcomcnfgを実行してアクセス権を設定したか確認します。
エラーの状況によっては、Platform Builderが例外をキャッチしてCEPCが一時停止する場合がありますが、そのまま何回か実行継続すれば通常実行状態にもどります。 うっとおしい時はCE例外処理…で当該例外番号を登録してください。
なお、dcomcnfgで起動ユーザとアクセスユーザにAdministratorを登録しましたが、 これは @* を登録するとすべてのユーザに権限が与えられます。 ただし、ここで @* を設定しても HKCR\AppID\{E8..}\AuthenticationLevelにNONE=1を設定しても、 dcomcnfgでのデフォルト値(HKLM\SOFTWARE\Microsoft\OLE\LegacyAuthenticationLevel)にNONE=1を設定しても、 NTLMSetUserInfoで登録されていないユーザは権限を与えられないようです。 誰にでもとりあえずオブジェクトを起動させて、 オブジェクト内部で簡単な認証を行うことが出来るといいんですがねー。 SOAPは出来るよなあ、これ。
実際に通信用として用いるにはシングルトンオブジェクトを活用したりすることに なります。その他CE側をクライアントにするとかは普通にできると思うので、 ヘルプ→Application Dev.→Component Services(DCOM)とか参照してください。 DCOM全般については、インサイドCOM+基本編が実用書として良いかと思います。