< May 2004 | June 2004 | July 2004 >

June 30, 2004

Visual Studio Installer で、ActiveX EXE をインストールする

Visual Studio Installer で、ActiveX EXE を含むインストーラを作成して、実際にインストールしようとすると、

エラー1904 モジュール (ActiveX.Exeのプログラム名) の登録に失敗し
ました。HRESULT-2147024885 サポートへお問い合わせください。

というメッセージが表示される。継続を選択するとインストールは完了するが、ActiveX EXE がレジストリに登録されないままである。インストール時に登録するには、ちょっと設定をいじってやる必要がある。Google グループ: Visual Studio Installerについて が参考になる。以下引用。

  1. レジストリエディタでActiveX EXEのCLSIDを調べて、メモっておきます。
  2. プロジェクトエクスプローラの依存関係にActiveX EXEが含まれていることを確認します。(参照設定がされていれば、依存関係に追跡されると思います。)
  3. プロジェクトエクスプローラの依存関係にActiveX EXEをクリックしてプロパティの中のRegisterプロパティを0(vsifrNone)を選択します。
  4. プロジェクトエクスプローラから「関連付け」をダブルクリックして関連付けウィンドウを表示します。COMオブジェクトを選択して右ボタンクリックで「COMオブジェクトの追加」を選択します。このとき先にメモっておいたCLSIDを追加するCOMオブジェクトの名前として使います。
  5. 追加したCOMオブジェクトのプロパティの中のComponentプロパティにActiveXEXEを選択します。
  6. COMオブジェクトのプロパティの中のContextプロパティを2(vsiccLocalServer32)を選択します。

2004.08.05 追記
-----------------------
/RegServer オプションで登録したときと同じにするには、上記の手順でクラスの登録をするほかに、ActiveX EXE そのものをタイプライブラリ登録する必要がありそう。まだ調査中ですが。

June 22, 2004

Windows Installer で、デフォルトのインストール先を指定する

Visual Studio Installer で作ったインストーラは、デフォルトのインストール先を指定することができない。でも、業務アプリなんかだと、たとえば、C:\foo にインストールしたいような場合とかあるんだよね。これを変更するには、Windows Installer のカスタマイズには必須のツール、Orca を使う。

まず、Windows Installer SDK を手に入れる。これは MS の Platform SDK Update より入手。デフォルトなら、 C:\Program Files\Microsoft SDK\Bin にOrca.msi があるので、これを実行して Orca をインストールする。

次に、Orca を起動して、ウインドウに修正したい MSI ファイルをドロップする。
Tables より、Custom Action を選択すると、右側に DIR_CA_TARGETDIR ってアクションがあると思う。値は、えーと、"[ProgramFilesFolder]foo" とかになってるかな?これがインストール先になるので、ここを書き換えてしまう。

ためしに、"C:\foo" に変更してみたら、うまくいった。
でも、システムの入ったドライブのfoo、とする場合は、C:\ を決めうちするより、"[WindowsVolume]" にするのが正解らしいです。

wsprintf と sprintf

Win32 API に、 wsprintf という関数がある。一見すると、C標準の sprintf と同じ、いや、 UNICODE が定義されていると、ワイド版になるところも含めると、_stprintf か?と思ったら、実は wsprintf は sprintf にはない制限事項が。

wsprintf

The wsprintf function formats and stores a series of characters and values in a buffer. Any arguments are converted and copied to the output buffer according to the corresponding format specification in the format string. The function appends a terminating null character to the characters it writes, but the return value does not include the terminating null character in its character count.

int wsprintf(
LPTSTR lpOut, // pointer to buffer for output
LPCTSTR lpFmt, // pointer to format-control string
... // optional arguments
);


Parameters
lpOut
Pointer to a buffer to receive the formatted output. The maximum size of the buffer is 1024 bytes.
lpFmt
Pointer to a null-terminated string that contains the format-control specifications. In addition to ordinary ASCII characters, a format specification for each argument appears in this string. For more information about the format specification, see the Remarks section.
...
Specifies one or more optional arguments. The number and type of argument parameters depend on the corresponding format-control specifications in the lpFmt parameter.

そう、出力結果の上限が 1024 バイトまでなのだ。それを越えた出力結果はちょん切られる。終端には '\0' が付かないようである。sprintf では、上限は知らないけど、もっと大きなサイズを扱うことができるのは確かである。

