2012-01-06 80 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