1717using namespace std ;
1818
1919vector<HWND> vec;
20+ HANDLE hDIB;
21+ vector<wstring> titles;
22+
23+ BOOL CALLBACK mycallbackMonitores (
24+ HMONITOR Arg1,
25+ HDC Arg2,
26+ LPRECT Arg3,
27+ LPARAM Arg4
28+ ){
29+
30+ // Get monitor info resolution to only show it
31+ MONITORINFO minfo;
32+ // ZeroMemory(&minfo, sizeof(MONITORINFO));
33+ minfo.cbSize = sizeof (MONITORINFO);
34+ GetMonitorInfoA (Arg1, &minfo);
35+ int w = minfo.rcMonitor .right - minfo.rcMonitor .left ;
36+ int h = minfo.rcMonitor .bottom - minfo.rcMonitor .top ;
37+
38+ // Get windows Desktop handle
39+ HWND hWnd = GetDesktopWindow ();
40+
41+ // Fill the data with a name and the windows handle
42+ WCHAR windowTitle[100 ];
43+ wstring title (windowTitle);
44+ titles.push_back (title);
45+ vec.push_back (hWnd);
46+
47+ // show info in screen
48+ int & indexMonitor = *reinterpret_cast <int *>(Arg4);
49+
50+ cout << " [" << (int )vec.size () - 1 << " ] " << " ..." << " Desktop " << indexMonitor << " -- resx: " << w << " resy: " << h;
51+ if (minfo.dwFlags ) {
52+ cout << " (Main Monitor)" ;
53+ }
54+ cout << " \n " ;
55+
56+ // new index to the next loop
57+ indexMonitor += 1 ;
58+
59+ return TRUE ;
60+ }
61+
2062
2163BOOL CALLBACK mycallback (HWND hwnd, LPARAM lParam) {
2264 const DWORD TITLE_SIZE = 1024 ;
2365 WCHAR windowTitle[TITLE_SIZE];
2466
2567 GetWindowTextW (hwnd, windowTitle, TITLE_SIZE);
26-
68+
2769 int length = ::GetWindowTextLength (hwnd);
28- std:: wstring title (&windowTitle[0 ]);
70+ wstring title (&windowTitle[0 ]);
2971
3072
3173 if (!IsWindowVisible (hwnd) || length == 0 ) {
@@ -35,16 +77,17 @@ BOOL CALLBACK mycallback(HWND hwnd, LPARAM lParam) {
3577
3678 // Retrieve the pointer passed into this callback, and re-'type' it.
3779 // The only way for a C API to pass arbitrary data is by means of a void*.
38- std:: vector<std:: wstring>& titles = *reinterpret_cast <std:: vector<std:: wstring>*>(lParam);
80+ vector<wstring>& titles = *reinterpret_cast <vector<wstring>*>(lParam);
3981 titles.push_back (title);
4082 vec.push_back (hwnd);
41- cout << " ............ " << " [" << (int )titles.size () - 1 << " ] " << hwnd << " ..." << string (title.begin (), title.end ()) << endl;
42-
83+ cout << " [" << (int )titles.size () - 1 << " ] " << hwnd << " ..." << string (title.begin (), title.end ()) << endl;
4384 return TRUE ;
4485}
4586
46- int SendWindow (HWND hWnd, const char * ndi_name)
47- {
87+ // This function return a frame
88+ // that contain a bitmat buffer captured from de window
89+ NDIlib_video_frame_v2_t CreateFrameFromHWND (HWND hWnd) {
90+
4891 HDC hdcWindow;
4992 HDC hdcMemDC = NULL ;
5093 HBITMAP hbmScreen = NULL ;
@@ -53,170 +96,181 @@ int SendWindow(HWND hWnd, const char* ndi_name)
5396 // Retrieve the handle to a display device context for the client
5497 // area of the window.
5598 hdcWindow = GetDC (hWnd);
99+
100+ // Get the client area for size calculation
101+ RECT rcClient;
102+ GetClientRect (hWnd, &rcClient);
56103
104+ // We are going to open a Win32 wrapper at rcClient resolution
105+ int xres = rcClient.right - rcClient.left ;
106+ int yres = rcClient.bottom - rcClient.top ;
107+
57108 // Create a compatible DC which is used in a BitBlt from the window DC
58109 hdcMemDC = CreateCompatibleDC (hdcWindow);
59- if (!hdcMemDC)
110+
111+ // Create a compatible bitmap from the Window DC
112+ hbmScreen = CreateCompatibleBitmap (hdcWindow, rcClient.right - rcClient.left , rcClient.bottom - rcClient.top );
113+
114+ // Select the compatible bitmap into the compatible memory DC.
115+ SelectObject (hdcMemDC, hbmScreen);
116+
117+ // Bit block transfer into our compatible memory DC.
118+ if (!BitBlt (hdcMemDC,
119+ 0 , 0 ,
120+ rcClient.right - rcClient.left , rcClient.bottom - rcClient.top ,
121+ hdcWindow,
122+ 0 , 0 ,
123+ SRCCOPY))
60124 {
61- MessageBox (hWnd, L" CreateCompatibleDC has failed" , L" Failed" , MB_OK);
125+ MessageBox (hWnd, L" BitBlt has failed" , L" Failed" , MB_OK);
62126 }
63127
64- // Get the client area for size calculation
65- RECT rcClient;
66- GetClientRect (hWnd, &rcClient);
67-
68- // We are going to open a Win32 wrapper at rcClient resolution at 29.97fps
69- const int xres = rcClient.right - rcClient.left ;
70- const int yres = rcClient.bottom - rcClient.top ;
128+ // Get the BITMAP from the HBITMAP
129+ // GetBitmapBits()
130+ GetObject (hbmScreen, sizeof (BITMAP), &bmpScreen);
131+
132+ BITMAPINFOHEADER bi;
133+
134+ bi.biSize = sizeof (BITMAPINFOHEADER);
135+ bi.biWidth = bmpScreen.bmWidth ;
136+ bi.biHeight = -bmpScreen.bmHeight ;
137+ bi.biPlanes = 1 ;
138+ bi.biBitCount = 32 ;
139+ bi.biCompression = BI_RGB;
140+ bi.biSizeImage = 0 ;
141+ bi.biXPelsPerMeter = 0 ;
142+ bi.biYPelsPerMeter = 0 ;
143+ bi.biClrUsed = 0 ;
144+ bi.biClrImportant = 0 ;
145+
146+ DWORD dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31 ) / 32 ) * 4 * bmpScreen.bmHeight ;
147+
148+ // Starting with 32-bit Windows, GlobalAlloc and LocalAlloc are implemented as wrapper functions that
149+ // call HeapAlloc using a handle to the process's default heap. Therefore, GlobalAlloc and LocalAlloc
150+ // have greater overhead than HeapAlloc.
151+ hDIB = GlobalAlloc (GHND, dwBmpSize);
152+ char *lpbitmap = (char *)GlobalLock (hDIB);
153+
154+ // Gets the "bits" from the bitmap and copies them into a buffer
155+ // which is pointed to by lpbitmap.
156+ GetDIBits (hdcWindow, hbmScreen, 0 , (UINT)bmpScreen.bmHeight , lpbitmap, (BITMAPINFO *)&bi, DIB_RGB_COLORS);
157+
158+ // at 29.97fps
71159 const int framerate_n = 30000 ;
72160 const int framerate_d = 1001 ;
73161
74- // This is the best stretch mode
75- // SetStretchBltMode(hdcWindow, HALFTONE);
162+ // Describe the frame.
163+ // Note another undocumented feature is that if you pass the pointer as NULL then it does not send the frame,
164+ // but it does still clock it correctly as if you did :) I bet you are glad you are reading this example.
165+ NDIlib_video_frame_v2_t frame;
166+ frame.xres = xres;
167+ frame.yres = yres;
168+ frame.FourCC = NDIlib_FourCC_type_BGRA;
169+ frame.frame_rate_N = framerate_n;
170+ frame.frame_rate_D = framerate_d;
171+ frame.p_data = (uint8_t *)lpbitmap;
172+ frame.line_stride_in_bytes = xres * 4 ;
76173
77- // Create a compatible bitmap from the Window DC
78- hbmScreen = CreateCompatibleBitmap (hdcWindow, rcClient.right - rcClient.left , rcClient.bottom - rcClient.top );
79- if (!hbmScreen)
80- {
81- MessageBox (hWnd, L" CreateCompatibleBitmap Failed" , L" Failed" , MB_OK);
82- }
174+ // Clean up
175+ DeleteObject (hbmScreen);
176+ DeleteObject (hdcMemDC);
177+ ReleaseDC (hWnd, hdcWindow);
83178
84- // Select the compatible bitmap into the compatible memory DC.
85- SelectObject (hdcMemDC, hbmScreen);
179+ return frame;
180+ }
181+
182+ int SendWindow (HWND hWnd, const char * ndi_name)
183+ {
86184
87185 // /////////////////
88- // Create an NDI source that is called "My Video" and is clocked to the video.
186+ // Create an NDI source and is clocked to the video.
89187 NDIlib_send_create_t NDI_send_create_desc;
90188 NDI_send_create_desc.p_ndi_name = ndi_name;
91189 NDIlib_send_instance_t m_pNDI_send = NDIlib_send_create (&NDI_send_create_desc);
92190 if (!m_pNDI_send) { return 0 ; };
93191
94192 cout << " \n " ;
95193
194+ // Loop
96195 for (int x = 0 , dx = (rand () & 7 ), cnt = 0 ;; x += dx)
97196 {
197+
98198 // Get the system time
99199 wchar_t temp[128 ];
100200 swprintf (temp, 128 , L" %06d" , cnt++);
101201 wcout << temp << " \r " ;
102202
103- // Bit block transfer into our compatible memory DC.
104- if (!BitBlt (hdcMemDC,
105- 0 , 0 ,
106- rcClient.right - rcClient.left , rcClient.bottom - rcClient.top ,
107- hdcWindow,
108- 0 , 0 ,
109- SRCCOPY))
110- {
111- MessageBox (hWnd, L" BitBlt has failed" , L" Failed" , MB_OK);
112- }
113-
114- // Get the BITMAP from the HBITMAP
115- GetObject (hbmScreen, sizeof (BITMAP), &bmpScreen);
116-
117- BITMAPINFOHEADER bi;
118-
119- bi.biSize = sizeof (BITMAPINFOHEADER);
120- bi.biWidth = bmpScreen.bmWidth ;
121- bi.biHeight = -bmpScreen.bmHeight ;
122- bi.biPlanes = 1 ;
123- bi.biBitCount = 32 ;
124- bi.biCompression = BI_RGB;
125- bi.biSizeImage = 0 ;
126- bi.biXPelsPerMeter = 0 ;
127- bi.biYPelsPerMeter = 0 ;
128- bi.biClrUsed = 0 ;
129- bi.biClrImportant = 0 ;
130-
131- DWORD dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31 ) / 32 ) * 4 * bmpScreen.bmHeight ;
132-
133- // Starting with 32-bit Windows, GlobalAlloc and LocalAlloc are implemented as wrapper functions that
134- // call HeapAlloc using a handle to the process's default heap. Therefore, GlobalAlloc and LocalAlloc
135- // have greater overhead than HeapAlloc.
136- HANDLE hDIB = GlobalAlloc (GHND, dwBmpSize);
137- char *lpbitmap = (char *)GlobalLock (hDIB);
138-
139- // Gets the "bits" from the bitmap and copies them into a buffer
140- // which is pointed to by lpbitmap.
141- GetDIBits (hdcWindow, hbmScreen, 0 , (UINT)bmpScreen.bmHeight , lpbitmap, (BITMAPINFO *)&bi, DIB_RGB_COLORS);
142-
143- // Describe the frame. Note another undocumented feature is that if you pass the pointer as NULL then it does not send the frame,
144- // but it does still clock it correctly as if you did :) I bet you are glad you are reading this example.
145- NDIlib_video_frame_v2_t frame;
146- frame.xres = xres;
147- frame.yres = yres;
148- frame.FourCC = NDIlib_FourCC_type_BGRA;
149- frame.frame_rate_N = framerate_n;
150- frame.frame_rate_D = framerate_d;
151- frame.p_data = (uint8_t *)lpbitmap;
152- frame.line_stride_in_bytes = xres * 4 ;
153-
154203 // We now just send the frame
155204 if (m_pNDI_send)
156- NDIlib_send_send_video_v2 (m_pNDI_send, &frame); /* */
205+ NDIlib_send_send_video_v2 (m_pNDI_send, &CreateFrameFromHWND (hWnd));
157206
158207 // Free memory heap
159208 GlobalFree (hDIB);
160209 }
161210
162- // Clean up
163- DeleteObject (hbmScreen);
164- DeleteObject (hdcMemDC);
165- ReleaseDC (hWnd, hdcWindow);
211+
166212
167213 return 0 ;
168214}
169215
170216int main ()
171217{
172- std::cout << " \n " << endl;
173- std::cout << " /////////////////////\n " << endl;
174- std::cout << " Windows list!\n " << endl;
175-
176- // info
177- /* const DWORD info_SIZE = 1024;
178- WCHAR infobuf[info_SIZE];
218+
219+ cout << " \n ///////////////////// " ;
220+ cout << " Monitor list! \n " << endl;
179221
180- GetComputerNameW(infobuf, (DWORD*)&info_SIZE);
181- wcout << L"Equipo: " << infobuf << endl;
222+ // Enumera the monitors
223+ int g = 0 ;
224+ EnumDisplayMonitors (NULL , NULL , mycallbackMonitores, (LPARAM)&g);
182225
183- GetUserNameW(infobuf, (DWORD*)&info_SIZE);
184- wcout << L"Usuario: " << infobuf << endl;
185- */
226+ cout << " \n ///////////////////// " ;
227+ cout << " Windows list! \n " << endl;
186228
187229 // Enumera las ventanas
188- std::vector<std::wstring> titles;
189230 EnumWindows (mycallback, reinterpret_cast <LPARAM>(&titles));
190231
191232 // input seleccion
192233 int x;
193- cout << " \n Select a window: (number between " << 0 << " and " << (int )titles .size () - 1 << " ): " ;
234+ cout << " \n Select a window or desktop : (number between " << 0 << " and " << (int )vec .size () - 1 << " ): " ;
194235 cin >> x;
195236
196- // check si se introdujo un numero correcto
197- while (cin.fail () || x < 0 || x >(int )titles .size () - 1 ) {
237+ // check user input
238+ while (cin.fail () || x < 0 || x >(int )vec .size () - 1 ) {
198239
199240 cout << " repetir: " << endl;
200241 cin.clear ();
201242 cin.ignore (256 , ' \n ' );
202243 cin >> x;
203244 }
204- cout << " ok" << endl;
205245
206- // retransmite ventana por ndi
246+ cout << " ok " << endl;
207247 cout << " Broadcasting -------> " << vec[x] << " ... " << string (titles[x].begin (), titles[x].end ());
208248
209- // Not required, but "correct" (see the SDK documentation.
249+ // Not required, but "correct" (see the SDK documentation.)
210250 if (!NDIlib_initialize ())
211251 {
212252 // Cannot run NDI. Most likely because the CPU is not sufficient (see SDK documentation).
213253 // you can check this directly with a call to NDIlib_is_supported_CPU()
214254 printf (" Cannot run NDI." );
215255 return 0 ;
216256 }
257+
258+ // string sederName = string(titles[x].begin(), titles[x].end());
259+ const wchar_t * input = titles[x].c_str ();
260+
261+ /*
262+ // make name to the sender description
263+ size_t size = (wcslen(input) + 1) * sizeof(wchar_t);
264+ char* buffer = new char[size];
265+ size_t convertedsize;
266+ wcstombs_s(&convertedsize, buffer, size, input, size);
267+ //const char* sederName = (const char*)buffer;
268+ */
217269
218- string b = string (titles[x]. begin (), titles[x]. end ());
270+ // Broadcasting window to ndi
219271 SendWindow (vec[x], " __ndi" );
272+
273+ // delete buffer;
220274
221275 // Not required, but nice
222276 NDIlib_destroy ();
0 commit comments