June 17, 2004

vbNullString

vbNullString という組み込み定数がある。
コードエディタで記述して、Shift + F2 を叩いてみる。

Const vbNullString = ""
VBA.Constants のメンバ
0 の値を持つ文字列を要求する外部プロシージャを呼び出すときに使う定数です。

さらに MSDN をひいてみる

vbNullString 値 0 を持つ文字列
長さ 0 の文字列 ("") とは異なります。外部プロシージャを呼び出す場合に使用します。

えーと、つまり、NULL ポインタだと思ったらいい? LPCTSTR でいうところの、長さ 0 の文字列は、

LPCTSTR lpszZeroLengthString = "";

なのに対して、

LPCTSTR lpszNullString = NULL;

みたいなもんだと思っていい?、ってずっと理解してた。でもさ、

If vbNullString = "" Then
	Debug.Print "vbNullString = """""
Else
	Debug.Print "vbNullString != """""
End If

は、
vbNullString = ""
となるんだよね。しかも、String 型の初期値は vbNullString だっていう情報まで。

この疑問のヒントになりそうなのが、The Backyard - BSTR にある。

BSTRには、さらにルールがある。
  1. 空文字列はNULL
  2. 実体としてのBSTRはNULLエンドセンチネルを持つ
  3. 文字列内にL'\0'を保持できる
  4. BLOBとして利用しても良い(UTF-16とは限らない)

えーと、空文字列はNULL、これは "" と、NULL は区別しないルールになってるって理解でいいの? だれか詳しい人、教えてください。

June 11, 2004

ClassView 情報ファイルにアクセスできません。ClassView 情報が使用できません。

VC++ 6.0 のプロジェクトワークスペースを開くとき、"ClassView 情報ファイルにアクセスできません。ClassView 情報が使用できません。"というメッセージが表示されることがある。同じプロジェクトを2つ開こうとしたときや、Visual Source Safe でソース管理しているときなんかに出くわすんだけど、これはプロジェクトの *.ncb ファイルがロックされているため起こる。ソース管理時は *.ncb ファイルは管理の対象としない方がいい。

June 7, 2004

error LNK2005

MFC を使用したプロジェクトで、こんなリンクエラーがでた。

コードを生成中...
リンク中...
nafxcw.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z) はすでに LIBCMT.lib(new.obj) で定義されています
nafxcw.lib(afxmem.obj) : error LNK2005: "void __cdecl operator delete(void *)" (??3@YAXPAX@Z) はすでに LIBCMT.lib(delete.obj) で定義されています
Release/Ocrreruset.exe : fatal error LNK1169: 1 つ以上の複数回定義されているシンボルが見つかりました
link.exe の実行エラー

ググってみたら、148652 - [PRB] C ランタイム ライブラリを MFC ライブラリより先にリンクしたときの LNK2005 エラーというのが見つかった。これによると、

CRT ライブラリでは、new、delete、および DllMain の各関数で弱い外部リンケージを使用します。MFC ライブラリにも new、delete、および DllMain の各関数が含まれており、このために MFC ライブラリを CRT ライブラリより先にリンクする必要があります。

ということであるらしい。解決策として、プロジェクトの設定でリンクの「無視するライブラリ」に Nafxcwd.libLibcmtd.lib を追加し(区切りはスペースでもカンマでもいいみたい)、「オブジェクト/ライブラリ モジュール」の方で、あらためて Nafxcwd.libLibcmtd.lib の順で指定したら、その順にリンクされるからうまくいく、と書いてある。

実はこれには補足があって、Nafxcwd.lib とLibcmtd.lib はともにデバッグ用のライブラリである。なので、Release でエラーが出る場合には、それぞれ Nafxcw.lib, Libcmt.lib に読み替えて設定する必要がある。

続きを読む...

June 3, 2004

Windows NT 系でデフォルトプリンタを調べる

246772 - HOWTO: Retrieve and Set the Default Printer in Windows

SUMMARY

You can retrieve or set the default printer by using different methods, depending on the version of Windows that you use.

MORE INFORMATION

With Windows NT 4.0 (and earlier versions), you cannot use:

  • Either SetPrinter or SetDefaultPrinter to set the default printer.
  • Either EnumPrinters or GetDefaultPrinter to get the default printer.

With Windows NT 4.0, you can use:

  • GetProfileString to get the default printer.
  • WriteProfileString to set the default printer.