VC++2010 UPnPポート開放

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Aqris

VC++2010 UPnPポート開放

#1

投稿記事 by Aqris » 10年前

現在VC++2010にてポート開放を行うアプリケーションを作成しています。
そこで以前こちらの掲示板に似た質問がありましたので、そのソースを利用させて頂きましたところ、ビルドエラーで行き詰まりました。
以下ソースコードです。

コード:

#include <windows.h>
#include <Natupnp.h>
#include <objbase.h>
#include <oleauto.h>
 
#pragma comment(lib,"ole32.lib")
#pragma comment(lib,"oleaut32.lib")
 
int main()
{
    // まずCOMの初期化
    ::CoInitialize( NULL );
 
    // インスタンス取得
    IUPnPNAT *nat;
    ::CoCreateInstance( CLSID_UPnPNAT, NULL, CLSCTX_ALL, IID_IUPnPNAT, (void **)&nat );
 
    // ポートマッピングのリスト取得
    IStaticPortMappingCollection *maps = NULL;
    nat->get_StaticPortMappingCollection( &maps );
 
    // アドレスと名前を登録できる形式に変更
    char *ip = "192.168.11.2"; //<- 自分のIPアドレス
    WCHAR localIPWideString[ 16 ];
    MultiByteToWideChar( CP_ACP, 0, ip, -1, localIPWideString, 16 );
    BSTR localIPBstr = SysAllocString( localIPWideString );
    BSTR proto = SysAllocString( L"TCP" ); //<- TCP/IPで登録する
    BSTR description = SysAllocString( L"TOOL" ); //<- ここはポートマッピングに登録する名前
 
    // ポートマッピング
    int port = 57630; //<- 開放するポート番号
    IStaticPortMapping *map;
    maps->Add( port, proto, port, localIPBstr, VARIANT_TRUE, description, &map );
 
    // BSTR の解放
    SysFreeString( description );
    SysFreeString( proto );
    SysFreeString( localIPBstr );
 
    // オブジェクト解放
    map->Release();
    maps->Release();
    nat->Release();
 
    // COMの終了
    ::CoUninitialize();
 
}
以下が今回表示されたエラー内容です。
error LNK2020: 未解決のトークン (0A00005A) CLSID_UPnPNAT
error LNK2020: 未解決のトークン (0A00005B) IID_IUPnPNAT
error LNK2001: 外部シンボル "IID_IUPnPNAT" は未解決です。
error LNK2001: 外部シンボル "CLSID_UPnPNAT" は未解決です。
fatal error LNK1120: 外部参照 4 が未解決です。

自身で調べてみましたが何分情報が少ないため、さっぱりです。
どうぞよろしくお願い致します。

YuO
記事: 947
登録日時: 14年前
住所: 東京都世田谷区

Re: VC++2010 UPnPポート開放

#2

投稿記事 by YuO » 10年前

uuid.libをリンクしてみてはどうでしょうか。

CLSID_UPnPNAT library linkでググったところ,最初に見つかったのがIUPnPNATというページ (newsgroupのアーカイブサイトっぽい)で,
そこにはuuid.libをリンクしろ,とMSの人の投稿がありました。
ただ,情報が古いために一応SDKのlibディレクトリで,

コード:

FOR %A IN (*.lib) DO @(
    ECHO %A
    dumpbin /symbols %A | find "UPnPNAT"
)
を実行したところ,uuid.libのみにCLSID_UPnPNATとIID_UPnPNATが定義されていました。

Aqris

Re: VC++2010 UPnPポート開放

#3

投稿記事 by Aqris » 10年前

YuO さん、返信有難うございます。
実際に試してみました所、エラー変わらずです。

コード:

#include <windows.h>
#include <Natupnp.h>
#include <objbase.h>
#include <oleauto.h>

#pragma comment(lib,"ole32.lib")
#pragma comment(lib,"oleaut32.lib")
#pragma comment(lib,"uuid.lib")

System::Void test()
{
    // まずCOMの初期化
    ::CoInitialize( NULL );
 
    // インスタンス取得
    IUPnPNAT *nat;
    ::CoCreateInstance( CLSID_UPnPNAT, NULL, CLSCTX_ALL, IID_IUPnPNAT, (void **)&nat );
 
    // ポートマッピングのリスト取得
    IStaticPortMappingCollection *maps = NULL;
    nat->get_StaticPortMappingCollection( &maps );
 
    // アドレスと名前を登録できる形式に変更
    char *ip = "192.168.11.2"; //<- 自分のIPアドレス
    WCHAR localIPWideString[ 16 ];
    MultiByteToWideChar( CP_ACP, 0, ip, -1, localIPWideString, 16 );
    BSTR localIPBstr = SysAllocString( localIPWideString );
    BSTR proto = SysAllocString( L"TCP" ); //<- TCP/IPで登録する
    BSTR description = SysAllocString( L"TOOL" ); //<- ここはポートマッピングに登録する名前
 
    // ポートマッピング
    int port = 57630; //<- 開放するポート番号
    IStaticPortMapping *map;
    maps->Add( port, proto, port, localIPBstr, VARIANT_TRUE, description, &map );
 
    // BSTR の解放
    SysFreeString( description );
    SysFreeString( proto );
    SysFreeString( localIPBstr );
 
    // オブジェクト解放
    map->Release();
    maps->Release();
    nat->Release();
 
    // COMの終了
    ::CoUninitialize();
}
以下エラー内容です。
error LNK2020: 未解決のトークン (0A000018) CLSID_UPnPNAT
error LNK2020: 未解決のトークン (0A000019) IID_IUPnPNAT
error LNK2001: 外部シンボル "IID_IUPnPNAT" は未解決です。
error LNK2001: 外部シンボル "CLSID_UPnPNAT" は未解決です。
fatal error LNK1120: 外部参照 4 が未解決です。

リンクのエラーは出ていないので、uuid.libは読み込めているとは思うのですが…

YuO
記事: 947
登録日時: 14年前
住所: 東京都世田谷区

Re: VC++2010 UPnPポート開放

#4

投稿記事 by YuO » 10年前

うーん……。

こちらで試したところ,少なくともリンカのエラーに関して,最小限のコード

コード:

#include <Windows.h>
#include <natupnp.h>

#pragma comment(lib, "ole32")

int main()
{
	::CoInitialize(nullptr);

	::IUPnPNAT * upnpNat;
	return ::CoCreateInstance(CLSID_UPnPNAT, nullptr, CLSCTX_ALL, IID_IUPnPNAT, (void **)&upnpNat);
}
に対して,エラーは起きないのですが……。
オフトピック
[(プロジェクト名) プロパティページ] - [構成プロパティ] - [リンカー] - [入力] - [追加の依存ファイル]を空 ([親またはプロジェクトの既定値から継承]チェックボックスをチェックしていない状態) で普通にビルドできるんですよね。
CoInitializeとCoCreateInstanceのためにole32.libは追加でリンクしていますが。
実行しても,S_OKが返ってきていますし……。
あと,コードを見ると初回の物はC++ですが2回目の物はC++/CLIのようです。
どちらの言語を使っているのでしょうか。

Aqris

Re: VC++2010 UPnPポート開放

#5

投稿記事 by Aqris » 10年前

YuO さん、返信有難うございます。

>>コードを見ると初回の物はC++ですが2回目の物はC++/CLIのようです。
初回のコードは貼り間違いでした。
実際に実行したコードは2回目の方で、環境はVisual Studio2010のC++/CLIです。
大変失礼しました。

コードを減らして実行してみても変わらずでした。
[追加の依存ファイル]も空の状態です。
念の為、全コードを貼っておきます。

コード:

#pragma once

#include <windows.h>
#include <Natupnp.h>
#include <objbase.h>
#include <oleauto.h>

#pragma comment(lib,"ole32.lib")
#pragma comment(lib,"oleaut32.lib")
#pragma comment(lib,"uuid.lib")


namespace upnptest {

	using namespace System;
	using namespace System::ComponentModel;
	using namespace System::Collections;
	using namespace System::Windows::Forms;
	using namespace System::Data;
	using namespace System::Drawing;

	/// <summary>
	/// Form1 の概要
	/// </summary>
	public ref class Form1 : public System::Windows::Forms::Form
	{
	public:
		Form1(void)
		{
			InitializeComponent();
			//
			//TODO: ここにコンストラクター コードを追加します
			//
		}

	protected:
		/// <summary>
		/// 使用中のリソースをすべてクリーンアップします。
		/// </summary>
		~Form1()
		{
			if (components)
			{
				delete components;
			}
		}
	private: System::Windows::Forms::Button^  button1;
	protected: 

	private:
		/// <summary>
		/// 必要なデザイナー変数です。
		/// </summary>
		System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
		/// <summary>
		/// デザイナー サポートに必要なメソッドです。このメソッドの内容を
		/// コード エディターで変更しないでください。
		/// </summary>
		void InitializeComponent(void)
		{
			this->button1 = (gcnew System::Windows::Forms::Button());
			this->SuspendLayout();
			// 
			// button1
			// 
			this->button1->Location = System::Drawing::Point(12, 3);
			this->button1->Name = L"button1";
			this->button1->Size = System::Drawing::Size(75, 23);
			this->button1->TabIndex = 0;
			this->button1->Text = L"button1";
			this->button1->UseVisualStyleBackColor = true;
			// 
			// Form1
			// 
			this->AutoScaleDimensions = System::Drawing::SizeF(6, 12);
			this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
			this->ClientSize = System::Drawing::Size(284, 261);
			this->Controls->Add(this->button1);
			this->Name = L"Form1";
			this->Text = L"Form1";
			this->ResumeLayout(false);
		}
#pragma endregion

		System::Void test()
		{
			// まずCOMの初期化
			::CoInitialize( NULL );

			// インスタンス取得
			IUPnPNAT *nat;
			::CoCreateInstance( CLSID_UPnPNAT, NULL, CLSCTX_ALL, IID_IUPnPNAT, (void **)&nat );
		}
	};
}


以下エラー
error LNK2020: 未解決のトークン (0A000011) CLSID_UPnPNAT
error LNK2020: 未解決のトークン (0A000012) IID_IUPnPNAT
error LNK2001: 外部シンボル "IID_IUPnPNAT" は未解決です。
error LNK2001: 外部シンボル "CLSID_UPnPNAT" は未解決です。
fatal error LNK1120: 外部参照 4 が未解決です。

C++/CLIでは何か違うのでしょうか…

sleep

Re: VC++2010 UPnPポート開放

#6

投稿記事 by sleep » 10年前

横から失礼いたします。

以下をコード上部付近にコピペしてビルドできるか試してみていただけますか?

コード:

