2012-01-06 142 views
3

我试图在Windows下使用C++ IUPnPNAT接口实现P2P应用程序中的自动端口转发,并且我无法仅仅因为它返回一个NULL对象而使其工作。我不确定我的路由器是否支持UPnP,因为它没有在Web界面中显示任何选项,但是如果我安装eMule或Skype,它们立即打开端口并正常工作,所以问题必须出现在我的代码中或在微软的界面。 eMule和Skype如何做到这一点?一个人可以帮助我吗?在Windows中使用C++进行UPnP端口转发

我贴我的代码:

WORD abre_puerto() { 
WORD puerto, i; 
wchar_t buf_port[12], puerto_s[6]; 
char nombre[256], ip[16]; 
wchar_t ipw[16], descripcion[100]; 
struct addrinfo *resultado = NULL; 
struct addrinfo *ptr = NULL; 
struct addrinfo hints; 
struct sockaddr_in *sockaddr_ipv4; 
IUPnPNAT *nat; 
IStaticPortMappingCollection *coleccion; 
IStaticPortMapping *mapeado; 
BSTR protocolo, ipb; 

swprintf(buf_port, sizeof(buf_port), L"%d", time(NULL)); 
swprintf(puerto_s, sizeof(puerto_s), L"151%c%c", buf_port[wcslen(buf_port) - 2], buf_port[wcslen(buf_port) - 1]); 
puerto = _wtoi(puerto_s); 

if(gethostname(nombre, sizeof(nombre)) == SOCKET_ERROR) {return 0;} 
ZeroMemory(&hints, sizeof(hints)); 
hints.ai_family = AF_INET; 
hints.ai_socktype = SOCK_STREAM; 
hints.ai_protocol = IPPROTO_TCP; 
if(getaddrinfo(nombre, NULL, &hints, &resultado) != 0) {return 0;} 

sockaddr_ipv4 = (struct sockaddr_in *)resultado->ai_addr; 
strcpy(ip, inet_ntoa(sockaddr_ipv4->sin_addr)); 
MultiByteToWideChar(CP_UTF8, 0, ip, -1, ipw, sizeof(ipw)); 
ipb = SysAllocString(ipw); 

nat = NULL; coleccion = NULL; mapeado = NULL; 

if(CoInitialize(NULL) != S_OK) {return 0;} 

if(CoCreateInstance(__uuidof(UPnPNAT), NULL, CLSCTX_ALL, __uuidof(IUPnPNAT), (void **)&nat) != S_OK) {return 0;} 
else if(nat == NULL) {return 0;} 

if(nat->get_StaticPortMappingCollection(&coleccion) != S_OK) {return 0;} 
else if(coleccion == NULL) {return 0;} //fails here: coleccion is allways NULL! 

protocolo = SysAllocString(L"TCP"); 
wcscpy(descripcion, TEXT("PROOF")); 

for(i = 0; i < 250; i++) { 
if(coleccion->get_Item(puerto, protocolo, &mapeado) != S_OK || mapeado == NULL) {break;} 
puerto++; mapeado->Release(); mapeado = NULL; 
} 
if(i == 250) {return 0;} 
if(coleccion->Add(puerto, protocolo, puerto, ipb, TRUE, descripcion, &mapeado) != S_OK) {return 0;} 
else if(mapeado == NULL) {return 0;} 
nat->Release(); coleccion->Release(); mapeado->Release(); 
CoUninitialize(); 

return puerto; 
} 

非常感谢你。

回答

1

道歉,但你没有明确的收到NULL指针的位置。

如果CoCreateInstance返回null,那么它表示相关类未在OLE/COM相关机器上注册 - Skype/eMule的工作是无关紧要的,因为它们可能使用的库是内置到应用程序中,而不是COM对象。

您应该确保COM对象在使用它的系统上注册 - 在注册表中搜索UPnPNAT uuid。

如果你想让应用程序在多个系统上工作,那么你应该考虑直接链接到.lib,而不是使用COM来连接一个对象,该对象可能在系统中注册或不在系统中注册它正在被使用。

+0

它看起来像UPnp框架是在Windows上的可选安装 - 所以它可能只是没有安装在您正在测试的系统上。 – Petesh 2012-01-06 11:10:39

+0

对不起,我忘了在我的问题中提到NULL对象,但是如果您阅读我留在代码中的注释,它将调用IUPnPNAT接口的方法get_StaticPortMappingCollection,NULL对象是“IStaticPortMappingCollection * coleccion “并且该方法不会失败,返回S_OK,它只是全空的对象。 CoCreateInstance返回S_OK并正确填充IUPnPNAT接口。该机器使用Windows 7,并在同一个路由器的同一个盒子中,eMule每次启动时都会运行并打开这些端口(可能使用MiniUPnPc库?)。 – alnog 2012-01-06 12:27:47

+0

最后我使用了MiniUPnPc lib并且工作正常。 – alnog 2012-01-21 18:04:41