如何在不保存文件的情况下制作打印屏幕并将其发送到 FTP 服务器?我的工作代码将文件保存到 HDD

How to make and send a print screen to a FTP server without save the file? My working code save the files to HDD

在制作这个 post 之前,我搜索并尝试了 4 天所有的东西,比如 https://www.codeproject.com/kb/gdi-plus/memimage.aspx,但我是编程新手。

此代码(不是我的)制作了一个打印屏幕,保存到一个文件,然后发送到 ftp 服务器。我想这样做而不将文件保存到 HDD,从内存到 FTP。

// The print-screen and save to file (jpg) code:

wstring wtmp;
tmp =   sDate + pictureName + ".jpeg";
wtmp = ToStringW(tmp);
screenName = wtmp.c_str();
ftpScreenName = wtmp.c_str();
fileToRemove = tmp.c_str();
using namespace Gdiplus;
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;

GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
{
HDC scrdc, memdc;
HBITMAP membit;
scrdc = ::GetDC(0);
int Height = GetSystemMetrics(SM_CYSCREEN);
int Width = GetSystemMetrics(SM_CXSCREEN);
memdc = CreateCompatibleDC(scrdc);
membit = CreateCompatibleBitmap(scrdc, Width, Height);
HBITMAP hOldBitmap = (HBITMAP)SelectObject(memdc, membit);
BitBlt(memdc, 0, 0, Width, Height, scrdc, 0, 0, SRCCOPY);
Gdiplus::Bitmap bitmap(membit, NULL);

EncoderParameters encoderParameters;
ULONG quality;

CLSID clsid;
GetEncoderClsid(L"image/jpeg", &clsid);
encoderParameters.Count = 1;
encoderParameters.Parameter[0].Guid = EncoderQuality;
encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong;
encoderParameters.Parameter[0].NumberOfValues = 1;

// Save the image as a JPEG with quality level 80.
quality = 80;
encoderParameters.Parameter[0].Value = &quality;

int result;
result = bitmap.Save(screenName, &clsid); //saving the file to HDD

//send to ftp with given info
saveFTP(server, user, password, ftpScreenName, screenName);
}
GdiplusShutdown(gdiplusToken);

// 这里是 FTP 客户端部分:

bool saveFTP(LPCWSTR l_server, LPCWSTR l_user, LPCWSTR l_pass, LPCWSTR l_ftpfile, LPCWSTR l_screen)
{
HINTERNET internet = InternetOpen(L"tester", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, INTERNET_FLAG_ASYNC);
HINTERNET inter = InternetConnect(internet, l_server, INTERNET_DEFAULT_FTP_PORT, l_user, l_pass, INTERNET_SERVICE_FTP, 0, 0);
bool result;
result = FtpPutFile(inter, l_screen, l_ftpfile, FTP_TRANSFER_TYPE_BINARY, 0);
InternetCloseHandle(inter);
InternetCloseHandle(internet);
return result;
}

使用FtpOpenFile() and InternetWriteFile() instead of FtpPutFile(). This is explicitly stated in the FtpPutFile()文档:

FtpPutFile is a high-level routine that handles all the bookkeeping and overhead associated with reading a file locally and storing it on an FTP server. An application that needs to send file data only, or that requires close control over the file transfer, should use the FtpOpenFile and InternetWriteFile functions.

以及 WinInet 的 FTP Sessions 文档

To upload or place files on an FTP server, the application can use either FtpPutFile or FtpOpenFile (along with InternetWriteFile). FtpPutFile can be used if the file already exists locally, while FtpOpenFile and InternetWriteFile can be used if data needs to be written to a file on the FTP server.

Gdiplus::Bitmap 可以保存到 HDD 文件或 IStream。您可以使用 CreateStreamOnHGlobal() or SHCreateMemStream() 创建内存流,然后将 Bitmap 保存到流中,最后使用 FtpOpenFile()InternetWriteFile().

上传流的内容

例如(为简洁起见省略了错误处理,请不要在您的实际代码中省略它!):

tmp = sDate + pictureName + ".jpeg";
wstring wtmp = ToStringW(tmp);
IStream *strm = SHCreateMemStream(NULL, 0);

using namespace Gdiplus;

GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

CLSID clsid;
GetEncoderClsid(L"image/jpeg", &clsid);
EncoderParameters encoderParameters;
encoderParameters.Count = 1;
encoderParameters.Parameter[0].Guid = EncoderQuality;
encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong;
encoderParameters.Parameter[0].NumberOfValues = 1;

// Save the image as a JPEG with quality level 80.
ULONG quality = 80;
encoderParameters.Parameter[0].Value = &quality;

HDC scrdc = ::GetDC(0);
int Height = GetSystemMetrics(SM_CYSCREEN);
int Width = GetSystemMetrics(SM_CXSCREEN);
HDC memdc = CreateCompatibleDC(scrdc);
HBITMAP membit = CreateCompatibleBitmap(scrdc, Width, Height);
HBITMAP hOldBitmap = (HBITMAP) SelectObject(memdc, membit);
BitBlt(memdc, 0, 0, Width, Height, scrdc, 0, 0, SRCCOPY);

{
Gdiplus::Bitmap bitmap(membit, NULL);
bitmap.Save(strm, &clsid); //saving the file to HDD
}

SelectObject(memdc, hOldBitmap);
DeleteObject(membit);
DeleteDC(memdc);
::ReleaseDC(0, scrdc);

GdiplusShutdown(gdiplusToken);

LARGE_INTEGER li;
li.QuadPart = 0;
strm->Seek(li, STREAM_SEEK_SET, NULL);

//send to ftp with given info
saveFTP(server, user, password, wtmp.c_str(), strm);
strm->Release();

bool saveFTP(LPCWSTR l_server, LPCWSTR l_user, LPCWSTR l_pass, LPCWSTR l_ftpfile, IStream *l_screen)
{
    HINTERNET internet = InternetOpen(L"tester", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, INTERNET_FLAG_ASYNC);
    HINTERNET conn = InternetConnect(internet, l_server, INTERNET_DEFAULT_FTP_PORT, l_user, l_pass, INTERNET_SERVICE_FTP, 0, 0);
    HINTERNET file = FtpOpenFile(conn, l_ftpfile, GENERIC_WRITE, FTP_TRANSFER_TYPE_BINARY, 0);

    BYTE buffer[1024], *pbuf;
    ULONG ulRead;
    DWORD dwWritten;
    HRESULT hr;
    bool success = true;

    do
    {
        hr = l_screen->Read(buffer, sizeof(buffer), &ulRead);
        if (FAILED(hr))
        {
            success = false;
            break;
        }

        pbuf = buffer;
        while (ulRead != 0)
        {
            if (!InternetWriteFile(file, pbuf, ulRead, &dwWritten))
            {
                success = false;
                break;
            }
            pbuf += dwWritten;
            ulRead -= dwWritten;
        }
    }
    while (hr == S_OK);

    InternetCloseHandle(file);
    InternetCloseHandle(conn);
    InternetCloseHandle(internet);

    return success;
}