#import "libid:1C565858-F302-471E-B409-F180AA4ABEC6"
あと、
「ファイル名を指定して実行」か、もしくは「コマンドプロンプト」から
regedit
と打ち込んで実行し、レジストリエディタを開いて見てください。そして、
HKEY_CLASSES_ROOT
を選択し、マウスの右クリック → 検索 を選択し
{AE1E00AA-3FD5-403C-8A27-2BBDC30CD0E1}
と入力した上で検索を実行してみてください。
上記操作で検索がひっかかるかどうか試してみていただけますか?

以上、2点ご確認いただけますでしょうか。
よろしくお願いします。

sleep

Re: VC++2010 UPnPポート開放

#7

投稿記事 by sleep » 10年前

もう1つ、
もしレジストリエディタで見つかった場合、最悪以下でビルドが通るかどうか試してみてください。

コード:

#include <windows.h>
#include <Natupnp.h>
#include <objbase.h>
#include <oleauto.h>
 
#pragma comment(lib,"ole32.lib")
#pragma comment(lib,"oleaut32.lib")
#pragma comment(lib,"uuid.lib")
 
System::Void test()
{
    // まずCOMの初期化
    ::CoInitialize( NULL );

    IID upnpnat_clsid = { 0xAE1E00AA, 0x3FD5, 0x403C, { 0x8A, 0x27, 0x2B, 0xBD, 0xC3, 0x0C, 0xD0, 0xE1 } };
    IID iupnpnat_iid  = { 0xb171c812, 0xcc76, 0x485a, { 0x94, 0xd8, 0xb6, 0xb3, 0xa2, 0x79, 0x4e, 0x99 } };

/* 
  //もし、VS2010で上記の initializer list が使用できなかった場合、
  //上記2行をコメントアウトし、以下のコメントアウト(/* */)を外してビルドしてみてください。
  IID upnpnat_clsid;
  upnpnat_clsid.Data1 = 0xAE1E00AA;
  upnpnat_clsid.Data2 = 0x3FD5;
  upnpnat_clsid.Data3 = 0x403C;
  upnpnat_clsid.Data4[0] = 0x8A;
  upnpnat_clsid.Data4[1] = 0x27;
  upnpnat_clsid.Data4[2] = 0x2B;
  upnpnat_clsid.Data4[3] = 0xBD;
  upnpnat_clsid.Data4[4] = 0xC3;
  upnpnat_clsid.Data4[5] = 0x0C;
  upnpnat_clsid.Data4[6] = 0xD0;
  upnpnat_clsid.Data4[7] = 0xE1;

  IID iupnpnat_iid;
  iupnpnat_iid.Data1 = 0xb171c812;
  iupnpnat_iid.Data2 = 0xcc76;
  iupnpnat_iid.Data3 = 0x485a;
  iupnpnat_iid.Data4[0] = 0x94;
  iupnpnat_iid.Data4[1] = 0xd8;
  iupnpnat_iid.Data4[2] = 0xb6;
  iupnpnat_iid.Data4[3] = 0xb3;
  iupnpnat_iid.Data4[4] = 0xa2;
  iupnpnat_iid.Data4[5] = 0x79;
  iupnpnat_iid.Data4[6] = 0x4e;
  iupnpnat_iid.Data4[7] = 0x99;
*/
 
    // インスタンス取得
    IUPnPNAT *nat;
    ::CoCreateInstance( upnpnat_clsid, NULL, CLSCTX_ALL, iupnpnat_iid, (void **)&nat );
 
    // ポートマッピングのリスト取得
    IStaticPortMappingCollection *maps = NULL;
    nat->get_StaticPortMappingCollection( &maps );
 
    // アドレスと名前を登録できる形式に変更
    char *ip = "192.168.11.2"; //<- 自分のIPアドレス
    WCHAR localIPWideString[ 16 ];
    MultiByteToWideChar( CP_ACP, 0, ip, -1, localIPWideString, 16 );
    BSTR localIPBstr = SysAllocString( localIPWideString );
    BSTR proto = SysAllocString( L"TCP" ); //<- TCP/IPで登録する
    BSTR description = SysAllocString( L"TOOL" ); //<- ここはポートマッピングに登録する名前
 
    // ポートマッピング
    int port = 57630; //<- 開放するポート番号
    IStaticPortMapping *map;
    maps->Add( port, proto, port, localIPBstr, VARIANT_TRUE, description, &map );
 
    // BSTR の解放
    SysFreeString( description );
    SysFreeString( proto );
    SysFreeString( localIPBstr );
 
    // オブジェクト解放
    map->Release();
    maps->Release();
    nat->Release();
 
    // COMの終了
    ::CoUninitialize();
}

sleep

Re: VC++2010 UPnPポート開放

#8

投稿記事 by sleep » 10年前

sleep さんが書きました:

コード:

  //上記2行をコメントアウトし、以下のコメントアウト(/* */)を外してビルドしてみてください。
上記の */ が 外枠のコメントアウトを外してしまうと思うので
内容が伝わったらコメント自体を削除してしまうか、もしくは
(/* */) は不要なので以下のようにコメントから削除してしまってください。

コード:

  //上記2行をコメントアウトし、以下のコメントアウトを外してビルドしてみてください。

sleep

Re: VC++2010 UPnPポート開放

#9

投稿記事 by sleep » 10年前

ついでで、もう1つ載せておきます。
DEFINE_GUID を使用して "LNK2001 外部シンボルは未解決です" のエラーを回避する方法

