ADDED .fossil-settings/encoding-glob Index: .fossil-settings/encoding-glob ================================================================== --- /dev/null +++ .fossil-settings/encoding-glob @@ -0,0 +1,1 @@ +* Index: .fossil-settings/ignore-glob ================================================================== --- .fossil-settings/ignore-glob +++ .fossil-settings/ignore-glob @@ -1,15 +1,14 @@ */__history/* +*/__recovery/* out/ -*.dcu -*.exe *.local *.identcache *.dsk *.stat +*.tvsconfig ~*.* *.~* *.bak *.rej *.org *.res -*/__recover/* ADDED src/Debug.pas Index: src/Debug.pas ================================================================== --- /dev/null +++ src/Debug.pas @@ -0,0 +1,43 @@ +unit Debug; + +interface + +procedure ODS(const DebugOutput: string); overload; +procedure ODS(const DebugOutput: string; const Args: array of const); overload; + +implementation +uses + Classes, SysUtils, + Windows, + L_SpecialFolders; + +var + OutputLog: TStreamWriter; + +{ ------------------------------------------------------------------------------------------------ } +procedure ODS(const DebugOutput: string); overload; +begin + OutputDebugString(PChar('PreviewHTML['+IntToHex(GetCurrentThreadId, 4)+']: ' + DebugOutput)); + {$IFDEF DEBUG} + if OutputLog = nil then begin + OutputLog := TStreamWriter.Create(TFileStream.Create(ChangeFileExt(TSpecialFolders.DLLFullName, '.log'), fmCreate or fmShareDenyWrite), TEncoding.UTF8); + OutputLog.OwnStream; + OutputLog.BaseStream.Seek(0, soFromEnd); + end; + OutputLog.Write(FormatDateTime('yyyy-MM-dd hh:nn:ss.zzz: ', Now)); + OutputLog.WriteLine(DebugOutput.Replace(#10, #10 + StringOfChar(' ', 25))); + {$ENDIF} +end {ODS}; +{ ------------------------------------------------------------------------------------------------ } +procedure ODS(const DebugOutput: string; const Args: array of const); overload; +begin + ODS(Format(DebugOutput, Args)); +end{ODS}; + + +initialization + +finalization + OutputLog.Free; + +end. Index: src/F_PreviewHTML.pas ================================================================== --- src/F_PreviewHTML.pas +++ src/F_PreviewHTML.pas @@ -68,43 +68,21 @@ end; var frmHTMLPreview: TfrmHTMLPreview; -procedure ODS(const DebugOutput: string); overload; -procedure ODS(const DebugOutput: string; const Args: array of const); overload; - //////////////////////////////////////////////////////////////////////////////////////////////////// implementation uses ShellAPI, ComObj, StrUtils, IOUtils, Masks, MSHTML, RegExpr, L_SpecialFolders, - WebBrowser, SciSupport, U_Npp_PreviewHTML; + WebBrowser, SciSupport, + Debug, + U_Npp_PreviewHTML; {$R *.dfm} -var - OutputLog: TStreamWriter; - -{ ------------------------------------------------------------------------------------------------ } -procedure ODS(const DebugOutput: string); overload; -begin - OutputDebugString(PChar('PreviewHTML['+IntToHex(GetCurrentThreadId, 4)+']: ' + DebugOutput)); - if OutputLog = nil then begin - OutputLog := TStreamWriter.Create(TFileStream.Create(ChangeFileExt(TSpecialFolders.DLLFullName, '.log'), fmCreate or fmShareDenyWrite), TEncoding.UTF8); - OutputLog.OwnStream; - OutputLog.BaseStream.Seek(0, soFromEnd); - end; - OutputLog.Write(FormatDateTime('yyyy-MM-dd hh:nn:ss.zzz: ', Now)); - OutputLog.WriteLine(DebugOutput); -end {ODS}; -{ ------------------------------------------------------------------------------------------------ } -procedure ODS(const DebugOutput: string; const Args: array of const); overload; -begin - ODS(Format(DebugOutput, Args)); -end{ODS}; - { ================================================================================================ } { ------------------------------------------------------------------------------------------------ } procedure TfrmHTMLPreview.FormCreate(Sender: TObject); @@ -719,11 +697,6 @@ inherited; self.UpdateDisplayInfo(StringReplace(Text, 'about:blank', '', [rfReplaceAll])); end; -initialization - -finalization - OutputLog.Free; - end. ADDED src/U_AutoUpdate.pas Index: src/U_AutoUpdate.pas ================================================================== --- /dev/null +++ src/U_AutoUpdate.pas @@ -0,0 +1,254 @@ +unit U_AutoUpdate; + +interface + +uses + SysUtils; + +type + TPluginUpdate = class + private + FURL: string; +// FOnProgress: TProgressEvent; // TODO: see L_HttpClient + FLatestVersion: string; + + function GetCurrentVersion: string; + function GetLatestVersion: string; + public + constructor Create{(const AURL: string)}; + + function IsUpdateAvailable(out NewVersion, Changes: string): Boolean; + function DownloadUpdate: string; + function ReplacePlugin(const PathDownloaded: string): Boolean; + + property URL: string read FURL; + + property CurrentVersion: string read GetCurrentVersion; + property LatestVersion: string read GetLatestVersion; + public + class function CompareVersions(const VersionA, VersionB: string): Integer; + end; + + EUpdateError = class(Exception); + +implementation +uses + Classes, RegularExpressions, Windows, NetEncoding, Zip, + L_HttpClient, L_VersionInfoW, L_SpecialFolders, + Debug; + +{ ------------------------------------------------------------------------------------------------ } +{ TPluginUpdate } + +{ ------------------------------------------------------------------------------------------------ } +constructor TPluginUpdate.Create; +begin + //FURL := AURL; +end {TPluginUpdate.Create}; + +{ ------------------------------------------------------------------------------------------------ } +function TPluginUpdate.GetCurrentVersion: string; +begin + with TFileVersionInfo.Create(TSpecialFolders.DLLFullName) do begin + Result := FileVersion; + Free; + end; +end {TPluginUpdate.GetCurrentVersion}; + +{ ------------------------------------------------------------------------------------------------ } +function TPluginUpdate.GetLatestVersion: string; +begin + // TODO +end {TPluginUpdate.GetLatestVersion}; + +{ ------------------------------------------------------------------------------------------------ } +function TPluginUpdate.IsUpdateAvailable(out NewVersion, Changes: string): Boolean; +var + Http: THttpClient; + Notes: string; + Matches: TMatchCollection; + Match: TMatch; + s: string; + FirstPos, LastPos: Integer; +begin + // Download the current release notes + ODS('Create HttpClient'); + Http := THttpClient.Create('http://fossil.2of4.net/npp_preview/doc/publish/ReleaseNotes.txt'); + try + ODS('Http.Get'); + if Http.Get() = 200 then begin + ODS('%d %s', [Http.StatusCode, Http.StatusText]); + for s in Http.ResponseHeaders do + ODS(s); + // get the response stream, and look for the latest version in there + Notes := Http.ResponseString; + ODS('Response: "%s"', [Copy(StringReplace(StringReplace(Notes, #10, '·', [rfReplaceAll]), #13, '·', [rfReplaceAll]), 1, 250)]); + + NewVersion := ''; + FirstPos := -1; + LastPos := -1; + + Matches := TRegEx.Matches(Notes, 'v[0-9]+(\.[0-9]+){3}'); + ODS('Matches: %d', [Matches.Count]); + for Match in Matches do begin + ODS('Match: Success=%s; Value="%s"; Index=%d', [BoolToStr(Match.Success, True), Match.Value, Match.Index]); + if NewVersion = '' then + NewVersion := Match.Value; + if FirstPos = -1 then + FirstPos := Match.Index; + if CompareVersions(CurrentVersion, Match.Value) <= 0 then begin + // This version is equal or older than the current version + LastPos := Match.Index; + Break; + end; + end {for}; + + if FirstPos = -1 then + FirstPos := Notes.IndexOf('
') + 5;
+      if (LastPos = -1) or (LastPos = FirstPos) then
+        LastPos := Notes.IndexOf('
'); + + Changes := Notes.Substring(FirstPos - 1, LastPos - FirstPos); + ODS('NewVersion: "%s"; Changes: "%s"', [NewVersion, Changes]); + + Changes := TNetEncoding.HTML.Decode(Changes.Trim); + end else begin + // TODO: show message, open project's main page? + raise EUpdateError.CreateFmt('%d %s', [Http.StatusCode, Http.StatusText]); + end; + finally + Http.Free; + end; + + Result := CompareVersions(CurrentVersion, NewVersion) > 0; + + FLatestVersion := NewVersion; +end {TPluginUpdate.IsUpdateAvailable}; + +{ ------------------------------------------------------------------------------------------------ } +function TPluginUpdate.DownloadUpdate: string; +var + Http: THttpClient; + FS: TFileStream; +begin + // TODO: Download http://fossil.2of4.net/npp_preview/zip/Preview_Plugin.zip?uuid=publish&name=plugins to a temp dir, + // extract it to a custom temp folder, and return that folder's path + Http := THttpClient.Create('http://fossil.2of4.net/npp_preview/zip/Preview_Plugin.zip?uuid=publish&name=plugins'); + try + if Http.Get() = 200 then begin + Result := TSpecialFolders.TempDll + 'Preview_Plugin.zip'; + FS := TFileStream.Create(Result, fmCreate or fmShareDenyWrite); + try + FS.CopyFrom(Http.ResponseStream, 0); + finally + FS.Free; + end; + end else begin + // TODO: show message, open project's main page? + raise EUpdateError.CreateFmt('%d %s', [Http.StatusCode, Http.StatusText]); + end; + finally + Http.Free; + end; +end {TPluginUpdate.DownloadUpdate}; + +{ ------------------------------------------------------------------------------------------------ } +function TPluginUpdate.ReplacePlugin(const PathDownloaded: string): Boolean; +var + NppDir: string; + Zip: TZipFile; + i: Integer; + Info: TZipHeader; + Name: string; + Backup: string; +begin + NppDir := TSpecialFolders.DLL + '..\'; + + Zip := TZipFile.Create; + try + ODS(PathDownloaded); + Zip.Open(PathDownloaded, zmRead); + for i := 0 to Zip.FileCount - 1 do begin + Info := Zip.FileInfo[i]; + Name := Zip.FileName[i].Replace('/', '\'); + ODS(Name); + + if Name.EndsWith('\') then Continue; // Skip directories + + if SameFileName(ExtractFileName(Name), 'ReleaseNotes.txt') then begin + Name := Name.Replace('ReleaseNotes.txt', 'Doc\PreviewHTML\ReleaseNotes.txt', [rfIgnoreCase]); + ODS('=> ' + Name); + end; + + if FileExists(NppDir + Name) then begin + Backup := NppDir + ChangeFileExt(Name, '-' + CurrentVersion + ExtractFileExt(Name)); + if SameFileName(ExtractFileExt(Name), '.dll') then begin + Backup := ChangeFileExt(Backup, '.~' + ExtractFileExt(Backup).Substring(1)); + ODS('Backup: ' + Backup); + Win32Check(RenameFile(NppDir + Name, Backup)); + end else begin + ODS('Backup: ' + Backup); + Win32Check(CopyFile(PChar(NppDir + Name), PChar(Backup), False)); + end; + end; + + ODS('Extracting file to: ' + NppDir + Name); + ForceDirectories(ExtractFileDir(NppDir + Name)); + Zip.Extract(i, ExtractFileDir(NppDir + Name), False); + end {for}; + finally + Zip.Free; + end; + + // TODO: Rename the current DLL to ChangeFileExt(DllName, '-' + OwnVersion + '.~dll') + // HardlinkOrCopy all files in extract location to path relative to plugins folder. ./Config should + // be translated to PluginsConfigFolder. ReleaseNotes.txt gets special treatment: it's in the + // root folder, but should be moved to ./Doc/PreviewHTML. + Result := True; +end {TPluginUpdate.ReplacePlugin}; + +{ ------------------------------------------------------------------------------------------------ } +class function TPluginUpdate.CompareVersions(const VersionA, VersionB: string): Integer; +var + va, vb: string; + na, nb: Integer; + Code: Integer; +begin + Result := 0; + if (VersionA = '') or (VersionB = '') then + Exit; + + if VersionA[1] = 'v' then va := Copy(VersionA, 2) else va := VersionA; + if VersionB[1] = 'v' then vb := Copy(VersionB, 2) else vb := VersionB; + + repeat + na := 0; + if va <> '' then begin +//ODS('va: "%s"; na: %d', [va, na]); + Val(va, na, Code); +//ODS('va: "%s"; na: %d; Code: %d', [va, na, Code]); + if Code in [0, 1] then + va := '' + else + va := Copy(va, Code + 1); + end; + + nb := 0; + if vb <> '' then begin +//ODS('vb: "%s"; nb: %d', [vb, nb]); + Val(vb, nb, Code); +//ODS('vb: "%s"; nb: %d; Code: %d', [vb, nb, Code]); + if Code in [0, 1] then + vb := '' + else + vb := Copy(vb, Code + 1); + end; + + Result := nb - na; +//ODS('Result = %d := %d - %d', [Result, nb, na]); + if Result <> 0 then + Exit; + until (va = '') and (vb = ''); +end {TPluginUpdate.CompareVersions}; + +end. Index: src/U_CustomFilter.pas ================================================================== --- src/U_CustomFilter.pas +++ src/U_CustomFilter.pas @@ -36,10 +36,11 @@ implementation uses IOUtils, process, Pipes, + Debug, F_PreviewHTML; { TCustomFilterThread } { ------------------------------------------------------------------------------------------------ } Index: src/U_Npp_PreviewHTML.pas ================================================================== --- src/U_Npp_PreviewHTML.pas +++ src/U_Npp_PreviewHTML.pas @@ -10,30 +10,31 @@ type TNppPluginPreviewHTML = class(TNppPlugin) private FSettings: TIniFile; + FUpdated: Boolean; public constructor Create; procedure SetInfo(NppData: TNppData); override; procedure CommandShowPreview; procedure CommandSetIEVersion(const BrowserEmulation: Integer); procedure CommandOpenFile(const Filename: nppString); + procedure CommandCheckUpdates; procedure CommandShowAbout; - procedure CommandReplaceHelloWorld; procedure DoNppnToolbarModification; override; - procedure DoNppnFileClosed(const BufferID: Cardinal); override; - procedure DoNppnBufferActivated(const BufferID: Cardinal); override; + procedure DoNppnFileClosed(const BufferID: THandle); override; + procedure DoNppnBufferActivated(const BufferID: THandle); override; procedure DoModified(const hwnd: HWND; const modificationType: Integer); override; function GetSettings(const Name: string = 'Settings.ini'): TIniFile; end {TNppPluginPreviewHTML}; -procedure _FuncReplaceHelloWorld; cdecl; +procedure _FuncCheckUpdate; cdecl; procedure _FuncShowPreview; cdecl; procedure _FuncOpenSettings; cdecl; procedure _FuncOpenFilters; cdecl; procedure _FuncShowAbout; cdecl; @@ -50,16 +51,17 @@ Npp: TNppPluginPreviewHTML; //////////////////////////////////////////////////////////////////////////////////////////////////// implementation uses - WebBrowser, Registry; + WebBrowser, Registry, + U_AutoUpdate; { ------------------------------------------------------------------------------------------------ } -procedure _FuncReplaceHelloWorld; cdecl; +procedure _FuncCheckUpdate; cdecl; begin - Npp.CommandReplaceHelloWorld; + Npp.CommandCheckUpdates; end; { ------------------------------------------------------------------------------------------------ } procedure _FuncOpenSettings; cdecl; begin Npp.CommandOpenFile('Settings.ini'); @@ -172,13 +174,67 @@ self.AddFuncItem('Edit &settings', _FuncOpenSettings); self.AddFuncItem('Edit &filter definitions', _FuncOpenFilters); self.AddFuncSeparator; + + self.AddFuncItem('Check for &updates', _FuncCheckUpdate); + + self.AddFuncSeparator; self.AddFuncItem('&About', _FuncShowAbout); end {TNppPluginPreviewHTML.SetInfo}; + +{ ------------------------------------------------------------------------------------------------ } +procedure TNppPluginPreviewHTML.CommandCheckUpdates; +const + scYesNo: array[Boolean] of string = ('No', 'Yes'); +var + Current, Latest, Notes: string; + Update: TPluginUpdate; + ZipPath: string; +begin + try + if FUpdated then begin + MessageBox(Npp.NppData.NppHandle, 'Please restart Notepad++ first!', PChar(Caption), MB_ICONWARNING); + Exit; + end; + + Update := TPluginUpdate.Create; + try + Current := Update.CurrentVersion; + if not Update.IsUpdateAvailable(Latest, Notes) then begin + MessageBox(Npp.NppData.NppHandle, + PChar(Format('Nothing to update!'#10#10'Your current version of this plugin, v%s, is the most recent one.', + [Current])), PChar(Caption), + MB_ICONINFORMATION); + Exit; + end; + + if ID_YES = MessageBox(Npp.NppData.NppHandle, + PChar(Format('Update available!'#10#10 + + 'Your current version of this plugin, v%0:s, is out of date.' + + ' We recommend you update to version %1:s.'#10#10 + + 'These are the changes since the current version:'#10#10 + + '%2:s'#10#10 + + 'Do you want to download and install %1:s?', + [Current, Latest, Notes])), + PChar(Caption), MB_YESNO or MB_DEFBUTTON1 or MB_ICONQUESTION) then begin + ZipPath := Update.DownloadUpdate; + FUpdated := Update.ReplacePlugin(ZipPath); + if FUpdated then + MessageBox(Npp.NppData.NppHandle, + 'Update completed. Please restart Notepad++ to use the updated plugin.', + PChar(Caption), MB_ICONINFORMATION); + end; + finally + Update.Free; + end; + except + ShowException(ExceptObject, ExceptAddr); + end; +end {TNppPluginPreviewHTML.CommandCheckUpdate}; { ------------------------------------------------------------------------------------------------ } procedure TNppPluginPreviewHTML.CommandOpenFile(const Filename: nppString); var FullPath: nppString; @@ -192,19 +248,10 @@ except ShowException(ExceptObject, ExceptAddr); end; end {TNppPluginPreviewHTML.CommandOpenFilters}; -{ ------------------------------------------------------------------------------------------------ } -procedure TNppPluginPreviewHTML.CommandReplaceHelloWorld; -var - s: UTF8String; -begin - s := 'Hello World'; - SendMessage(self.NppData.ScintillaMainHandle, SCI_REPLACESEL, 0, LPARAM(PAnsiChar(s))); -end {TNppPluginPreviewHTML.CommandReplaceHelloWorld}; - { ------------------------------------------------------------------------------------------------ } procedure TNppPluginPreviewHTML.CommandSetIEVersion(const BrowserEmulation: Integer); begin if GetBrowserEmulation <> BrowserEmulation then begin SetBrowserEmulation(BrowserEmulation); @@ -270,20 +317,20 @@ // SendMessage(self.NppData.ScintillaMainHandle, SCI_SETMODEVENTMASK, SC_MOD_INSERTTEXT or SC_MOD_DELETETEXT, 0); // SendMessage(self.NppData.ScintillaSecondHandle, SCI_SETMODEVENTMASK, SC_MOD_INSERTTEXT or SC_MOD_DELETETEXT, 0); end {TNppPluginPreviewHTML.DoNppnToolbarModification}; { ------------------------------------------------------------------------------------------------ } -procedure TNppPluginPreviewHTML.DoNppnBufferActivated(const BufferID: Cardinal); +procedure TNppPluginPreviewHTML.DoNppnBufferActivated(const BufferID: THandle); begin inherited; if Assigned(frmHTMLPreview) and frmHTMLPreview.Visible then begin frmHTMLPreview.btnRefresh.Click; end; end {TNppPluginPreviewHTML.DoNppnBufferActivated}; { ------------------------------------------------------------------------------------------------ } -procedure TNppPluginPreviewHTML.DoNppnFileClosed(const BufferID: Cardinal); +procedure TNppPluginPreviewHTML.DoNppnFileClosed(const BufferID: THandle); begin if Assigned(frmHTMLPreview) then begin frmHTMLPreview.ForgetBuffer(BufferID); end; inherited; ADDED src/common/L_HttpClient.pas Index: src/common/L_HttpClient.pas ================================================================== --- /dev/null +++ src/common/L_HttpClient.pas @@ -0,0 +1,490 @@ +unit L_HttpClient; + +interface +uses + SysUtils, Classes, WinInet; + +type + THttpConnectEnum = ( + hcDirect = INTERNET_OPEN_TYPE_DIRECT, + hcPreconfig = INTERNET_OPEN_TYPE_PRECONFIG, + hcPreconfigNoAuto = INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY, + hcProxy = INTERNET_OPEN_TYPE_PROXY + ); + + THttpClient = class; + TProgressNotify = procedure(Sender: THttpClient; Msg: string; BytesRead, TotalBytes: Cardinal; out Cancel: Boolean) of object; + + THttpClient = class + private + FhReq: HINTERNET; + FOnProgress: TProgressNotify; + FURL: string; + + function SendRequestAndGetResponse(const Verb, Resource: string; + const Data: Pointer; const DataSize: Cardinal; + Flags: Cardinal = 0): integer; + procedure ReadResponseHeaders; + protected + FPath: string; + FRequestHeaders: TStringList; + FResponseStatus: cardinal; + FResponseStatusText: string; + FResponseHeaders: TStringList; + FResponseStream: TMemoryStream; + + function QueryInfoString(const InfoFlag: cardinal): string; overload; inline; + function QueryInfoString(const InfoFlag: cardinal; out Value: string): boolean; overload; + function QueryInfoInteger(const InfoFlag: cardinal): cardinal; overload; inline; + function QueryInfoInteger(const InfoFlag: cardinal; out Value: cardinal): Boolean; overload; inline; + + function GetResponseString: string; // RawString + public + UserAgent: string; + Hostname: string; + Port: integer; + UseProxy: THttpConnectEnum; + Proxy, ProxyByPass: string; + UserName: string; + Password: string; + ConnectTimeout, SendTimeout, ReceiveTimeout: Cardinal; + + constructor Create(const URL: string); overload; + constructor Create(const Hostname, Path: string; const Port: integer = INTERNET_DEFAULT_HTTP_PORT); overload; + destructor Destroy; override; + + function Head(Path: string = ''; const BypassCache: Boolean = False): integer; + function Get(Path: string = ''; const BypassCache: Boolean = False): integer; + function Post(Data: string): integer; overload; + function Post(Data: TStream): integer; overload; + function Post(Path: string; Data: string): integer; overload; + function Post(Path: string; Data: TStream): integer; overload; + + property Path: string read FPath; + property RequestHeaders: TStringList read FRequestHeaders; + property StatusCode: cardinal read FResponseStatus; + property StatusText: string read FResponseStatusText; + property ResponseHeaders: TStringList read FResponseHeaders; + property ResponseStream: TMemoryStream read FResponseStream; + property ResponseString: string read GetResponseString; // RawString + property URL: string read FURL; + + property OnProgress: TProgressNotify read FOnProgress write FOnProgress; + end; + +type + EHttpError = class(Exception); + + +implementation +uses + Windows, Math; + +const + READBUFFERSIZE = 4096; + ERROR_INSUFFICIENT_BUFFER = 122; { dderror } + +resourcestring + scConnecting = 'Connecting'; + scUploading = 'Sending'; + scDownloading = 'Receiving'; + scFinished = 'Done'; + +{ ================================================================================================ } +{ THttpClient } + +{ ------------------------------------------------------------------------------------------------ } +constructor THttpClient.Create(const URL: string); +var + UC: URL_COMPONENTS; +begin + UC.dwStructSize := sizeof(UC); + UC.lpszScheme := nil; + UC.dwSchemeLength := 0; + UC.nScheme := INTERNET_SCHEME_UNKNOWN; + UC.lpszHostName := PChar(StringOfChar(#0, Length(URL) + 1)); + UC.dwHostNameLength := Length(URL) + 1; + UC.nPort := INTERNET_INVALID_PORT_NUMBER; + UC.lpszUserName := PChar(StringOfChar(#0, Length(URL) + 1)); + UC.dwUserNameLength := Length(URL) + 1; + UC.lpszPassword := PChar(StringOfChar(#0, Length(URL) + 1)); + UC.dwPasswordLength := Length(URL) + 1; + UC.lpszUrlPath := PChar(StringOfChar(#0, Length(URL) + 1)); + UC.dwUrlPathLength := Length(URL) + 1; + UC.lpszExtraInfo := nil; + UC.dwExtraInfoLength := 0; + + Win32Check(InternetCrackUrl(PChar(URL), 0, 0, UC)); + if not UC.nScheme in [INTERNET_SCHEME_HTTP, INTERNET_SCHEME_HTTPS, INTERNET_SCHEME_FILE] then begin + raise EHttpError.CreateFmt('Unsupported scheme used in URL "%s". Only http:// and https:// are supported', [URL]); + end; + Create(UC.lpszHostName, UC.lpszUrlPath, UC.nPort); + Self.UserName := UC.lpszUserName; + Self.Password := UC.lpszPassword; +end {THttpClient.Create}; +{ ------------------------------------------------------------------------------------------------ } +constructor THttpClient.Create(const Hostname, Path: string; const Port: integer); +var + UC: URL_COMPONENTS; + Buffer: string; + Size: Cardinal; +begin + FPath := Path; + Self.UserAgent := ChangeFileExt(ExtractFileName(ParamStr(0)), ''); + Self.Hostname := Hostname; + Self.Port := Port; + Self.UseProxy := hcPreconfig; + FRequestHeaders := TStringList.Create; + FRequestHeaders.NameValueSeparator := ':'; + ConnectTimeout := 0; + SendTimeout := 0; + ReceiveTimeout := 0; + + Size := INTERNET_MAX_URL_LENGTH; + SetLength(Buffer, Size); + if InternetCreateUrl(UC, ICU_ESCAPE, PChar(Buffer), Size) then begin + FURL := Copy(Buffer, 1, Size); + end else if GetLastError = ERROR_INSUFFICIENT_BUFFER then begin + SetLength(Buffer, Size); + if InternetCreateUrl(UC, ICU_ESCAPE, PChar(Buffer), Size) then begin + FURL := Copy(Buffer, 1, Size); + end; + end; +end {THttpClient.Create}; +{ ------------------------------------------------------------------------------------------------ } +destructor THttpClient.Destroy; +begin + if Assigned(FResponseStream) then FreeAndNil(FResponseStream); + if Assigned(FResponseHeaders) then FreeAndNil(FResponseHeaders); + FRequestHeaders.Free; + inherited; +end {THttpClient.Destroy}; + +{ ------------------------------------------------------------------------------------------------ } +function THttpClient.Head(Path: string = ''; const BypassCache: Boolean = False): integer; +begin + if Path = '' then begin + Path := FPath; + end; + if BypassCache then begin + Result := SendRequestAndGetResponse('HEAD', Path, nil, 0, INTERNET_FLAG_RELOAD); + end else begin + Result := SendRequestAndGetResponse('HEAD', Path, nil, 0); + end; +end {THttpClient.Head}; + +{ ------------------------------------------------------------------------------------------------ } +function THttpClient.Get(Path: string = ''; const BypassCache: Boolean = False): integer; +begin + if Path = '' then begin + Path := FPath; + end; + if BypassCache then begin + Result := SendRequestAndGetResponse('GET', Path, nil, 0, INTERNET_FLAG_RELOAD); + end else begin + Result := SendRequestAndGetResponse('GET', Path, nil, 0); + end; +end {THttpClient.Get}; + +{ ------------------------------------------------------------------------------------------------ } +function THttpClient.Post(Data: TStream): integer; +begin + Result := Self.Post(FPath, Data); +end {THttpClient.Post}; +{ ------------------------------------------------------------------------------------------------ } +function THttpClient.Post(Path: string; Data: TStream): integer; +var + MemData: TMemoryStream; + CleanUp: boolean; +begin + if Data is TMemoryStream then begin + MemData := TMemoryStream(Data); + CleanUp := False; + end else begin + Data.Position := 0; + MemData := TMemoryStream.Create; + MemData.CopyFrom(Data, Data.Size); + CleanUp := True; + end; + try + Result := SendRequestAndGetResponse('POST', Path, MemData.Memory, MemData.Size); + finally + if CleanUp then begin + MemData.Free; + end; + end; +end {THttpClient.Post}; +{ ------------------------------------------------------------------------------------------------ } +function THttpClient.Post(Data: string): integer; +begin + Result := Self.Post(FPath, Data); +end {THttpClient.Post}; +{ ------------------------------------------------------------------------------------------------ } +function THttpClient.Post(Path: string; Data: string): integer; +begin + Result := SendRequestAndGetResponse('POST', Path, PChar(Data), ByteLength(Data)); +end {THttpClient.Post}; + +{ ------------------------------------------------------------------------------------------------ } +function THttpClient.SendRequestAndGetResponse(const Verb, Resource: string; + const Data: Pointer; + const DataSize: Cardinal; + Flags: Cardinal = 0): integer; +var + hInt, hConn: HINTERNET; + PProxy, PProxyBypass, PUserName, PPassword: PChar; + BytesRead, TotalBytesToRead, TotalBytesRead: Cardinal; + Buffer: TMemoryStream; + Size: Cardinal; + Cancel: Boolean; +begin + Result := 0; // means the request has been canceled + + FPath := Resource; + + { Initialize the response data } + FResponseStatus := 0; + FResponseStatusText := ''; + if Assigned(FResponseHeaders) then FreeAndNil(FResponseHeaders); + if Assigned(FResponseStream) then FreeAndNil(FResponseStream); + + { Set the proxy parameters } + if UseProxy = hcProxy then begin + if Length(Self.Proxy) = 0 then begin + PProxy := nil; + end else begin + PProxy := PChar(Self.Proxy); + end; + if Length(Self.ProxyByPass) = 0 then begin + PProxyByPass := nil; + end else begin + PProxyByPass := PChar(Self.ProxyByPass); + end; + end else begin + PProxy := nil; + PProxyBypass := nil; + end; + + Cancel := False; + if Assigned(FOnProgress) then begin + FOnProgress(Self, scConnecting, 0, 0, Cancel); + if Cancel then + Exit; + end; + + { Open an internet handle and set the request parameters } + hInt := InternetOpen(PChar(UserAgent), Ord(UseProxy), PProxy, PProxyBypass, 0); + Win32Check(Assigned(hInt)); + try + if ConnectTimeout > 0 then InternetSetOption(hInt, INTERNET_OPTION_CONNECT_TIMEOUT, @ConnectTimeout, sizeof(ConnectTimeout)); + if SendTimeout > 0 then InternetSetOption(hInt, INTERNET_OPTION_SEND_TIMEOUT, @SendTimeout, sizeof(SendTimeout)); + if ReceiveTimeout > 0 then InternetSetOption(hInt, INTERNET_OPTION_RECEIVE_TIMEOUT, @ReceiveTimeout, sizeof(ReceiveTimeout)); + + if Length(Self.UserName) = 0 then begin + PUserName := nil; + end else begin + PUserName := PChar(Self.UserName); + end; + if Length(Self.Password) = 0 then begin + PPassword := nil; + end else begin + PPassword := PChar(Self.Password); + end; + + { Try to connect, then send the request } + hConn := InternetConnect(hInt, PChar(Hostname), Self.Port, PUserName, PPassword, INTERNET_SERVICE_HTTP, 0, 1); + Win32Check(Assigned(hConn)); + try + if Self.Port = INTERNET_DEFAULT_HTTPS_PORT then begin + Flags := Flags or INTERNET_FLAG_SECURE or INTERNET_FLAG_IGNORE_CERT_CN_INVALID or INTERNET_FLAG_IGNORE_CERT_DATE_INVALID; + end; + FhReq := HttpOpenRequest(hConn, PChar(Verb), PChar(Resource), nil, nil, nil, Flags, 1); + Win32Check(Assigned(FhReq)); + try + InternetQueryOption(FhReq, INTERNET_OPTION_URL, nil, Size); + FURL := StringOfChar(#0, Size); + Win32Check(InternetQueryOption(FhReq, INTERNET_OPTION_URL, PChar(FURL), Size)); + SetLength(FURL, Size); + + if Assigned(FOnProgress) then begin + FOnProgress(Self, scUploading, 0, 0, Cancel); + if Cancel then + Exit; + end; + + Win32Check(HttpSendRequest(FhReq, + PChar(FRequestHeaders.Text), Length(FRequestHeaders.Text), + Data, DataSize)); + + { Try to get the content-length } + if not QueryInfoInteger(HTTP_QUERY_CONTENT_LENGTH, TotalBytesToRead) then + TotalBytesToRead := 0; + + FResponseStream := TMemoryStream.Create; + Buffer := TMemoryStream.Create; + try + TotalBytesRead := 0; + Buffer.SetSize(READBUFFERSIZE); + repeat + Sleep(0); + if not InternetReadFile(FhReq, Buffer.Memory, READBUFFERSIZE, BytesRead) then begin + Break; + end; + if BytesRead > 0 then begin + Buffer.Position := 0; + FResponseStream.CopyFrom(Buffer, Min(BytesRead, READBUFFERSIZE)); + Inc(TotalBytesRead, BytesRead); + if Assigned(FOnProgress) then begin + FOnProgress(Self, scDownloading, TotalBytesRead, TotalBytesToRead, Cancel); + if Cancel then Exit; + end; + end; + until (BytesRead = 0); + finally + Buffer.Free; + FResponseStream.Position := 0; + end; + + { Read the response status and headers } + FResponseStatus := QueryInfoInteger(HTTP_QUERY_STATUS_CODE); + FResponseStatusText := QueryInfoString(HTTP_QUERY_STATUS_TEXT); + ReadResponseHeaders; + + finally + InternetCloseHandle(FhReq); + end; + finally + InternetCloseHandle(hConn); + end; + finally + InternetCloseHandle(hInt); + end; + + if Assigned(FOnProgress) then + FOnProgress(Self, scFinished, TotalBytesRead, TotalBytesToRead, Cancel); + + Result := FResponseStatus; +end {THttpClient.SendRequestAndGetResponse}; + + +{ ------------------------------------------------------------------------------------------------ } +function THttpClient.QueryInfoInteger(const InfoFlag: cardinal): cardinal; +begin + Win32Check(QueryInfoInteger(InfoFlag, Result)); +end {THttpClient.QueryInfoInteger}; +{ ------------------------------------------------------------------------------------------------ } +function THttpClient.QueryInfoInteger(const InfoFlag: cardinal; out Value: cardinal): boolean; +var + Index, BufSize: Cardinal; +begin + Index := 0; + bufsize := sizeOf(Value); + Result := HttpQueryInfo(FhReq, InfoFlag or HTTP_QUERY_FLAG_NUMBER, @Value, BufSize, Index); +end {THttpClient.QueryInfoInteger}; + +{ ------------------------------------------------------------------------------------------------ } +function THttpClient.QueryInfoString(const InfoFlag: cardinal): string; +begin + Win32Check(QueryInfoString(InfoFlag, Result)); +end {THttpClient.QueryInfoString}; +{ ------------------------------------------------------------------------------------------------ } +function THttpClient.QueryInfoString(const InfoFlag: cardinal; out Value: string): Boolean; +var + BufSize, Index: cardinal; + i: byte; +begin + Result := True; + Index := 0; + bufsize := READBUFFERSIZE; + for i := 0 to 1 do begin + SetLength(Value, bufsize div SizeOf(Char)); + if not HttpQueryInfo(FhReq, InfoFlag, PChar(Value), bufsize, Index) then begin + case GetLastError of + ERROR_INSUFFICIENT_BUFFER: begin + // bufsize now contains the required size; just go to the next iteration. + end; + ERROR_HTTP_HEADER_NOT_FOUND: begin + // no more headers; just return the current result + SetLength(Value, bufsize div SizeOf(Char)); + Break; + end; + else begin + Result := False; + Break; + end; + end; + end else begin + // HttpQueryInfo was successful + SetLength(Value, bufsize div SizeOf(Char)); + Break; + end; + end {for}; +end {THttpClient.QueryInfoString}; + +{ ------------------------------------------------------------------------------------------------ } +procedure THttpClient.ReadResponseHeaders; +var + Headers, Header: string; + i, Offset: integer; +begin + Headers := QueryInfoString(HTTP_QUERY_RAW_HEADERS); + Header := StringOfChar(#0, Length(Headers)); + FResponseHeaders := TStringList.Create; + FResponseHeaders.NameValueSeparator := ':'; + FResponseHeaders.CaseSensitive := False; + + Offset := 0; + for i := 1 to Length(Headers) - 1 do begin + if Headers[i] = #0 then begin + SetLength(Header, i - Offset - 1); + if Length(Header) = 0 then begin + Break; + end; + FResponseHeaders.Add(Header); + Header := StringOfChar(#0, Length(Headers) - i); + Offset := i; + end else begin + Header[i - Offset] := Headers[i]; + end; + end; + if (Length(Header) > 0) and (Header[1] <> #0) then begin + Offset := Pos(#0, Header); + if Offset > 0 then begin + FResponseHeaders.Add(Copy(Header, 1, Offset - 1)); + end else begin + FResponseHeaders.Add(Header); + end; + end; +end {THttpClient.ReadResponseHeaders}; + +{ ------------------------------------------------------------------------------------------------ } +function THttpClient.GetResponseString: string; // RawString +var + ContentType: string; + CharPos: Integer; + Encoding: TEncoding; + SS: TStringStream; +begin + if Assigned(FResponseStream) and (FResponseStream.Size > 0) then begin +// SetLength(Result, FResponseStream.Size div StringElementSize(Result)); +// CopyMemory(@Result[1], FResponseStream.Memory, FResponseStream.Size); + ContentType := ResponseHeaders.Values['Content-Type']; + CharPos := Pos('charset=', ContentType); + if CharPos > 0 then begin + Encoding := TEncoding.GetEncoding(Copy(ContentType, CharPos + 8)); + end else begin + Encoding := TEncoding.Default; + end; + SS := TStringStream.Create('', Encoding, True); + try + SS.CopyFrom(FResponseStream, 0); + Result := SS.DataString; + finally + SS.Free; + end; + end else begin + Result := ''; + end; +end {THttpClient.GetResponseString}; + +end. Index: src/common/L_VersionInfoW.pas ================================================================== --- src/common/L_VersionInfoW.pas +++ src/common/L_VersionInfoW.pas @@ -7,53 +7,64 @@ type TFileVersionInfo = class private { Private declarations } - FFilename : WideString; + FFilename : string; FHasVersionInfo : boolean; - FCompanyName : WideString; - FFileDescription : WideString; - FFileVersion : WideString; - FInternalname : WideString; - FLegalCopyright : WideString; - FLegalTradeMarks : WideString; - FOriginalFilename : WideString; - FProductName : WideString; - FProductVersion : WideString; - FComments : WideString; + FCompanyName : string; + FFileDescription : string; + FFileVersion : string; + FInternalname : string; + FLegalCopyright : string; + FLegalTradeMarks : string; + FOriginalFilename : string; + FProductName : string; + FProductVersion : string; + FComments : string; FMajorVersion : Word; FMinorVersion : Word; - FRevision : Word; + FRevision : Word; FBuild : Word; + FFlags : Word; + FFileDateTime : TDateTime; - procedure SetFileName(AFileName: WideString); + procedure SetFileName(const AFileName: string); + function HasFlag(const Index: integer): boolean; protected { Protected declarations } public { Public declarations } - constructor Create(AFileName: WideString); + constructor Create(const AFileName: string); destructor Destroy; override; - property FileName : WideString read FFileName write SetFileName; + property FileName : string read FFileName write SetFileName; public { Published declarations } - property CompanyName : WideString read FCompanyName; - property FileDescription : WideString read FFileDescription; - property FileVersion : WideString read FFileVersion; - property Internalname : WideString read FInternalname; - property LegalCopyright : WideString read FLegalCopyright; - property LegalTradeMarks : WideString read FLegalTradeMarks; - property OriginalFilename : WideString read FOriginalFilename; - property ProductName : WideString read FProductName; - property ProductVersion : WideString read FProductVersion; - property Comments : WideString read FComments; - property MajorVersion : Word read FMajorVersion; - property MinorVersion : Word read FMinorVersion; - property Revision : Word read FRevision; - property Build : Word read FBuild; + property CompanyName : string read FCompanyName; + property FileDescription : string read FFileDescription; + property FileVersion : string read FFileVersion; + property Internalname : string read FInternalname; + property LegalCopyright : string read FLegalCopyright; + property LegalTradeMarks : string read FLegalTradeMarks; + property OriginalFilename : string read FOriginalFilename; + property ProductName : string read FProductName; + property ProductVersion : string read FProductVersion; + property Comments : string read FComments; + property MajorVersion : Word read FMajorVersion; + property MinorVersion : Word read FMinorVersion; + property Revision : Word read FRevision; + property Build : Word read FBuild; + property Flags : Word read FFlags; + property IsDebug : boolean index VS_FF_DEBUG read HasFlag; + property IsPreRelease : boolean index VS_FF_PRERELEASE read HasFlag; + property IsPatched : boolean index VS_FF_PATCHED read HasFlag; + property IsPrivateBuild : boolean index VS_FF_PRIVATEBUILD read HasFlag; + property IsInfoInferred : boolean index VS_FF_INFOINFERRED read HasFlag; + property IsSpecialBuild : boolean index VS_FF_SPECIALBUILD read HasFlag; + property FileDateTime : TDateTime read FFileDateTime; end; implementation type @@ -61,11 +72,11 @@ wLanguage : word; wCodePage : word; end; PLangAndCP = ^TLangAndCP; -constructor TFileVersionInfo.Create(AFileName: WideString); +constructor TFileVersionInfo.Create(const AFileName: string); begin inherited Create; SetFileName(AFileName); end; @@ -72,39 +83,45 @@ destructor TFileVersionInfo.Destroy; begin inherited Destroy; end; -procedure TFileVersionInfo.SetFileName(AFileName: WideString); -var - Dummy : cardinal; - BufferSize: integer; - Buffer : Pointer; - Lang : PLangAndCP; - SubBlock : WideString; - InfoBlock : VS_FIXEDFILEINFO; - InfoPtr : Pointer; - function QueryValue(AName: WideString): WideString; - var - Value : PWChar; - begin - SubBlock := WideFormat('\\StringFileInfo\\%.4x%.4x\\%s', [Lang.wLanguage, Lang.wCodePage, AName]); - VerQueryValueW(Buffer, PWChar(SubBlock), Pointer(Value), Dummy); - Result := WideString(Value); - end; +procedure TFileVersionInfo.SetFileName(const AFileName: string); +var + Dummy : UINT; + BufferSize: DWORD; + Buffer : Pointer; + PLang : PLangAndCP; + SubBlock : string; + SysTime: TSystemTime; + { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - } + function QueryValue(const AName: string): string; + var + Value : PChar; + begin + SubBlock := WideFormat('\\StringFileInfo\\%.4x%.4x\\%s', [PLang.wLanguage, PLang.wCodePage, AName]); + if VerQueryValue(Buffer, PChar(SubBlock), Pointer(Value), Dummy) then + Result := string(Value) + else + Result := ''; + end; + { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - } +var + PInfoBlock : PVSFixedFileInfo; + FileTime : TFileTime; begin FFilename := AFileName; - BufferSize := GetFileVersionInfoSizeW(PWChar(AFileName), Dummy); + BufferSize := GetFileVersionInfoSize(PChar(AFileName), Dummy); FHasVersionInfo := (Buffersize > 0); - if BufferSize > 0 then begin + if FHasVersionInfo then begin Buffer := AllocMem(BufferSize); try - GetFileVersionInfoW(PWChar(AFileName),0,BufferSize,Buffer); + GetFileVersionInfo(PChar(AFileName), Dummy, BufferSize, Buffer); SubBlock := '\\VarFileInfo\\Translation'; - VerQueryValueW(Buffer, PWChar(SubBlock), Pointer(Lang), Dummy); + VerQueryValue(Buffer, PChar(SubBlock), Pointer(PLang), Dummy); FCompanyName := QueryValue('CompanyName'); FFileDescription := QueryValue('FileDescription'); FFileVersion := QueryValue('FileVersion'); FInternalName := QueryValue('InternalName'); @@ -113,21 +130,25 @@ FOriginalFilename := QueryValue('OriginalFilename'); FProductName := QueryValue('ProductName'); FProductVersion := QueryValue('ProductVersion'); FComments := QueryValue('Comments'); - VerQueryValue(Buffer, '\', InfoPtr, Dummy); - Move(InfoPtr^, InfoBlock, SizeOf(VS_FIXEDFILEINFO)); - FMajorVersion := InfoBlock.dwFileVersionMS shr 16; - FMinorVersion := InfoBlock.dwFileVersionMS and 65535; - FRevision := InfoBlock.dwFileVersionLS shr 16; - FBuild := InfoBlock.dwFileVersionLS and 65535; + VerQueryValue(Buffer, '\', Pointer(PInfoBlock), Dummy); + FMajorVersion := PInfoBlock.dwFileVersionMS shr 16; + FMinorVersion := PInfoBlock.dwFileVersionMS and 65535; + FRevision := PInfoBlock.dwFileVersionLS shr 16; + FBuild := PInfoBlock.dwFileVersionLS and 65535; + FFlags := PInfoBlock.dwFileFlags and PInfoBlock.dwFileFlagsMask; + + FileTime.dwLowDateTime := PInfoBlock.dwFileDateLS; + FileTime.dwHighDateTime := PInfoBlock.dwFileDateMS; + if FileTimeToLocalFileTime(FileTime, FileTime) and FileTimeToSystemTime(FileTime, SysTime) and (SysTime.wYear > 1601) then + FFileDateTime := SystemTimeToDateTime(SysTime); finally - FreeMem(Buffer,BufferSize); + FreeMem(Buffer, BufferSize); end; - end - else begin + end else begin FCompanyname := ''; FFileDescription := ''; FFileVersion := ''; FInternalname := ''; FLegalCopyright := ''; @@ -140,9 +161,14 @@ FMinorVersion := 0; FRevision := 0; FBuild := 0; end; end; + +function TFileVersionInfo.HasFlag(const Index: integer): boolean; +begin + Result := (FFlags and Index) <> 0; +end; end. Index: src/lib/NppDockingForms.pas ================================================================== --- src/lib/NppDockingForms.pas +++ src/lib/NppDockingForms.pas @@ -149,18 +149,18 @@ {$IFDEF NPPUNICODE} StringToWideChar(self.Caption, self.ToolbarData.Title, 500); GetModuleFileNameW(HInstance, self.ToolbarData.ModuleName, 1000); StringToWideChar(ExtractFileName(self.ToolbarData.ModuleName), self.ToolbarData.ModuleName, 1000); StringToWideChar('', self.ToolbarData.AdditionalInfo, 1); - {r:=}SendMessageW(self.Npp.NppData.NppHandle, NPPM_DMMREGASDCKDLG, 0, Integer(@self.ToolbarData)); + {r:=}SendMessageW(self.Npp.NppData.NppHandle, NPPM_DMMREGASDCKDLG, 0, NativeInt(@self.ToolbarData)); {$ELSE} StrCopy(self.ToolbarData.Title, PChar(self.Caption)); GetModuleFileNameA(HInstance, self.ToolbarData.ModuleName, 1000); StrLCopy(self.ToolbarData.ModuleName, PChar(ExtractFileName(self.ToolbarData.ModuleName)), 1000); StrCopy(self.ToolbarData.AdditionalInfo, PChar('')); {r:=} - SendMessageA(self.Npp.NppData.NppHandle, NPPM_DMMREGASDCKDLG, 0, Integer(@self.ToolbarData)); + SendMessageA(self.Npp.NppData.NppHandle, NPPM_DMMREGASDCKDLG, 0, NativeInt(@self.ToolbarData)); {$ENDIF} self.Visible := true; end; @@ -183,11 +183,11 @@ // I still don't know why the pointer climbs up to the docking dialog that holds this one // but this works for now. procedure TNppDockingForm.RemoveControlParent(control: TControl); var wincontrol: TWinControl; - i, r: integer; + i, r: NativeInt; begin if (control is TWinControl) then begin wincontrol := control as TWinControl; wincontrol.HandleNeeded; Index: src/lib/SciSupport.pas ================================================================== --- src/lib/SciSupport.pas +++ src/lib/SciSupport.pas @@ -8,17 +8,17 @@ {$DEFINE MACRO_SUPPORT} uses Windows; type - TScintillaMessageFnc = function(ptr : Pointer; Msg, wParam, lParam : LongInt) : LongInt; cdecl; + TScintillaMessageFnc = function(ptr : Pointer; Msg: UINT; wParam: WPARAM; lParam : LPARAM) : LRESULT; cdecl; uptr_t = Longword; sptr_t = Longint; TNotifyHeader = record - hwndFrom : Pointer; - idFrom : Cardinal; - code : Cardinal; + hwndFrom : HWND; + idFrom : uptr_t; + code : NativeUInt; end; PSCNotification = ^TSCNotification; TSCNotification = record nmhdr : TNotifyHeader; position : Integer; // SCN_STYLENEEDED, SCN_MODIFIED Index: src/lib/nppplugin.pas ================================================================== --- src/lib/nppplugin.pas +++ src/lib/nppplugin.pas @@ -397,11 +397,11 @@ DMN_FLOAT = (DMN_FIRST + 3); //nmhdr.code = DWORD(DMN_XXX, int newContainer); //nmhdr.hwndFrom = hwndNpp; //nmhdr.idFrom = ctrlIdNpp; type {$IFDEF NPPUNICODE} - nppString = WideString; + nppString = UnicodeString; nppChar = WChar; nppPChar = PWChar; {$ELSE} nppString = AnsiString; nppChar = AnsiChar; @@ -427,11 +427,11 @@ ToolbarBmp: HBITMAP; ToolbarIcon: HICON; end; TCommunicationInfo = record - internalMsg: Cardinal; + internalMsg: NativeUInt; srcModuleName: nppPChar; info: Pointer; end; TNppData = record @@ -471,11 +471,11 @@ end; TNppPlugin = class(TObject) private FuncArray: array of _TFuncItem; - FClosingBufferID: Integer; + FClosingBufferID: THandle; FConfigDir: string; protected PluginName: nppString; function GetPluginsConfigDir: string; function AddFuncSeparator: Integer; @@ -501,12 +501,12 @@ procedure MessageProc(var Msg: TMessage); virtual; // hooks procedure DoNppnToolbarModification; virtual; procedure DoNppnShutdown; virtual; - procedure DoNppnBufferActivated(const BufferID: Cardinal); virtual; - procedure DoNppnFileClosed(const BufferID: Cardinal); virtual; + procedure DoNppnBufferActivated(const BufferID: THandle); virtual; + procedure DoNppnFileClosed(const BufferID: THandle); virtual; procedure DoUpdateUI(const hwnd: HWND; const updated: Integer); virtual; procedure DoModified(const hwnd: HWND; const modificationType: Integer); virtual; // df function DoOpen(filename: String): boolean; overload; @@ -750,16 +750,16 @@ procedure TNppPlugin.DoNppnToolbarModification; begin // override these end; -procedure TNppPlugin.DoNppnBufferActivated(const BufferID: Cardinal); +procedure TNppPlugin.DoNppnBufferActivated(const BufferID: THandle); begin // override these end; -procedure TNppPlugin.DoNppnFileClosed(const BufferID: Cardinal); +procedure TNppPlugin.DoNppnFileClosed(const BufferID: THandle); begin // override these end; procedure TNppPlugin.DoModified(const hwnd: HWND; const modificationType: Integer); Index: src/prj/PreviewHTML.dpr ================================================================== --- src/prj/PreviewHTML.dpr +++ src/prj/PreviewHTML.dpr @@ -27,11 +27,13 @@ F_PreviewHTML in '..\F_PreviewHTML.pas' {frmHTMLPreview}, WebBrowser in '..\lib\WebBrowser.pas', L_VersionInfoW in '..\common\L_VersionInfoW.pas', L_SpecialFolders in '..\common\L_SpecialFolders.pas', RegExpr in '..\common\RegExpr.pas', - U_CustomFilter in '..\U_CustomFilter.pas'; + U_CustomFilter in '..\U_CustomFilter.pas', + U_AutoUpdate in '..\U_AutoUpdate.pas', + Debug in '..\Debug.pas'; {$R *.res} {$Include '..\lib\NppPluginInclude.pas'} Index: src/prj/PreviewHTML.dproj ================================================================== --- src/prj/PreviewHTML.dproj +++ src/prj/PreviewHTML.dproj @@ -2,23 +2,28 @@ {A2533A0E-8621-4A31-A675-059AFF5AA9FB} PreviewHTML.dpr True Debug - 1 + 3 Library VCL 18.2 - Win32 + Win64 true true Base true + + + true + Base + true true Base true @@ -31,12 +36,20 @@ true Cfg_2 true true + + + true + Cfg_2 + true + true + false + false PreviewHTML 4 false System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) true + + System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + false 0 0 RELEASE;$(DCC_Define) @@ -82,12 +99,18 @@ DEBUG;$(DCC_Define) false true + C:\MC\Run\Office\Np++\unicode\notepad++ true + + 0 + C:\MC\Run\Office\Np++\x64\notepad++.exe + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + MainSource @@ -111,10 +134,12 @@ + + Cfg_2 Base @@ -165,27 +190,356 @@ 6.0.0.0 - False True - False + True + + + + PreviewHTML.dll + true + + + + + Contents\MacOS + 0 + + + 1 + + + + + classes + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\armeabi + 1 + + + + + library\lib\mips + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable + 1 + + + + + res\values + 1 + + + + + res\drawable + 1 + + + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-ldpi + 1 + + + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + + + res\drawable-small + 1 + + + + + res\drawable-normal + 1 + + + + + res\drawable-large + 1 + + + + + res\drawable-xlarge + 1 + + + + + 0 + + + 1 + + + 1 + + + + + 0 + + + 1 + .framework + + + + + 0 + .dll;.bpl + + + 1 + .dylib + + + + + 0 + .bpl + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 1 + + + + + + + Contents\Resources + 1 + + + + + 1 + + + 1 + + + 0 + + + 1 + + + 1 + + + library\lib\armeabi-v7a + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + + + + + + + 12 - - - False - - False - "C:\MC\Run\Util\Compression\UPX\upx.exe" --best -q "$(OUTPUTPATH)" - True - + False False