我已经使用Peter Below的APIClipboard部门多年,但它不再适用于Unicode Delphi。
ClipboardAsString返回gobbledegook:
[HttpPost]
public async Task<IActionResult> Upload(IList<IFormFile> files)
{
foreach (IFormFile source in files)
{
string filename = ContentDispositionHeaderValue.Parse(source.ContentDisposition).FileName.Trim('"');
filename = this.EnsureCorrectFilename(filename);
using (FileStream output = System.IO.File.Create(this.GetPathAndFilename(filename)))
await source.CopyToAsync(output);
}
return this.RedirectToAction("Index");
}
private string EnsureCorrectFilename(string filename)
{
if (filename.Contains("\\"))
filename = filename.Substring(filename.LastIndexOf("\\") + 1);
return filename;
}
private string GetPathAndFilename(string filename)
{
return this.HostingEnvironment.WebRootPath + "\\files\\" + filename;
}
StringToClipboard仅复制第一个字符:
Procedure DataFromClipboard( fmt: DWORD; S: TStream );
Var
hMem: THandle;
pMem: Pointer;
datasize: DWORD;
Begin { DataFromClipboard }
Assert( Assigned( S ));
hMem := GetClipboardData( fmt );
If hMem <> 0 Then Begin
datasize := GlobalSize( hMem );
If datasize > 0 Then Begin
pMem := GlobalLock( hMem );
If pMem = Nil Then
raise EclipboardError.Create( eLockFailed );
try
S.WriteBuffer( pMem^, datasize );
finally
GlobalUnlock( hMem );
end;
End;
End;
End;
Procedure CopyDataFromClipboard( fmt: DWORD; S: TStream );
Begin { CopyDataFromClipboard }
Assert( Assigned( S ));
If OpenClipboard( 0 ) Then
try
DataFromClipboard( fmt , S );
finally
CloseClipboard;
end
Else
raise EclipboardError.Create( eCannotOpenClipboard );
End;
Function ClipboardAsString: String;
Const
nullchar: Char = #0;
Var
ms: TMemoryStream;
Begin { ClipboardAsString }
If not IsClipboardFormatAvailable( CF_TEXT ) Then
Result := EmptyStr
Else Begin
ms:= TMemoryStream.Create;
try
CopyDataFromClipboard( CF_TEXT , ms );
ms.Seek( 0, soFromEnd );
ms.WriteBuffer( nullChar, Sizeof( nullchar ));
Result := Pchar( ms.Memory );
finally
ms.Free;
end;
End;
End;
我已搜索但无法找到此单元的更新版本。有更多Unicode字符串经验的人是否知道解决此问题的最佳方法?
由于
答案 0 :(得分:5)
CF_TEXT
是Ansi,CF_UNICODETEXT
是Unicode。需要根据string
是Ansi还是Unicode来更新代码以使用适当的格式,例如:
Const
CFTextFmt = {$IFDEF UNICODE}CF_UNICODETEXT{$ELSE}CF_TEXT{$ENDIF};
Function ClipboardAsString: String;
Var
ms: TMemoryStream;
Begin { ClipboardAsString }
If not IsClipboardFormatAvailable( CFTextFmt ) Then
Result := EmptyStr
Else Begin
ms := TMemoryStream.Create;
try
CopyDataFromClipboard( CFTextFmt, ms );
SetString(Result, PChar(ms.Memory), ms.Size);
finally
ms.Free;
end;
End;
End;
Procedure StringToClipboard( Const S: String );
Begin
CopyDataToClipboard( CFTextFmt, PChar(S)^, (Length(S) + 1) * SizeOf(Char));
End;
或者,你可以使用VCL自己的TClipboard.AsText
属性,它会为你处理这些细节:
uses
Clipbrd;
Function ClipboardAsString: String;
Begin
Result := Clipboard.AsText;
End;
Procedure StringToClipboard( Const S: String );
Begin
Clipboard.AsText := S;
End;
据说,在旁注中,DataToClipboard()
有一些错误。它应该允许datasize
为0并且不要忽略它,否则无法存储空白数据(这是可取的)。它不需要使用GMEM_ZEROINIT
(不是错误,但是浪费了开销)。如果HGLOBAL
失败,则需要释放SetClipboardData()
:
Procedure DataToClipboard( fmt: DWORD; Const data; datasize: Integer );
Var
hMem: THandle;
pMem: Pointer;
Begin { DataToClipboard }
If datasize < 0 Then datasize := 0;
hMem := GlobalAlloc( GMEM_MOVEABLE or GMEM_SHARE, datasize );
If hMem = 0 Then
raise EclipboardError.Create( eSystemOutOfMemory );
Try
If datasize > 0 Then
Begin
pMem := GlobalLock( hMem );
If pMem = Nil Then
raise EclipboardError.Create( eLockFailed );
Try
Move( data, pMem^, datasize );
Finally
GlobalUnlock( hMem );
End;
End;
If SetClipboardData( fmt, hMem ) = 0 Then
raise EClipboarderror( eSetDataFailed );
Except
GlobalFree( hMem );
raise;
End;
End; { DataToClipboard }
当CopyDataToClipboard()
为True时,emptyClipboardFirst
中还有一个错误:
如果应用程序在hwnd设置为NULL的情况下调用OpenClipboard,则EmptyClipboard会将剪贴板所有者设置为NULL; 导致SetClipboardData失败。
因此,在清空剪贴板然后在其上放置新数据时,您必须将有效的非零HWND
传递给OpenClipboard()
。