元のコードの以下の位置へ initguid.h を追記してビルドも試してみてください。

コード:

#include <windows.h>

#include <initguid.h>

#include <Natupnp.h>
#include <objbase.h>
#include <oleauto.h>

Aqris

Re: VC++2010 UPnPポート開放

#10

投稿記事 by Aqris » 10年前

sleepさん、返信有難うございます。

>>以下をコード上部付近にコピペしてビルドできるか試してみていただけますか?

コード:

#import "libid:1C565858-F302-471E-B409-F180AA4ABEC6"
 エラーによりビルドできませんでした。以下エラーです。
 error C2812: #import は /clr:pure および /clr:safe でサポートされていません


>>{AE1E00AA-3FD5-403C-8A27-2BBDC30CD0E1}
>>上記操作で検索がひっかかるかどうか試してみていただけますか?
 見つかりました。以下が見つかったものです。
 Home Networking NAT Traversal via UPnP Configuration Manager


>>もしレジストリエディタで見つかった場合、最悪以下でビルドが通るかどうか試してみてください。

コード:

 IID upnpnat_clsid = { 0xAE1E00AA, 0x3FD5, 0x403C, { 0x8A, 0x27, 0x2B, 0xBD, 0xC3, 0x0C, 0xD0, 0xE1 } };
 IID iupnpnat_iid  = { 0xb171c812, 0xcc76, 0x485a, { 0x94, 0xd8, 0xb6, 0xb3, 0xa2, 0x79, 0x4e, 0x99 } };
 上の2行を含むコードでビルドできました!ありがとうございます!


>>元のコードの以下の位置へ initguid.h を追記してビルドも試してみてください。
 こちらはエラー変わらずでビルドできませんでした。


おかげさまでコンパイルを行うことができました。ありがとうございます。
しかし…実行してみると

コード:

maps->Add( port, proto, port, localIPBstr,VARIANT_TRUE, description, &map);
の行で
 'System.NullReferenceException' のハンドルされていない例外が upnptest.exe で発生しました。
 追加情報: オブジェクト参照がオブジェクト インスタンスに設定されていません。
という例外が発生します。

その時の変数の値は以下のとおりです。
&map 0x005FEC40
description 0x009638F4 "TOOL"
localIPBstr  0x009638BC "192.168.2.102"
map 0x0089A728
maps <未定義の値>
port 57630
proto 0x009633E4 "TCP"
this 0x02404b04

IPアドレスは自身のIPアドレスを使用し、ルータのUPnPも許可設定です。またファイアウォール・セキュリティソフト共にoffの状態です。
他の方を見ているとこのプログラムで問題無く動いているようですが、私の場合一体何が原因なのでしょうか。

sleep

Re: VC++2010 UPnPポート開放

#11

投稿記事 by sleep » 10年前

Aqrisさん、ご確認ありがとうございます。
大体の状況はわかりました。
Aqris さんが書きました: >>以下をコード上部付近にコピペしてビルドできるか試してみていただけますか?

コード:

#import "libid:1C565858-F302-471E-B409-F180AA4ABEC6"
 エラーによりビルドできませんでした。以下エラーです。
 error C2812: #import は /clr:pure および /clr:safe でサポートされていません
プロジェクトのプロパティページで
[構成プロパティ] → 「全般」→「共通言語ランタイムサポート」が、
「純粋 MSIL 共通言語ランタイム サポート (/clr:pure)」の設定であることはわかりました。
しかし、それは特に問題ではありません。

Aqris さんが書きました: >>{AE1E00AA-3FD5-403C-8A27-2BBDC30CD0E1}
>>上記操作で検索がひっかかるかどうか試してみていただけますか?
 見つかりました。以下が見つかったものです。
 Home Networking NAT Traversal via UPnP Configuration Manager
当たり前と言えば当たり前ですが、UPnPNATの登録が存在しないわけではなさそうです。
ついでに以下のGUIDもレジストリエディタで検索していただけますか?

コード:

{B171C812-CC76-485A-94D8-B6B3A2794E99}
Aqris さんが書きました: >>もしレジストリエディタで見つかった場合、最悪以下でビルドが通るかどうか試してみてください。

コード:

 IID upnpnat_clsid = { 0xAE1E00AA, 0x3FD5, 0x403C, { 0x8A, 0x27, 0x2B, 0xBD, 0xC3, 0x0C, 0xD0, 0xE1 } };
 IID iupnpnat_iid  = { 0xb171c812, 0xcc76, 0x485a, { 0x94, 0xd8, 0xb6, 0xb3, 0xa2, 0x79, 0x4e, 0x99 } };
 上の2行を含むコードでビルドできました!ありがとうございます!
Aqris さんが書きました: >>元のコードの以下の位置へ initguid.h を追記してビルドも試してみてください。
 こちらはエラー変わらずでビルドできませんでした。
原因は特定できませんが、とりあえずGUIDの初期化ができていないようですね。
一度、initguid.h を全ての#includeより上部に宣言してビルドしてみるのを試すのも良いかもしれません。

Aqris さんが書きました: しかし…実行してみると

コード:

maps->Add( port, proto, port, localIPBstr,VARIANT_TRUE, description, &map);
の行で
 'System.NullReferenceException' のハンドルされていない例外が upnptest.exe で発生しました。
 追加情報: オブジェクト参照がオブジェクト インスタンスに設定されていません。
という例外が発生します。
上記で再度レジストリエディタの検索をお願いしてます。( {B171C812-CC76-485A-94D8-B6B3A2794E99} )
そのGUIDがレジストリに見つからなければ maps->Add は失敗し、NULLを返してくるのは分かりますが
もし、GUIDが存在しているにも関わらず失敗してNULLを返してきているとしたら、
Microsoftに直接問い合わせるか、開発環境を交換した方が良いと思います。

状況を説明すると、直接指定で失敗するという状況は、結構お手上げな状態です。
ダンプを取ってWinDbgを使用して解析しないと原因が特定できないレベルなので、環境固有に近く、少なくとも一般的な領域ではないですね。
Microsoftがやるような作業です。

Aqris さんが書きました: 他の方を見ているとこのプログラムで問題無く動いているようですが、私の場合一体何が原因なのでしょうか。
ありえるとしたら、プロジェクトの作成過程に違いがある可能性はあります。
その他の方に Aqrisさんの環境で自分の環境と同じようにプロジェクトを作成していただき
現状つまづいているUPnPNATのコード部分だけのテストコードを作成して実行してみると良いです。
それで動作するのであればプロジェクトの作成のみの違いなので、プロジェクトのプロパティを比較することで、その違いが分かると思います。

sleep

Re: VC++2010 UPnPポート開放

#12

投稿記事 by sleep » 10年前

あと、ビルドが成功しているコードで以下の場所に
printf("error: %d\n", GetLastError());
を追加し、どんな値が返されてきているか確認をお願いしてもよろしいでしょうか。

コード:

    // インスタンス取得
    IUPnPNAT *nat;
    ::CoCreateInstance( upnpnat_clsid, NULL, CLSCTX_ALL, iupnpnat_iid, (void **)&nat );
    printf("error: %d\n", GetLastError());

sleep

Re: VC++2010 UPnPポート開放

#13

投稿記事 by sleep » 10年前

少し語弊があるので訂正しておきます。
sleep さんが書きました:
Aqris さんが書きました: >>以下をコード上部付近にコピペしてビルドできるか試してみていただけますか?

コード:

#import "libid:1C565858-F302-471E-B409-F180AA4ABEC6"
 エラーによりビルドできませんでした。以下エラーです。
 error C2812: #import は /clr:pure および /clr:safe でサポートされていません
プロジェクトのプロパティページで
[構成プロパティ] → 「全般」→「共通言語ランタイムサポート」が、
「純粋 MSIL 共通言語ランタイム サポート (/clr:pure)」の設定であることはわかりました。
しかし、それは特に問題ではありません。
確かに直接指定による maps->add が失敗する原因とはなり得ませんが、
今まで出ていた LNK2001やLNK2020の原因にはなります。
「純粋 MSIL 共通言語ランタイム サポート (/clr:pure)」をしていた場合
GUIDの初期化は失敗します。
GUIDの初期化に関しては、
[構成プロパティ] → 「全般」→「共通言語ランタイムサポート」を
「共通言語ランタイム サポート (/clr)」
に指定し直すことで解決することができます。

sleep

Re: VC++2010 UPnPポート開放

#14

投稿記事 by sleep » 10年前

MSDNを確認してみたんですが・・・
VS2010は initializer list に未対応の様子ですが、初期化は成功してましたか?
Support For C++11 Features (Modern C++)
Aqris さんが書きました: >>もしレジストリエディタで見つかった場合、最悪以下でビルドが通るかどうか試してみてください。

コード:

 IID upnpnat_clsid = { 0xAE1E00AA, 0x3FD5, 0x403C, { 0x8A, 0x27, 0x2B, 0xBD, 0xC3, 0x0C, 0xD0, 0xE1 } };
 IID iupnpnat_iid  = { 0xb171c812, 0xcc76, 0x485a, { 0x94, 0xd8, 0xb6, 0xb3, 0xa2, 0x79, 0x4e, 0x99 } };
 上の2行を含むコードでビルドできました!ありがとうございます!
逆に初期化が失敗していただけであれば、以下に変更すればビルドだけでなく実行の方も成功するかもしれません。
sleep さんが書きました:

コード:

    IID upnpnat_clsid;
    upnpnat_clsid.Data1 = 0xAE1E00AA;
    upnpnat_clsid.Data2 = 0x3FD5;
    upnpnat_clsid.Data3 = 0x403C;
    upnpnat_clsid.Data4[0] = 0x8A;
    upnpnat_clsid.Data4[1] = 0x27;
    upnpnat_clsid.Data4[2] = 0x2B;
    upnpnat_clsid.Data4[3] = 0xBD;
    upnpnat_clsid.Data4[4] = 0xC3;
    upnpnat_clsid.Data4[5] = 0x0C;
    upnpnat_clsid.Data4[6] = 0xD0;
    upnpnat_clsid.Data4[7] = 0xE1;

    IID iupnpnat_iid;
    iupnpnat_iid.Data1 = 0xb171c812;
    iupnpnat_iid.Data2 = 0xcc76;
    iupnpnat_iid.Data3 = 0x485a;
    iupnpnat_iid.Data4[0] = 0x94;
    iupnpnat_iid.Data4[1] = 0xd8;
    iupnpnat_iid.Data4[2] = 0xb6;
    iupnpnat_iid.Data4[3] = 0xb3;
    iupnpnat_iid.Data4[4] = 0xa2;
    iupnpnat_iid.Data4[5] = 0x79;
    iupnpnat_iid.Data4[6] = 0x4e;
    iupnpnat_iid.Data4[7] = 0x99;
 
    // インスタンス取得
    IUPnPNAT *nat;
    ::CoCreateInstance( upnpnat_clsid, NULL, CLSCTX_ALL, iupnpnat_iid, (void **)&nat );
