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

Posted

技术标签:

【中文标题】如何在不保存文件的情况下制作打印屏幕并将其发送到 FTP 服务器?我的工作代码将文件保存到硬盘【英文标题】:How to make and send a print screen to a FTP server without save the file? My working code save the files to HDD 【发布时间】:2017-01-13 22:53:34 【问题描述】:

在发表这篇文章之前,我搜索并尝试了 4 天,例如 https://www.codeproject.com/kb/gdi-plus/memimage.aspx,但我是编程新手。

这段代码(不是我的),制作了一个打印屏幕,保存到一个文件,然后被发送到一个 ftp 服务器。我想这样做而不将文件保存到硬盘,从内存到 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;

【问题讨论】:

【参考方案1】:

使用FtpOpenFile()InternetWriteFile() 代替FtpPutFile()。这在FtpPutFile() 文档中有明确说明:

FtpPutFile 是一个高级例程,它处理与在本地读取文件并将其存储在 FTP 服务器上相关的所有簿记和开销。 只需要发送文件数据或需要密切控制文件传输的应用程序应使用FtpOpenFileInternetWriteFile 函数

以及在 WinInet 的 FTP Sessions 文档中

要在 FTP 服务器上上传或放置文件,应用程序可以使用 FtpPutFileFtpOpenFile(以及 InternetWriteFileFtpPutFile 可以用于本地已经存在的文件,而FtpOpenFileInternetWriteFile 可以用于将数据写入 FTP 服务器上的文件。

Gdiplus::Bitmap 可以保存到 HDD 文件或IStream。您可以使用 使用CreateStreamOnHGlobal()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;

【讨论】:

感谢雷米的回复。现在我必须替换 result = FtpPutFile(inter, l_screen, l_ftpfile, FTP_TRANSFER_TYPE_BINARY, 0); InternetCloseHandle(inter);互联网关闭句柄(互联网);结果 = FtpOpenFile()(inter, l_screen, l_ftpfile, FTP_TRANSFER_TYPE_BINARY, 0); InternetWriteFile(inter); InternetCloseHandle(inter); InternetCloseHandle(internet); 你能告诉我我必须在我的代码中写哪些参数: InternetWriteFile( __in HINTERNET hFile, __in_bcount(dwNumberOfBytesToWrite) LPCVOID lpBuffer, __in DWORD dwNumberOfBytesToWrite, __out LPDWORD lpdwNumberOfBytesWritten ); 谢谢先生!我在代码的第一部分只有一个错误:SHCreateMemStream undefined。 @snowman 如果你阅读了我链接的文档,你需要在你的代码中使用#include <Shlwapi.h> 并链接到Shlwapi.lib 对不起,我是新手。我通过添加 #include #pragma comment(lib, "Shlwapi.lib") 来修复它但是现在我有一个未解决的外部:错误 9 错误 LNK2001:未解决的外部符号 "bool __cdecl saveFTP(wchar_t const *,wchar_t const *,wchar_t const *,wchar_t const *,wchar_t const *)" (?saveFTP@@YA_NPB_W0000@Z) D:\picsupload\main.obj

以上是关于如何在不保存文件的情况下制作打印屏幕并将其发送到 FTP 服务器?我的工作代码将文件保存到硬盘的主要内容,如果未能解决你的问题,请参考以下文章

如何在不将 csv 保存到磁盘的情况下将 csv 格式的数据从内存发送到数据库?

在不尝试打印的情况下验证 Postscript?

如何在不使用 Ruby 保存到磁盘的情况下生成 zip 文件?

如何在不唤醒 Android 屏幕的情况下发送通知

如何在不写入文件的情况下压缩流并将其上传到 Azure Blob 存储?

sed