Visual Studio Installer で、ActiveX EXE を含むインストーラを作成して、実際にインストールしようとすると、
エラー1904 モジュール (ActiveX.Exeのプログラム名) の登録に失敗しというメッセージが表示される。継続を選択するとインストールは完了するが、ActiveX EXE がレジストリに登録されないままである。インストール時に登録するには、ちょっと設定をいじってやる必要がある。Google グループ: Visual Studio Installerについて が参考になる。以下引用。
- レジストリエディタでActiveX EXEのCLSIDを調べて、メモっておきます。
- プロジェクトエクスプローラの依存関係にActiveX EXEが含まれていることを確認します。(参照設定がされていれば、依存関係に追跡されると思います。)
- プロジェクトエクスプローラの依存関係にActiveX EXEをクリックしてプロパティの中のRegisterプロパティを0(vsifrNone)を選択します。
- プロジェクトエクスプローラから「関連付け」をダブルクリックして関連付けウィンドウを表示します。COMオブジェクトを選択して右ボタンクリックで「COMオブジェクトの追加」を選択します。このとき先にメモっておいたCLSIDを追加するCOMオブジェクトの名前として使います。
- 追加したCOMオブジェクトのプロパティの中のComponentプロパティにActiveXEXEを選択します。
- COMオブジェクトのプロパティの中のContextプロパティを2(vsiccLocalServer32)を選択します。
2004.08.05 追記
-----------------------
/RegServer オプションで登録したときと同じにするには、上記の手順でクラスの登録をするほかに、ActiveX EXE そのものをタイプライブラリ登録する必要がありそう。まだ調査中ですが。
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]" にするのが正解らしいです。
Win32 API に、 wsprintf という関数がある。一見すると、C標準の sprintf と同じ、いや、 UNICODE が定義されていると、ワイド版になるところも含めると、_stprintf か?と思ったら、実は wsprintf は sprintf にはない制限事項が。
wsprintfThe 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 では、上限は知らないけど、もっと大きなサイズを扱うことができるのは確かである。
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には、さらにルールがある。
- 空文字列はNULL
- 実体としてのBSTRはNULLエンドセンチネルを持つ
- 文字列内にL'\0'を保持できる
- BLOBとして利用しても良い(UTF-16とは限らない)
えーと、空文字列はNULL、これは "" と、NULL は区別しないルールになってるって理解でいいの? だれか詳しい人、教えてください。
VC++ 6.0 のプロジェクトワークスペースを開くとき、"ClassView 情報ファイルにアクセスできません。ClassView 情報が使用できません。"というメッセージが表示されることがある。同じプロジェクトを2つ開こうとしたときや、Visual Source Safe でソース管理しているときなんかに出くわすんだけど、これはプロジェクトの *.ncb ファイルがロックされているため起こる。ソース管理時は *.ncb ファイルは管理の対象としない方がいい。
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.lib と Libcmtd.lib を追加し(区切りはスペースでもカンマでもいいみたい)、「オブジェクト/ライブラリ モジュール」の方で、あらためて Nafxcwd.lib と Libcmtd.lib の順で指定したら、その順にリンクされるからうまくいく、と書いてある。
実はこれには補足があって、Nafxcwd.lib とLibcmtd.lib はともにデバッグ用のライブラリである。なので、Release でエラーが出る場合には、それぞれ Nafxcw.lib, Libcmt.lib に読み替えて設定する必要がある。
246772 - HOWTO: Retrieve and Set the Default Printer in Windows
SUMMARYYou can retrieve or set the default printer by using different methods, depending on the version of Windows that you use.
MORE INFORMATIONWith 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.