もし、上記の変更で正常動作が確認できたとしたら、
GUIDさえ引っ張ってこれれば動作することの裏が取れるので
そうなると、元のコードのままで以下の設定を変更してあげるだけで解決となりそうです。
sleep さんが書きました: [構成プロパティ] → 「全般」→「共通言語ランタイムサポート」を
「共通言語ランタイム サポート (/clr)」
に指定し直すことで解決することができます。

Aqris
記事: 4
登録日時: 10年前

Re: VC++2010 UPnPポート開放

#15

投稿記事 by Aqris » 10年前

sleepさん、何度も返信有難うございます。大変勉強になります。

>>ついでに以下のGUIDもレジストリエディタで検索していただけますか?

コード:

{B171C812-CC76-485A-94D8-B6B3A2794E99}
 見つかりました。値のデータは以下です。
 IUPnPNAT


>>原因は特定できませんが、とりあえずGUIDの初期化ができていないようですね。
>>一度、initguid.h を全ての#includeより上部に宣言してビルドしてみるのを試すのも良いかもしれません。

 initguid.h を全ての#includeより上部に宣言し試してみましたが、変わらず未解決エラーがでてビルドできませんでした。


>>ありえるとしたら、プロジェクトの作成過程に違いがある可能性はあります。
>>その他の方に Aqrisさんの環境で自分の環境と同じようにプロジェクトを作成していただき
>>現状つまづいているUPnPNATのコード部分だけのテストコードを作成して実行してみると良いです。

 現在の環境のままプロジェクトを作成し直し、最低限の内容で試みてみましたが結果変わらずでした。


>>あと、ビルドが成功しているコードで以下の場所に
>>printf("error: %d\n", GetLastError());
>>を追加し、どんな値が返されてきているか確認をお願いしてもよろしいでしょうか。

 出力結果は error: 127 でした。


>>VS2010は initializer list に未対応の様子ですが、初期化は成功してましたか?

 初期化の成功時はメッセージ出ましたっけ?おそらく失敗のメッセージが表示されていないので初期化には成功していると思うのですが…
 試しに教えていただいた以下のコードと「共通言語ランタイム サポート (/clr)」設定の両方を試してみました。

コード:

    IID upnpnat_clsid;
    upnpnat_clsid.Data1 = 0xAE1E00AA;
    upnpnat_clsid.Data2 = 0x3FD5;
    upnpnat_clsid.Data3 = 0x403C;
    upnpnat_clsid.Data4[0] = 0x8A;
    upnpnat_clsid.Data4[1] = 0x27;
    upnpnat_clsid.Data4[2] = 0x2B;
    upnpnat_clsid.Data4[3] = 0xBD;
    upnpnat_clsid.Data4[4] = 0xC3;
    upnpnat_clsid.Data4[5] = 0x0C;
    upnpnat_clsid.Data4[6] = 0xD0;
    upnpnat_clsid.Data4[7] = 0xE1;
 
    IID iupnpnat_iid;
    iupnpnat_iid.Data1 = 0xb171c812;
    iupnpnat_iid.Data2 = 0xcc76;
    iupnpnat_iid.Data3 = 0x485a;
    iupnpnat_iid.Data4[0] = 0x94;
    iupnpnat_iid.Data4[1] = 0xd8;
    iupnpnat_iid.Data4[2] = 0xb6;
    iupnpnat_iid.Data4[3] = 0xb3;
    iupnpnat_iid.Data4[4] = 0xa2;
    iupnpnat_iid.Data4[5] = 0x79;
    iupnpnat_iid.Data4[6] = 0x4e;
    iupnpnat_iid.Data4[7] = 0x99;
 
    // インスタンス取得
    IUPnPNAT *nat;
    ::CoCreateInstance( upnpnat_clsid, NULL, CLSCTX_ALL, iupnpnat_iid, (void **)&nat );
結果、実行中に変わらず以下の例外が表示されプログラムが停止しました。
 'System.NullReferenceException' のハンドルされていない例外が upnptest.exe で発生しました。
 追加情報: オブジェクト参照がオブジェクト インスタンスに設定されていません。

おそらく私の環境が悪いのかなということはなんとなく理解できたのですが、ここで一つ質問です。
これまでのポート開放プログラムが正常にビルド・実行され、
仮にルータの設定ミスやファイアウォールなどでポートの開放に失敗した場合のエラー内容(例外?)はどのようなものなのでしょうか。

Aqris
記事: 4
登録日時: 10年前

Re: VC++2010 UPnPポート開放

#16

投稿記事 by Aqris » 10年前

別のコンピュータ(VisualStudio2010, C++/CLI)で以下のコードをプログラムをビルドしてみました。

コード:

#include <windows.h>
#include <Natupnp.h>
#include <objbase.h>
#include <oleauto.h>
 
#pragma comment(lib,"ole32.lib")
#pragma comment(lib,"oleaut32.lib")
 
System::Void test(){
    // まずCOMの初期化
    ::CoInitialize( NULL );
 
    // インスタンス取得
    IUPnPNAT *nat;
    ::CoCreateInstance( CLSID_UPnPNAT, NULL, CLSCTX_ALL, IID_IUPnPNAT, (void **)&nat );
 
    // ポートマッピングのリスト取得
    IStaticPortMappingCollection *maps = NULL;
    nat->get_StaticPortMappingCollection( &maps );
 
    // アドレスと名前を登録できる形式に変更
    char *ip = "192.168.11.2"; //<- 自分のIPアドレス
    WCHAR localIPWideString[ 16 ];
    MultiByteToWideChar( CP_ACP, 0, ip, -1, localIPWideString, 16 );
    BSTR localIPBstr = SysAllocString( localIPWideString );
    BSTR proto = SysAllocString( L"TCP" ); //<- TCP/IPで登録する
    BSTR description = SysAllocString( L"TOOL" ); //<- ここはポートマッピングに登録する名前
 
    // ポートマッピング
    int port = 57630; //<- 開放するポート番号
    IStaticPortMapping *map;
    maps->Add( port, proto, port, localIPBstr, VARIANT_TRUE, description, &map );
 
    // BSTR の解放
    SysFreeString( description );
    SysFreeString( proto );
    SysFreeString( localIPBstr );
 
    // オブジェクト解放
    map->Release();
    maps->Release();
    nat->Release();
 
    // COMの終了
    ::CoUninitialize();
}
するとやはりこれまでと同様の未解決エラーが出ました。以下エラーです。
  error LNK2020: 未解決のトークン (0A000018) CLSID_UPnPNAT
  error LNK2020: 未解決のトークン (0A000019) IID_IUPnPNAT
  error LNK2001: 外部シンボル "IID_IUPnPNAT" は未解決です。
  error LNK2001: 外部シンボル "CLSID_UPnPNAT" は未解決です。
  error LNK1120: 外部参照 4 が未解決です。

しかし、「共通言語ランタイム サポート (/clr)」に変更することによってビルドは通るようにはなりました。
ビルドしたプログラムを実行してみると以前と同様の32行目の
  maps->Add( port, proto, port, localIPBstr, VARIANT_TRUE, description, &map );
この部分で以下の例外が発生し、プログラムが停止しました。以下エラーです。
  'System.NullReferenceException' のハンドルされていない例外が upnptest2.exe で発生しました。
  追加情報: オブジェクト参照がオブジェクト インスタンスに設定されていません。

この例外がプログラミング環境によるものなのか、それともルータのUPnP設定やファイアウォールの設定等が上手くできていないからによるものなのかが分からず困っています。

sleep

Re: VC++2010 UPnPポート開放

#17

投稿記事 by sleep » 10年前

Aqrisさん、度々ご確認ありがとうございます。
Aqris さんが書きました: >>ありえるとしたら、プロジェクトの作成過程に違いがある可能性はあります。
>>その他の方に Aqrisさんの環境で自分の環境と同じようにプロジェクトを作成していただき
>>現状つまづいているUPnPNATのコード部分だけのテストコードを作成して実行してみると良いです。

 現在の環境のままプロジェクトを作成し直し、最低限の内容で試みてみましたが結果変わらずでした。
その他の方と同じ方法でプロジェクトを作成して、実行に失敗するということになると
単純にコーディングやIDEの設定ではどうにもならなそうですね。

Aqris さんが書きました: 試しに教えていただいた以下のコードと「共通言語ランタイム サポート (/clr)」設定の両方を試してみました。

結果、実行中に変わらず以下の例外が表示されプログラムが停止しました。
 'System.NullReferenceException' のハンドルされていない例外が upnptest.exe で発生しました。
 追加情報: オブジェクト参照がオブジェクト インスタンスに設定されていません。
(/clr の設定へ変更することで) 元のコードはビルドが通るようになったのですよね?
元のコードに以下のように 戻り値を取得できるようにして
・ ::CoCreateInstance
・ nat->get_StaticPortMappingCollection
の戻り値を確認していただけますか?

コード:

	HRESULT ret;

	// インスタンス取得
	IUPnPNAT *nat;
	ret = ::CoCreateInstance(CLSID_UPnPNAT, NULL, CLSCTX_ALL, IID_IUPnPNAT, (void **)&nat);
	printf("HRESULT: %d  ::CoCreateInstance\n", ret);

	// ポートマッピングのリスト取得
	IStaticPortMappingCollection *maps = NULL;
	ret = nat->get_StaticPortMappingCollection(&maps);
	printf("HRESULT: %d  nat->get_StaticPortMappingCollection(&maps)\n", ret);
もし、::CoCreateInstanceは成功(S_OK)を返してきていて、
nat->get_StaticPortMappingCollectionが失敗している場合は
話が変わってきます。(以下の質問への回答へ続く)

Aqris さんが書きました: おそらく私の環境が悪いのかなということはなんとなく理解できたのですが、ここで一つ質問です。
これまでのポート開放プログラムが正常にビルド・実行され、
仮にルータの設定ミスやファイアウォールなどでポートの開放に失敗した場合のエラー内容(例外?)はどのようなものなのでしょうか。
google で get_StaticPortMappingCollection と入力して検索すると
ポート解放用ソフトを使用してポート解放しようとして get_StaticPortMappingCollection がエラーを返す例がいくつも出てくると思います。
その中に該当するものがあるかどうか調べてみてください。

ちなみに私にはこの手のケースは経験がないので、おそらく私より
引っ越しで住まいを変えつつオンラインゲームなどでポート解放を必要とする状況をより多く経験されている方達に伺った方が良いアドバイスがいただけるのではないかと思います。
(IDEやコーディングうんぬんではなくなりますね)


