parent
							
								
									ec9e4c99d8
								
							
						
					
					
						commit
						219e4bc8e9
					
				| 
						 | 
				
			
			@ -17,22 +17,22 @@
 | 
			
		|||
 | 
			
		||||
/*
 | 
			
		||||
1.
 | 
			
		||||
SecureCRT支持设置标签页的标题,命令行参数 /N "tab name"就可以
 | 
			
		||||
SecureCRT支持设置标签页的标题,命令行参数 /N "tab name"就可以
 | 
			
		||||
Example:
 | 
			
		||||
To launch a new Telnet session, displaying the name "Houston, TX" on the tab, use the following:
 | 
			
		||||
/T /N "Houston, TX" /TELNET 192.168.0.6
 | 
			
		||||
 | 
			
		||||
2.
 | 
			
		||||
多次启动的SecureCRT放到一个窗口的不同标签页中,使用参数:  /T
 | 
			
		||||
多次启动的SecureCRT放到一个窗口的不同标签页中,使用参数:  /T
 | 
			
		||||
  SecureCRT.exe /T /N "TP#ssh://192.168.1.3" /SSH2 /L root /PASSWORD 1234 120.26.109.25
 | 
			
		||||
 | 
			
		||||
3.
 | 
			
		||||
telnet客户端的启动:
 | 
			
		||||
telnet客户端的启动:
 | 
			
		||||
  putty.exe telnet://administrator@127.0.0.1:52389
 | 
			
		||||
如果是SecureCRT,则需要
 | 
			
		||||
如果是SecureCRT,则需要
 | 
			
		||||
  SecureCRT.exe /T /N "TP#telnet://192.168.1.3" /SCRIPT X:\path\to\startup.vbs /TELNET 127.0.0.1 52389
 | 
			
		||||
其中,startup.vbs的内容为:
 | 
			
		||||
---------文件开始---------
 | 
			
		||||
其中,startup.vbs的内容为:
 | 
			
		||||
---------文件开始---------
 | 
			
		||||
#$language = "VBScript"
 | 
			
		||||
#$interface = "1.0"
 | 
			
		||||
Sub main
 | 
			
		||||
| 
						 | 
				
			
			@ -41,11 +41,11 @@ Sub main
 | 
			
		|||
  crt.Screen.Send "SESSION-ID" & VbCr
 | 
			
		||||
  crt.Screen.Synchronous = False
 | 
			
		||||
End Sub
 | 
			
		||||
---------文件结束---------
 | 
			
		||||
---------文件结束---------
 | 
			
		||||
 | 
			
		||||
4. 为了让putty的窗口标签显示正常的IP,可以尝试在连接成功后,主动向服务端发送下列命令:
 | 
			
		||||
4. 为了让putty的窗口标签显示正常的IP,可以尝试在连接成功后,主动向服务端发送下列命令:
 | 
			
		||||
    PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@192.168.1.2: \w\a\]$PS1"
 | 
			
		||||
手工测试了,ubuntu服务器可以,不知道是否能够支持所有的Linux。SecureCRT对此表示忽略。
 | 
			
		||||
手工测试了,ubuntu服务器可以,不知道是否能够支持所有的Linux。SecureCRT对此表示忽略。
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
//#define RDP_CLIENT_SYSTEM_BUILTIN
 | 
			
		||||
| 
						 | 
				
			
			@ -208,6 +208,40 @@ bool calc_psw51b(const char* password, std::string& ret) {
 | 
			
		|||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool isDegital(std::string str) {
 | 
			
		||||
	for (int i = 0; i < str.size(); i++) {
 | 
			
		||||
		if (str.at(i) == '-' && str.size() > 1)  // 有可能出现负数
 | 
			
		||||
			continue;
 | 
			
		||||
		if (str.at(i) > '9' || str.at(i) < '0')
 | 
			
		||||
			return false;
 | 
			
		||||
	}
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string strtolower(std::string str) {
 | 
			
		||||
	for (int i = 0; i < str.size(); i++)
 | 
			
		||||
	{
 | 
			
		||||
		str[i] = tolower(str[i]);
 | 
			
		||||
	}
 | 
			
		||||
	return str;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SplitString(const std::string& s, std::vector<std::string>& v, const std::string& c)
 | 
			
		||||
{
 | 
			
		||||
	std::string::size_type pos1, pos2;
 | 
			
		||||
	pos2 = s.find(c);
 | 
			
		||||
	pos1 = 0;
 | 
			
		||||
	while (std::string::npos != pos2)
 | 
			
		||||
	{
 | 
			
		||||
		v.push_back(s.substr(pos1, pos2 - pos1));
 | 
			
		||||
 | 
			
		||||
		pos1 = pos2 + c.size();
 | 
			
		||||
		pos2 = s.find(c, pos1);
 | 
			
		||||
	}
 | 
			
		||||
	if (pos1 != s.length())
 | 
			
		||||
		v.push_back(s.substr(pos1));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TsHttpRpc::TsHttpRpc() {
 | 
			
		||||
    m_stop = false;
 | 
			
		||||
    mg_mgr_init(&m_mg_mgr, nullptr);
 | 
			
		||||
| 
						 | 
				
			
			@ -344,7 +378,7 @@ void TsHttpRpc::_mg_event_handler(struct mg_connection *nc, int ev, void *ev_dat
 | 
			
		|||
        bool b_is_index = false;
 | 
			
		||||
 | 
			
		||||
        if (uri == "/") {
 | 
			
		||||
            ex_wstr page = L"<html lang=\"zh_CN\"><head><meta charset=\"utf-8\"/><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/><title>Teleport助手</title>\n<style type=\"text/css\">\n.box{padding:20px;margin:40px;border:1px solid #78b17c;background-color:#e4ffe5;}\n</style>\n</head><body><div class=\"box\">Teleport助手工作正常!</div></body></html>";
 | 
			
		||||
            ex_wstr page = L"<html lang=\"zh_CN\"><head><meta charset=\"utf-8\"/><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/><title>Teleport助手</title>\n<style type=\"text/css\">\n.box{padding:20px;margin:40px;border:1px solid #78b17c;background-color:#e4ffe5;}\n</style>\n</head><body><div class=\"box\">Teleport助手工作正常!</div></body></html>";
 | 
			
		||||
            ex_wstr2astr(page, ret_buf, EX_CODEPAGE_UTF8);
 | 
			
		||||
 | 
			
		||||
            mg_printf(nc, "HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n%s", ret_buf.size() - 1, &ret_buf[0]);
 | 
			
		||||
| 
						 | 
				
			
			@ -441,7 +475,7 @@ int TsHttpRpc::_parse_request(struct http_message* req, ex_astr& func_cmd, ex_as
 | 
			
		|||
 | 
			
		||||
    ex_astrs strs;
 | 
			
		||||
 | 
			
		||||
    size_t pos_start = 1;	// 跳过第一个字节,一定是 '/'
 | 
			
		||||
    size_t pos_start = 1;	// 跳过第一个字节,一定是 '/'
 | 
			
		||||
 | 
			
		||||
    size_t i = 0;
 | 
			
		||||
    for (i = pos_start; i < req->uri.len; ++i) {
 | 
			
		||||
| 
						 | 
				
			
			@ -451,7 +485,7 @@ int TsHttpRpc::_parse_request(struct http_message* req, ex_astr& func_cmd, ex_as
 | 
			
		|||
                tmp_uri.assign(req->uri.p + pos_start, i - pos_start);
 | 
			
		||||
                strs.push_back(tmp_uri);
 | 
			
		||||
            }
 | 
			
		||||
            pos_start = i + 1;	// 跳过当前找到的分隔符
 | 
			
		||||
            pos_start = i + 1;	// 跳过当前找到的分隔符
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (pos_start < req->uri.len) {
 | 
			
		||||
| 
						 | 
				
			
			@ -485,7 +519,7 @@ int TsHttpRpc::_parse_request(struct http_message* req, ex_astr& func_cmd, ex_as
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    if (func_args.length() > 0) {
 | 
			
		||||
        // 将参数进行 url-decode 解码
 | 
			
		||||
        // 将参数进行 url-decode 解码
 | 
			
		||||
        int len = func_args.length() * 2;
 | 
			
		||||
        ex_chars sztmp;
 | 
			
		||||
        sztmp.resize(len);
 | 
			
		||||
| 
						 | 
				
			
			@ -521,7 +555,7 @@ void TsHttpRpc::_process_js_request(const ex_astr& func_cmd, const ex_astr& func
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void TsHttpRpc::_create_json_ret(ex_astr& buf, int errcode) {
 | 
			
		||||
    // 返回: {"code":123}
 | 
			
		||||
    // 返回: {"code":123}
 | 
			
		||||
 | 
			
		||||
    Json::FastWriter jr_writer;
 | 
			
		||||
    Json::Value jr_root;
 | 
			
		||||
| 
						 | 
				
			
			@ -535,12 +569,64 @@ void TsHttpRpc::_create_json_ret(ex_astr& buf, Json::Value& jr_root) {
 | 
			
		|||
    buf = jr_writer.write(jr_root);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TsHttpRpc::_rpc_func_url_protocol(const ex_astr& args, ex_astr& buf)
 | 
			
		||||
{
 | 
			
		||||
	//处理urlprotocol调用访式
 | 
			
		||||
	// 将参数进行 url-decode 解码
 | 
			
		||||
	std::string func_args = args;
 | 
			
		||||
	if (func_args.length() > 0)
 | 
			
		||||
	{
 | 
			
		||||
		int len = func_args.length() * 2;
 | 
			
		||||
		ex_chars sztmp;
 | 
			
		||||
		sztmp.resize(len);
 | 
			
		||||
		memset(&sztmp[0], 0, len);
 | 
			
		||||
		if (-1 == ts_url_decode(func_args.c_str(), func_args.length(), &sztmp[0], len, 0))
 | 
			
		||||
			return ;
 | 
			
		||||
 | 
			
		||||
		func_args = &sztmp[0];
 | 
			
		||||
	}
 | 
			
		||||
	EXLOGD(("%s\n"), func_args.c_str());
 | 
			
		||||
	//处理传参过来的teleport://{}/,只保留参数部份
 | 
			
		||||
	std::string urlproto_appname = TP_URLPROTO_APP_NAME;
 | 
			
		||||
	urlproto_appname += "://{";
 | 
			
		||||
	func_args.erase(0, urlproto_appname.length());//去除第一个URLPROTO_APP_NAME以及://字符
 | 
			
		||||
	int pos = func_args.length() - 1;
 | 
			
		||||
	if (func_args.substr(pos, 1) == "/")
 | 
			
		||||
		func_args.erase(pos - 1, 2);//去除最后一个}/字符
 | 
			
		||||
	else
 | 
			
		||||
		func_args.erase(pos, 1);
 | 
			
		||||
 | 
			
		||||
	//由于命令行、ie浏览器参数传递时会把原来json结构中的"号去掉,需要重新格式化参数为json格式
 | 
			
		||||
	if (func_args.find("\"", 0) == std::string::npos) {
 | 
			
		||||
		std::vector<std::string> strv;
 | 
			
		||||
		SplitString(func_args, strv, ",");
 | 
			
		||||
		func_args = "";
 | 
			
		||||
		for (std::vector<std::string>::size_type i = 0; i < strv.size(); i++) {
 | 
			
		||||
			std::vector<std::string> strv1;
 | 
			
		||||
			SplitString(strv[i], strv1, ":");
 | 
			
		||||
			strv1[0] = "\"" + strv1[0] + "\"";
 | 
			
		||||
			if (!isDegital(strv1[1]) && strtolower(strv1[1]) != "true" && strtolower(strv1[1]) != "false")
 | 
			
		||||
				strv1[1] = "\"" + strv1[1] + "\"";
 | 
			
		||||
 | 
			
		||||
			strv[i] = strv1[0] + ":" + strv1[1];
 | 
			
		||||
			if (i == 0)
 | 
			
		||||
				func_args = strv[i];
 | 
			
		||||
			else
 | 
			
		||||
				func_args += "," + strv[i];
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	func_args = "{" + func_args + "}";
 | 
			
		||||
	EXLOGD(("%s\n"), func_args.c_str());
 | 
			
		||||
	//调用TsHttpRpc类里的_rpc_func_run_client启动客户端
 | 
			
		||||
	_rpc_func_run_client(func_args, buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf) {
 | 
			
		||||
    // 入参:{"ip":"192.168.5.11","port":22,"uname":"root","uauth":"abcdefg","authmode":1,"protocol":2}
 | 
			
		||||
    // 入参:{"ip":"192.168.5.11","port":22,"uname":"root","uauth":"abcdefg","authmode":1,"protocol":2}
 | 
			
		||||
    //   authmode: 1=password, 2=private-key
 | 
			
		||||
    //   protocol: 1=rdp, 2=ssh
 | 
			
		||||
    // SSH返回: {"code":0, "data":{"sid":"0123abcde"}}
 | 
			
		||||
    // RDP返回: {"code":0, "data":{"sid":"0123abcde0A"}}
 | 
			
		||||
    // SSH返回: {"code":0, "data":{"sid":"0123abcde"}}
 | 
			
		||||
    // RDP返回: {"code":0, "data":{"sid":"0123abcde0A"}}
 | 
			
		||||
 | 
			
		||||
    Json::Reader jreader;
 | 
			
		||||
    Json::Value jsRoot;
 | 
			
		||||
| 
						 | 
				
			
			@ -554,7 +640,7 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf) {
 | 
			
		|||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 判断参数是否正确
 | 
			
		||||
    // 判断参数是否正确
 | 
			
		||||
    if (!jsRoot["teleport_ip"].isString()
 | 
			
		||||
        || !jsRoot["teleport_port"].isNumeric() || !jsRoot["remote_host_ip"].isString()
 | 
			
		||||
        || !jsRoot["session_id"].isString() || !jsRoot["protocol_type"].isNumeric() || !jsRoot["protocol_sub_type"].isNumeric()
 | 
			
		||||
| 
						 | 
				
			
			@ -663,7 +749,7 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf) {
 | 
			
		|||
            int iHeight = GetSystemMetrics(SM_CYSCREEN);
 | 
			
		||||
 | 
			
		||||
            if (rdp_w == 0 || rdp_h == 0) {
 | 
			
		||||
                //全屏
 | 
			
		||||
                //全屏
 | 
			
		||||
                width = iWidth;
 | 
			
		||||
                higth = iHeight;
 | 
			
		||||
                display = 2;
 | 
			
		||||
| 
						 | 
				
			
			@ -732,7 +818,7 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf) {
 | 
			
		|||
            fclose(f);
 | 
			
		||||
            ex_astr2wstr(sz_file_name, tmp_rdp_file);
 | 
			
		||||
 | 
			
		||||
            // 变量替换
 | 
			
		||||
            // 变量替换
 | 
			
		||||
            ex_replace_all(w_exe_path, _T("{tmp_rdp_file}"), tmp_rdp_file);
 | 
			
		||||
        } else if (g_cfg.rdp_name == L"freerdp") {
 | 
			
		||||
            w_exe_path += L"{size} {console} {clipboard} {drives} ";
 | 
			
		||||
| 
						 | 
				
			
			@ -741,7 +827,7 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf) {
 | 
			
		|||
            ex_wstr w_screen;
 | 
			
		||||
 | 
			
		||||
            if (rdp_w == 0 || rdp_h == 0) {
 | 
			
		||||
                //全屏
 | 
			
		||||
                //全屏
 | 
			
		||||
                w_screen = _T("/f");
 | 
			
		||||
            } else {
 | 
			
		||||
                char sz_size[64] = { 0 };
 | 
			
		||||
| 
						 | 
				
			
			@ -767,10 +853,10 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf) {
 | 
			
		|||
 | 
			
		||||
            w_sid = L"02" + w_sid;
 | 
			
		||||
 | 
			
		||||
            w_exe_path += L" /gdi:sw"; // 使用软件渲染,gdi:hw使用硬件加速,但是会出现很多黑块(录像回放时又是正常的!)
 | 
			
		||||
            w_exe_path += L" -grab-keyboard"; // [new style] 防止启动FreeRDP后,失去本地键盘响应,必须得先最小化一下FreeRDP窗口(不过貌似不起作用)
 | 
			
		||||
            w_exe_path += L" /gdi:sw"; // 使用软件渲染,gdi:hw使用硬件加速,但是会出现很多黑块(录像回放时又是正常的!)
 | 
			
		||||
            w_exe_path += L" -grab-keyboard"; // [new style] 防止启动FreeRDP后,失去本地键盘响应,必须得先最小化一下FreeRDP窗口(不过貌似不起作用)
 | 
			
		||||
 | 
			
		||||
            // 变量替换
 | 
			
		||||
            // 变量替换
 | 
			
		||||
            ex_replace_all(w_exe_path, _T("{size}"), w_screen);
 | 
			
		||||
 | 
			
		||||
            if (flag_console && rdp_console)
 | 
			
		||||
| 
						 | 
				
			
			@ -855,7 +941,7 @@ void TsHttpRpc::_rpc_func_rdp_play(const ex_astr& func_args, ex_astr& buf) {
 | 
			
		|||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 判断参数是否正确
 | 
			
		||||
    // 判断参数是否正确
 | 
			
		||||
    if (!jsRoot["rid"].isInt()
 | 
			
		||||
        || !jsRoot["web"].isString()
 | 
			
		||||
        || !jsRoot["sid"].isString()
 | 
			
		||||
| 
						 | 
				
			
			@ -879,9 +965,9 @@ void TsHttpRpc::_rpc_func_rdp_play(const ex_astr& func_args, ex_astr& buf) {
 | 
			
		|||
    char cmd_args[1024] = { 0 };
 | 
			
		||||
    ex_strformat(cmd_args, 1023, "%d \"%s\" \"%09d-%s-%s-%s-%s\"", rid, a_sid.c_str(), rid, a_user.c_str(), a_acc.c_str(), a_host.c_str(), a_start.c_str());
 | 
			
		||||
 | 
			
		||||
    // TODO: 理论上不应该由助手来提前做域名转为IP这样的操作,而是应该将域名发送给播放器,由播放器自己去处理
 | 
			
		||||
    // 但是在改造FreeRDP制作的播放器时,为了从服务器上下载文件,使用了Mongoose库,如果传入的是域名,会出现问题(貌似是异步查询DNS的问题)
 | 
			
		||||
    // 所以暂时先由助手进行域名IP转换。
 | 
			
		||||
    // TODO: 理论上不应该由助手来提前做域名转为IP这样的操作,而是应该将域名发送给播放器,由播放器自己去处理
 | 
			
		||||
    // 但是在改造FreeRDP制作的播放器时,为了从服务器上下载文件,使用了Mongoose库,如果传入的是域名,会出现问题(貌似是异步查询DNS的问题)
 | 
			
		||||
    // 所以暂时先由助手进行域名IP转换。
 | 
			
		||||
    {
 | 
			
		||||
        unsigned int port_i = 0;
 | 
			
		||||
        struct mg_str scheme, query, fragment, user_info, host, path;
 | 
			
		||||
| 
						 | 
				
			
			@ -897,7 +983,7 @@ void TsHttpRpc::_rpc_func_rdp_play(const ex_astr& func_args, ex_astr& buf) {
 | 
			
		|||
        ex_astr _scheme;
 | 
			
		||||
        _scheme.assign(scheme.p, scheme.len);
 | 
			
		||||
 | 
			
		||||
        // 将host从域名转换为IP
 | 
			
		||||
        // 将host从域名转换为IP
 | 
			
		||||
        ex_astr str_tp_host;
 | 
			
		||||
        str_tp_host.assign(host.p, host.len);
 | 
			
		||||
        struct hostent *tp_host = gethostbyname(str_tp_host.c_str());
 | 
			
		||||
| 
						 | 
				
			
			@ -1001,7 +1087,7 @@ void TsHttpRpc::_rpc_func_file_action(const ex_astr& func_args, ex_astr& buf) {
 | 
			
		|||
        _create_json_ret(buf, TPE_JSON_FORMAT);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    // 判断参数是否正确
 | 
			
		||||
    // 判断参数是否正确
 | 
			
		||||
    if (!jsRoot["action"].isNumeric()) {
 | 
			
		||||
        _create_json_ret(buf, TPE_PARAM);
 | 
			
		||||
        return;
 | 
			
		||||
| 
						 | 
				
			
			@ -1024,9 +1110,9 @@ void TsHttpRpc::_rpc_func_file_action(const ex_astr& func_args, ex_astr& buf) {
 | 
			
		|||
        ZeroMemory(&ofn, sizeof(ofn));
 | 
			
		||||
 | 
			
		||||
        ofn.lStructSize = sizeof(ofn);
 | 
			
		||||
        ofn.lpstrTitle = _T("选择文件");
 | 
			
		||||
        ofn.lpstrTitle = _T("选择文件");
 | 
			
		||||
        ofn.hwndOwner = hParent;
 | 
			
		||||
        ofn.lpstrFilter = _T("可执行程序 (*.exe)\0*.exe\0");
 | 
			
		||||
        ofn.lpstrFilter = _T("可执行程序 (*.exe)\0*.exe\0");
 | 
			
		||||
        ofn.lpstrFile = wszReturnPath;
 | 
			
		||||
        ofn.nMaxFile = MAX_PATH;
 | 
			
		||||
        ofn.lpstrInitialDir = wsDefaultPath.c_str();
 | 
			
		||||
| 
						 | 
				
			
			@ -1044,12 +1130,12 @@ void TsHttpRpc::_rpc_func_file_action(const ex_astr& func_args, ex_astr& buf) {
 | 
			
		|||
        ZeroMemory(&bi, sizeof(BROWSEINFO));
 | 
			
		||||
        bi.hwndOwner = NULL;
 | 
			
		||||
        bi.pidlRoot = NULL;
 | 
			
		||||
        bi.pszDisplayName = wszReturnPath; //此参数如为NULL则不能显示对话框
 | 
			
		||||
        bi.lpszTitle = _T("选择目录");
 | 
			
		||||
        bi.pszDisplayName = wszReturnPath; //此参数如为NULL则不能显示对话框
 | 
			
		||||
        bi.lpszTitle = _T("选择目录");
 | 
			
		||||
        bi.ulFlags = BIF_RETURNONLYFSDIRS;
 | 
			
		||||
        bi.lpfn = NULL;
 | 
			
		||||
        bi.iImage = 0;   //初始化入口参数bi结束
 | 
			
		||||
        LPITEMIDLIST pIDList = SHBrowseForFolder(&bi);//调用显示选择对话框
 | 
			
		||||
        bi.iImage = 0;   //初始化入口参数bi结束
 | 
			
		||||
        LPITEMIDLIST pIDList = SHBrowseForFolder(&bi);//调用显示选择对话框
 | 
			
		||||
        if (pIDList) {
 | 
			
		||||
            ret = true;
 | 
			
		||||
            SHGetPathFromIDList(pIDList, wszReturnPath);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue