此工程编译出winvnc4.exe二进制文件。它得到的二进制是作为VNC服务端来使用的。
一、从main说起
- int main(int argc, const char* argv[]) {
- int result = 0;
-
- try {
-
-
-
- initStdIOLoggers();
- initFileLogger("C:\\temp\\WinVNC4.log");
- rfb::win32::initEventLogLogger(VNCServerService::Name);
-
-
- logParams.setParam("*:stderr:0");
-
-
- programInfo();
- processParams(argc, argv);
-
-
- if (runServer) {
- if (close_console) {
- vlog.info("closing console");
- if (!FreeConsole())
- vlog.info("unable to close console:%u", GetLastError());
- }
-
- network::TcpSocket::initTcpSockets();
- VNCServerWin32 server;
-
- if (runAsService) {
- printf("Starting Service-Mode VNC Server.\n");
- VNCServerService service(server);
-
- service.start();
- result = service.getStatus().dwWin32ExitCode;
- } else {
- printf("Starting User-Mode VNC Server.\n");
-
- result = server.run();
- }
- }
-
- vlog.debug("WinVNC service destroyed");
- } catch (rdr::Exception& e) {
- try {
- vlog.error("Fatal Error: %s", e.str());
- } catch (...) {
- fprintf(stderr, "WinVNC: Fatal Error: %s\n", e.str());
- }
- if (!runAsService)
- MsgBox(0, TStr(e.str()), MB_ICONERROR | MB_OK);
- }
-
- vlog.debug("WinVNC process quitting");
- return result;
- }
步一、打印信息设置
步二、打印程序详细信息
programInfo();
步三、处理命令行
- processParams(argc, argv);
- void
- processParams(int argc, const char* argv[]) {
- for (int i=1; i<argc; i++) {
- try {
-
- if (strcasecmp(argv[i], "-connect") == 0) {
- runServer = false;
- CharArray host;
- if (i+1 < argc) {
- host.buf = strDup(argv[i+1]);
- } else {
- AddNewClientDialog ancd;
- if (ancd.showDialog())
- host.buf = strDup(ancd.getHostName());
- }
- if (host.buf) {
- HWND hwnd = FindWindow(0, _T("winvnc::IPC_Interface"));
- COPYDATASTRUCT copyData;
- copyData.dwData = 1;
- copyData.cbData = strlen(host.buf);
- copyData.lpData = (void*)host.buf;
- i++;
- SendMessage(hwnd, WM_COPYDATA, 0, (LPARAM)©Data);
- printf("Sent connect request to VNC Server...\n");
- }
- } else if (strcasecmp(argv[i], "-disconnect") == 0) {
- HWND hwnd = FindWindow(0, _T("winvnc::IPC_Interface"));
- COPYDATASTRUCT copyData;
- copyData.dwData = 2;
- copyData.lpData = 0;
- copyData.cbData = 0;
- SendMessage(hwnd, WM_COPYDATA, 0, (LPARAM)©Data);
- printf("Sent disconnect request to VNC Server...\n");
- runServer = false;
- } else if (strcasecmp(argv[i], "-start") == 0) {
- printf("Attempting to start service...\n");
- runServer = false;
- if (rfb::win32::startService(VNCServerService::Name))
- printf("Started service successfully\n");
- } else if (strcasecmp(argv[i], "-stop") == 0) {
- printf("Attempting to stop service...\n");
- runServer = false;
- if (rfb::win32::stopService(VNCServerService::Name))
- printf("Stopped service successfully\n");
- } else if (strcasecmp(argv[i], "-status") == 0) {
- printf("Querying service status...\n");
- runServer = false;
- rfb::win32::printServiceStatus(VNCServerService::Name);
-
- } else if (strcasecmp(argv[i], "-service") == 0) {
- printf("Run in service mode\n");
- runAsService = true;
-
- } else if (strcasecmp(argv[i], "-register") == 0) {
- printf("Attempting to register service...\n");
- runServer = false;
- int j = i;
- i = argc;
- if (rfb::win32::registerService(VNCServerService::Name,
- _T("VNC Server Version 4"),
- argc-(j+1), &argv[j+1]))
- printf("Registered service successfully\n");
- } else if (strcasecmp(argv[i], "-unregister") == 0) {
- printf("Attempting to unregister service...\n");
- runServer = false;
- if (rfb::win32::unregisterService(VNCServerService::Name))
- printf("Unregistered service successfully\n");
-
- } else if (strcasecmp(argv[i], "-noconsole") == 0) {
- close_console = true;
-
- } else if ((strcasecmp(argv[i], "-help") == 0) ||
- (strcasecmp(argv[i], "--help") == 0) ||
- (strcasecmp(argv[i], "-h") == 0) ||
- (strcasecmp(argv[i], "/?") == 0)) {
- runServer = false;
- programUsage();
- break;
-
- } else {
-
- if (Configuration::setParam(argv[i], true))
- continue;
-
- if ((argv[i][0] == '-') && (i+1 < argc)) {
- if (Configuration::setParam(&argv[i][1], argv[i+1], true)) {
- i++;
- continue;
- }
- }
-
- runServer = false;
- programUsage();
- break;
- }
-
- } catch (rdr::Exception& e) {
- vlog.error(e.str());
- }
- }
- }
(1)从命令行中提取出IP地址串,并组成把它放到COPYDATASTRUCT中。
找到窗口_T("winvnc::IPC_Interface"),将得到的COPYDATASTRUCT数据发送到窗口中。
因为在服务端此窗口的创建是在 “第一个构造函数:”, 而此时窗口一定是找不到的,那么还有一种情况可以找到就是VNC服务端与VNC客户端并存时就会出现。
这是因为VNC客户端也会创建此窗口。
那么可以说,这时的发送WM_COPYDATA其实是发送给客户端的。
- if (host.buf) {
- HWND hwnd = FindWindow(0, _T("winvnc::IPC_Interface"));
- COPYDATASTRUCT copyData;
- copyData.dwData = 1;
- copyData.cbData = strlen(host.buf);
- copyData.lpData = (void*)host.buf;
- i++;
- SendMessage(hwnd, WM_COPYDATA, 0, (LPARAM)©Data);
- printf("Sent connect request to VNC Server...\n");
- }
针对此WM_COPYDATA的响应是:
(2)
(3)
(4)
(5)
(6)
(7)
步四、启动服务
有两种方式可以选择:服务方式、用户模式(!!!!!!!!最重要)
- if (runAsService) {
- printf("Starting Service-Mode VNC Server.\n");
- VNCServerService service(server);
-
- service.start();
- result = service.getStatus().dwWin32ExitCode;
- } else {
- printf("Starting User-Mode VNC Server.\n");
-
- result = server.run();
- }
启动时得保证
runServer == true;
runServer的初始值是static bool runServer = true;,当我们有指定命令行时,此变量会变为false。
如在 “步三、处理命令行" ,命令行是“-connect”、"-disconnect"、“-start”、"-stop"、"-status"、"-register"、"-unregister"、"-help"
意思是如果指定了命令行,那么是不会启动服务的。
如果是要关闭console界面那么调用系统API
来实现
(1)以服务方式启动客户端
- VNCServerWin32 server;
-
- if (runAsService) {
- printf("Starting Service-Mode VNC Server.\n");
- VNCServerService service(server);
-
- service.start();
- result = service.getStatus().dwWin32ExitCode;
(2)以用户模式启动客户端服务
VNCServerWin32 server;
-
- int VNCServerWin32::run() {
- { Lock l(runLock);
- hostThread = Thread::self();
- runServer = true;
- }
-
-
-
- if (isServiceProcess())
- config.setKey(HKEY_LOCAL_MACHINE, RegConfigPath);
- else
- config.setKey(HKEY_CURRENT_USER, RegConfigPath);
- config.setNotifyThread(Thread::self(), VNCM_REG_CHANGED);
-
-
- STrayIconThread trayIcon(*this, IDI_ICON, IDI_CONNECTED, IDR_TRAY);
-
- DWORD result = 0;
- try {
-
-
- ManagedListener rfb(&sockMgr, &vncServer);
- ManagedListener http(&sockMgr, httpServer);
-
-
- MSG msg;
- do {
-
-
- rfb.setPort(port_number, localHost);
- http.setPort(http_port, localHost);
-
-
- httpServer->setRFBport(rfb.sock ? port_number : 0);
-
-
- CharArray pattern;
- pattern.buf = hosts.getData();
- if (!localHost) {
- rfb.setFilter(pattern.buf);
- http.setFilter(pattern.buf);
- }
-
-
-
- {
- const TCHAR* prefix = isServiceProcess() ?
- _T("VNC Server (Service):") : _T("VNC Server (User):");
-
- std::list<char*> addrs;
- if (rfb.sock)
- rfb.sock->getMyAddresses(&addrs);
- else
- addrs.push_front(strDup("Not accepting connections"));
-
- std::list<char*>::iterator i, next_i;
- int length = _tcslen(prefix)+1;
- for (i=addrs.begin(); i!= addrs.end(); i++)
- length += strlen(*i) + 1;
-
- TCharArray toolTip(length);
- _tcscpy(toolTip.buf, prefix);
- for (i=addrs.begin(); i!= addrs.end(); i=next_i) {
- next_i = i; next_i ++;
- TCharArray addr = *i;
- _tcscat(toolTip.buf, addr.buf);
- if (next_i != addrs.end())
- _tcscat(toolTip.buf, _T(","));
- }
- trayIcon.setToolTip(toolTip.buf);
- }
-
- vlog.debug("Entering message loop");
-
-
-
- while (sockMgr.getMessage(&msg, NULL, 0, 0)) {
- if (msg.hwnd == 0) {
- if (msg.message == VNCM_REG_CHANGED)
- break;
- if (msg.message == VNCM_COMMAND)
- doCommand();
- }
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
-
- } while ((msg.message != WM_QUIT) || runServer);
-
- vlog.debug("Server exited cleanly");
- } catch (rdr::SystemException &s) {
- vlog.error(s.str());
- result = s.err;
- } catch (rdr::Exception &e) {
- vlog.error(e.str());
- }
-
- { Lock l(runLock);
- runServer = false;
- hostThread = 0;
- }
-
- return result;
- }
(2、1)注册表设置,并向线程发送NCM_REG_CHANGED消息
- if (isServiceProcess())
- config.setKey(HKEY_LOCAL_MACHINE, RegConfigPath);
- else
- config.setKey(HKEY_CURRENT_USER, RegConfigPath);
- config.setNotifyThread(Thread::self(), VNCM_REG_CHANGED);
发送的消息最后是在 “(2、4)进入一个while的操作,直到收到WM_QUIT后才退出” 中被收到的
(2、2)
创建 tray icon
-
- STrayIconThread trayIcon(*this, IDI_ICON, IDI_CONNECTED, IDR_TRAY);
创建时会调用STrayIconThread的构造函数:
- STrayIconThread::STrayIconThread(VNCServerWin32& sm, UINT inactiveIcon_, UINT activeIcon_, UINT menu_)
- : server(sm), inactiveIcon(inactiveIcon_), activeIcon(activeIcon_), menu(menu_),
- windowHandle(0), runTrayIcon(true) {
- start();
- }
因为STrayIconThread继承自Thread,所以这里的start其实会调用到STrayIconThread::run()
- void STrayIconThread::run() {
- while (runTrayIcon) {
- if (rfb::win32::desktopChangeRequired() &&
- !rfb::win32::changeDesktop())
- Sleep(2000);
-
- STrayIcon icon(*this);
- windowHandle = icon.getHandle();
-
- MSG msg;
- while (runTrayIcon && ::GetMessage(&msg, 0, 0, 0) > 0) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
-
- windowHandle = 0;
- }
- }
(2、2、1)
- if (rfb::win32::desktopChangeRequired() &&
- !rfb::win32::changeDesktop())
- Sleep(2000);
(2、2、2)创建STrayIcon,并获得它的窗口句柄。
- STrayIcon icon(*this);
- windowHandle = icon.getHandle();
STrayIcon继承自TrayIcon, TrayIcon继承自MsgWindow
- class winvnc::STrayIcon : public TrayIcon
- class TrayIcon : public MsgWindow
- class MsgWindow {
- public:
- MsgWindow(const TCHAR* _name);
- virtual ~MsgWindow();
-
- const TCHAR* getName() {return name.buf;}
- HWND getHandle() const {return handle;}
-
- virtual LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam);
-
- protected:
- TCharArray name;
- HWND handle;
- };
创建STrayIcon时会调用到三个构造函数:
第一个构造函数:
MsgWindow的构造函数就是创建一个窗口,窗口名称为"VNCTray",大小为10*10;
- MsgWindow::MsgWindow(const TCHAR* name_) : name(tstrDup(name_)), handle(0) {
- vlog.debug("creating window \"%s\"", (const char*)CStr(name.buf));
- handle = CreateWindow((const TCHAR*)baseClass.classAtom, name.buf, WS_OVERLAPPED,
- 0, 0, 10, 10, 0, 0, baseClass.instance, this);
- if (!handle) {
- throw rdr::SystemException("unable to create WMNotifier window instance", GetLastError());
- }
- vlog.debug("created window \"%s\" (%x)", (const char*)CStr(name.buf), handle);
- }
窗口类名为(const TCHAR*)baseClass.classAtom; _T("rfb::win32::MsgWindowClass")
baseClass是类MsgWindowClass,它用来管理窗口类。
- MsgWindowClass::MsgWindowClass() : classAtom(0) {
- WNDCLASS wndClass;
- wndClass.style = 0;
- wndClass.lpfnWndProc = MsgWindowProc;
- wndClass.cbClsExtra = 0;
- wndClass.cbWndExtra = 0;
- wndClass.hInstance = instance = GetModuleHandle(0);
- wndClass.hIcon = 0;
- wndClass.hCursor = 0;
- wndClass.hbrBackground = 0;
- wndClass.lpszMenuName = 0;
- wndClass.lpszClassName = _T("rfb::win32::MsgWindowClass");
- classAtom = RegisterClass(&wndClass);
- if (!classAtom) {
- throw rdr::SystemException("unable to register MsgWindow window class", GetLastError());
- }
- }
特别重要的是它的
窗口消息处理函数MsgWindowProc。
如果消息是在创建窗口时,即CreateWindows时,会收到消息WM_CREATE,此时把(long)((CREATESTRUCT*)lParam)->lpCreateParams,即MsgWindow的this指针作为
窗口数据存起来。之后的MsgWindowsProc中对各消息的处理就是取出窗口中的数据,强转为MsgWindows后,调用它的processMessage 函数,
因为MsgWindows类中的processMessage成员是虚函数,所以如果继承类有去重载它,那么是只会调用了继承类的processMessage函数。如:
STrayIcon的成员processMessage.
- LRESULT CALLBACK MsgWindowProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) {
- LRESULT result;
-
- if (msg == WM_CREATE)
- SetWindowLong(wnd, GWL_USERDATA, (long)((CREATESTRUCT*)lParam)->lpCreateParams);
- else if (msg == WM_DESTROY)
- SetWindowLong(wnd, GWL_USERDATA, 0);
- MsgWindow* _this = (MsgWindow*) GetWindowLong(wnd, GWL_USERDATA);
- if (!_this) {
- vlog.info("null _this in %x, message %x", wnd, msg);
- return SafeDefWindowProc(wnd, msg, wParam, lParam);
- }
-
- try {
- result = _this->processMessage(msg, wParam, lParam);
- } catch (rdr::Exception& e) {
- vlog.error("untrapped: %s", e.str());
- }
-
- return result;
- };
第二个构造函数:
- TrayIcon() : MsgWindow(_T("VNCTray")) {
- fdef NOTIFYICONDATA_V1_SIZE
- nid.cbSize = NOTIFYICONDATA_V1_SIZE;
- lse
- nid.cbSize = sizeof(NOTIFYICONDATA);
- ndif
-
- nid.hWnd = getHandle();
- nid.uID = 0;
- nid.hIcon = 0;
- nid.uFlags = NIF_ICON | NIF_MESSAGE;
- nid.uCallbackMessage = WM_USER;
- }
第三个构造函数:STrayIcon构造函数
- STrayIcon(STrayIconThread& t) : thread(t),
- vncConfig(_T("vncconfig.exe"), isServiceProcess() ? _T("-noconsole -service") : _T("-noconsole")),
- vncConnect(_T("winvnc4.exe"), _T("-connect")) {
-
-
- SetWindowText(getHandle(), _T("winvnc::IPC_Interface"));
-
-
- SetTimer(getHandle(), 1, 3000, 0);
- PostMessage(getHandle(), WM_TIMER, 1, 0);
- PostMessage(getHandle(), WM_SET_TOOLTIP, 0, 0);
- }
在STrayIcon的构造函数中:
首先构造两对象
- LaunchProcess vncConfig;
- LaunchProcess vncConnect;
作用:在窗口收到消息WM_COMMAND,命令为ID_CONNECT时就连接服务端:
- CurrentUserToken token;
- if (token.isValid())
- vncConnect.start(isServiceProcess() ? (HANDLE)token : 0);
- else
- vlog.error("Options: unknown current user");
- void LaunchProcess::start(HANDLE userToken) {
- if (procInfo.hProcess && (WaitForSingleObject(procInfo.hProcess, 0) != WAIT_OBJECT_0))
- return;
- await();
-
-
- STARTUPINFO sinfo;
- memset(&sinfo, 0, sizeof(sinfo));
- sinfo.cb = sizeof(sinfo);
-
-
- TCharArray exePath;
- if (!tstrContains(exeName.buf, _T('\\'))) {
- ModuleFileName filename;
- TCharArray path; splitPath(filename.buf, &path.buf, 0);
- exePath.buf = new TCHAR[_tcslen(path.buf) + _tcslen(exeName.buf) + 2];
- _stprintf(exePath.buf, _T("%s\\%s"), path.buf, exeName.buf);
- } else {
- exePath.buf = tstrDup(exeName.buf);
- }
-
-
-
-
-
- TCharArray cmdLine(_tcslen(exeName.buf) + 3 + _tcslen(params.buf) + 1);
- _stprintf(cmdLine.buf, _T("\"%s\" %s"), exeName.buf, params.buf);
- #ifdef _DEBUG
- DWORD flags = CREATE_NEW_CONSOLE;
- #else
- DWORD flags = CREATE_NO_WINDOW;
- #endif
- BOOL success;
- if (userToken)
- success = CreateProcessAsUser(userToken, exePath.buf, cmdLine.buf, 0, 0, FALSE, flags, 0, 0, &sinfo, &procInfo);
- else
- success = CreateProcess(exePath.buf, cmdLine.buf, 0, 0, FALSE, flags, 0, 0, &sinfo, &procInfo);
- if (!success)
- throw rdr::SystemException("unable to launch process", GetLastError());
-
-
- WaitForInputIdle(procInfo.hProcess, 15000);
- }
然后,设置窗口名称为_T("winvnc::IPC_Interface"
然后开启定时器1,每3S触发一次;
最后给窗口发送WM_TIMER与WM_SET_TOOLTIP消息;
作用:WM_TIMER用于刷新图标状态
如果桌面不是输入桌面,那么就把图标关闭,如果(“当前桌面和名称”与"输入桌面名称“是否一致来判断);
如果桌面还是存在那么更新当前的图标状态。(激活或非激活)
- if (rfb::win32::desktopChangeRequired()) {
- SendMessage(getHandle(), WM_CLOSE, 0, 0);
- return 0;
- }
- setIcon(thread.server.isServerInUse() ? thread.activeIcon : thread.inactiveIcon);
- return 0;
WM_SET_TOOLTIP用于设置”工具提示信息“
- case WM_SET_TOOLTIP:
- {
- rfb::Lock l(thread.lock);
- if (thread.toolTip.buf)
- setToolTip(thread.toolTip.buf);
- }
(2、2、3)消息循环
- MSG msg;
- while (runTrayIcon && ::GetMessage(&msg, 0, 0, 0) > 0) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
(2、3)创建监听socket
- ManagedListener rfb(&sockMgr, &vncServer);
- ManagedListener http(&sockMgr, httpServer);
(2、4)进入一个while的操作,直到收到WM_QUIT后才退出
- MSG msg;
- do {
-
-
-
-
-
-
-
-
- while (sockMgr.getMessage(&msg, NULL, 0, 0)) {
- if (msg.hwnd == 0) {
- if (msg.message == VNCM_REG_CHANGED)
- break;
- if (msg.message == VNCM_COMMAND)
- doCommand();
- }
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- } while ((msg.message != WM_QUIT) || runServer);
这里最重要的是 sockMgr.getMessage(&msg, NULL, 0, 0 函数!!!!!!!!
三、扩展知识
1、TLSAlloc()
缩写为TLS。进程中的全局变量与函数内定义的静态(static)变量,是各个线程都可以访问的共享变量。在一个线程修改的内存内容,对所有线程都生效。这是一个优点也是一个缺点。说它是优点,线程的数据交换变得非常快捷。说它是缺点,一个线程死掉了,其它线程也性命不保; 多个线程访问共享数据,需要昂贵的同步开销,也容易造成同步相关的BUG。
如果需要在一个线程内部的各个 函数调用都能访问、但其它线程不能访问的 变量(被称为static memory local to a thread 线程局部 静态变量),就需要新的机制来实现。这就是TLS。
线程局部存储在不同的平台有不同的实现,可移植性不太好。幸好要实现 线程局部存储并不难,最简单的办法就是建立一个全局表,通过当前线程ID去查询相应的数据,因为各个线程的ID不同,查到的数据自然也不同了。
Win32
方法一:每个线程创建时系统给它分配一个
LPVOID指针的数组(叫做TLS数组),这个数组从C编程角度是隐藏着的不能直接访问,需要通过一些C API函数调用访问。首先定义
一些DWORD线程 全局变量或函数静态 变量,准备作为各个线程访问自己的TLS 数组的
索引变量。一个 线程使用TLS时,第一步在线程内调用TlsAlloc()函数,
为一个TLS数组索引变量与这个线程的TLS数组的某个槽(slot)关联起来,例如获得一个索引变量:
global_dwTLSindex=TLSAlloc();
注意,此步之后,当前线程实际上访问的是这个TLS 数组索引变量的线程内的拷贝版本。也就说,不同线程虽然看起来用的是同名的TLS 数组索引变量,但实际上各个线程得到的可能是不同DWORD值。其意义在于,每个使用TLS的 线程获得了一个DWORD类型的
线程局部静态变量作为TLS 数组的索引变量。C/C++原本没有直接定义
线程局部静态变量的机制,所以在如此大费周折。
第二步,为当前线程动态分配一块内存区域(使用LocalAlloc() 函数调用),然后把指向这块内存区域的 指针放入TLS 数组相应的槽中(使用TlsValue()函数调用)。
第三步,在当前线程的任何函数内,都可以通过TLS 数组的索引变量,使用TlsGetValue()函数得到上一步的那块内存区域的 指针,然后就可以进行内存区域的读写操作了。这就实现了在一个线程内部这个范围处处可访问的变量。
最后,如果不再需要上述线程局部静态变量,要动态释放掉这块内存区域(使用LocalFree()函数),然后从TLS 数组中放弃对应的槽(使用TlsFree()函数)。
在VNC-4.0-winsrc开源代码中看到,它用了TSL的方法:
(1)定义
- static DWORD threadStorage = TlsAlloc();
为一个TLS数组索引变量与这个线程的TLS数组的某个槽(slot)关联起来,例如获得一个索引变量:
(2)设置值
- WINBASEAPI
- BOOL
- WINAPI
- TlsSetValue(
- __in DWORD dwTlsIndex,
- __in_opt LPVOID lpTlsValue
- );
- DWORD WINAPI
- Thread::threadProc(LPVOID lpParameter) {
- Thread* thread = (Thread*) lpParameter;
- <span style="color:#ff0000;"> TlsSetValue(threadStorage, thread);</span>
- logAction(thread, "started");
- try {
- thread->run();
- logAction(thread, "stopped");
- } catch (rdr::Exception& e) {
- logError(thread, e.str());
- }
- bool deleteThread = false;
- {
- Lock l(thread->mutex);
- thread->state = ThreadStopped;
- thread->sig->signal();
- deleteThread = thread->deleteAfterRun;
- }
- if (deleteThread)
- delete thread;
- return 0;
- }
(3)获得值
- WINBASEAPI
- LPVOID
- WINAPI
- TlsGetValue(
- __in DWORD dwTlsIndex
- );
- Thread*
- Thread::self() {
- <span style="color:#ff0000;">Thread* thread = (Thread*) TlsGetValue(threadStorage);</span>
- if (!thread) {
- thread = new Thread(GetCurrentThread(), GetCurrentThreadId());
- <span style="color:#cc0000;"> TlsSetValue(threadStorage, thread);</span>
- }
- return thread;
- }
2、__declspec(thread)的使用
- #include <stdio.h>
- #include <assert.h>
-
-
- __declspec(thread) int g_nData = 0;
-
-
-
-
- DWORD WINAPI ThreadProc(LPVOID lpParameter)
- {
- g_nData = 5;
-
- Sleep(100);
- TCHAR szMsg[100] = {0};
- wsprintf(szMsg, L"Auxi thread, g_nData:%d\n", g_nData);
- MessageBox(NULL, szMsg, L"AuxiThread", MB_ICONINFORMATION);
- return 0;
- }
-
-
- int main()
- {
- DWORD dwId;
-
- HANDLE hThread = CreateThread(NULL, 1024, ThreadProc, NULL, 0, &dwId);
- assert(hThread);
-
- Sleep(50);
- g_nData = 10;
-
- TCHAR szMsg[100] = {0};
- wsprintf(szMsg, L"Result %d\n", g_nData);
- MessageBox(NULL, szMsg, L"MainThread", MB_ICONINFORMATION);
-
- return 0;
- }