私がよく分からないのは、その他の方というのは
同じ場所でコーディングされているわけではないのでしょうか?
同じ場所で片方動いて、もう片方動かない、ということを前提で話をしてきましたが
場所が違うとなると状況は変わってくるので、Aqrisさんが使用しているPCの問題とは限らなくなりますね。
(むしろ、その線は薄れます)

sleep

Re: VC++2010 UPnPポート開放

#18

投稿記事 by sleep » 10年前

Aqris さんが書きました: この例外がプログラミング環境によるものなのか、それともルータのUPnP設定やファイアウォールの設定等が上手くできていないからによるものなのかが分からず困っています。
以下のように、場合によっては
セキュリティソフトやファイアウォールを無効にしてあっても
同じ環境でも片方のPCはポート解放に成功し、もう片方のPCはポート解放に失敗する
といった例もあるようです。
Windows7 64bitのポート開放でつまづいています。XPでは問題なくできたのですが


このへんの話になってくると、メーカー毎の外部デバイスの状態が影響してくるので
もう症例が多すぎてどれに該当するのだか私にはさっぱりですね。

Aqris
記事: 4
登録日時: 10年前

Re: VC++2010 UPnPポート開放

#19

投稿記事 by Aqris » 10年前

sleepさん、何度もありがとうございます。

>>元のコードに以下のように 戻り値を取得できるようにして
>>・ ::CoCreateInstance
>>・ nat->get_StaticPortMappingCollection
>>の戻り値を確認していただけますか?

 出力結果は以下のとおりでした。
 HRESULT: 0 ::CoCreateInstance
 HRESULT: 0 nat->get_StaticPortMappingCollection(&maps)


>>google で get_StaticPortMappingCollection と入力して検索すると
>>ポート解放用ソフトを使用してポート解放しようとして >>get_StaticPortMappingCollection がエラーを返す例がいくつも出てくると思います。
>>その中に該当するものがあるかどうか調べてみてください。

 今までの段階でそこにすらいけていないということはなんとなく分かりました。ありがとうございます。

 別のコンピュータでも駄目とはどういうことなのでしょうかね…
 とにかくどんな方法でもポート開放プログラムが作成できれば良いのですが…

sleep

Re: VC++2010 UPnPポート開放

#20

投稿記事 by sleep » 10年前

Aqris さんが書きました: >>元のコードに以下のように 戻り値を取得できるようにして
>>・ ::CoCreateInstance
>>・ nat->get_StaticPortMappingCollection
>>の戻り値を確認していただけますか?

 出力結果は以下のとおりでした。
 HRESULT: 0 ::CoCreateInstance
 HRESULT: 0 nat->get_StaticPortMappingCollection(&maps)
この方の症例と似てますね。
res の値が S_OK になっているにもかかわらず maps の値が NULL になっているため maps->Add( で例外が出ている
ただ、解決には至っていない様です。

sleep

Re: VC++2010 UPnPポート開放

#21

投稿記事 by sleep » 10年前

Aqris さんが書きました:  別のコンピュータでも駄目とはどういうことなのでしょうかね…
 とにかくどんな方法でもポート開放プログラムが作成できれば良いのですが…
UPnP自体は、ネットに繋がった家電製品をリモートで操作できるようにするプロトコルです。
現状の状態のままプログラムで解決するという話になると、
少なくとも正規の手法ではUPnPと同等のプロトコルをルータが利用できないと他の方法は取れないと思います。


現状でできるとすれば
有力候補は、ルータのメーカーへの問い合わせをしてみる、ではないでしょうか。
ルータの型番でのUPnPへの対応状況やおそらくPCの設定も含めて状況確認をしてくださると思います。

また、ポート解放専門で質問を扱っているサイトもあるようなので
そちらで詳細に状況を説明してみると、Aqrisさんの環境での解決策をいただけるかもしれないですね。


とりあえず、私で助力できそうなのはこの辺ぐらいまでですかね。

sleep

Re: VC++2010 UPnPポート開放

#22

投稿記事 by sleep » 10年前

sleep さんが書きました: この方の症例と似てますね。
res の値が S_OK になっているにもかかわらず maps の値が NULL になっているため maps->Add( で例外が出ている
ただ、解決には至っていない様です。
あ・・・、これレスは上についていってるんですね。失礼しました。
この方達は以下のアドバイスで解決されていたようですね。
res の値が S_OK になっているにもかかわらず
maps の値が NULL になっているため maps->Add( で例外が出ていると思います

この場合、使用しているPCからルーターへのポートマッピングが
うまく機能していないのが原因と考えられます

XPで説明しますと、
マイネットワークから左側にあるネットワークタスクに
「ネットワークに接続しているUPnPデバイスの・・・」
で一度、非表示してもらいファイアーウォールに登録されている
UPnP のポートを閉じてもらいOSの再起動をしてみてください
もしかしたらうまくいくかもしれません

Aqris
記事: 4
登録日時: 10年前

Re: VC++2010 UPnPポート開放

#23

投稿記事 by Aqris » 10年前

sleepさん、返信ありがとうございます。

このプログラムについてはすべて一から見直してやり直してみたいと思います。
別の言語も視野に入れて頑張ってみます。

本トピックに返信をくださったYuOさん、sleepさん、本当にありがとうございました。

閉鎖

“C言語何でも質問掲示板” へ戻る