Из архива
Расскажу об одном небольшом нюансе который поможет сэкономить время и нервы. Эта особенность мною была замечена только в MySQL (проявлялась как в 5 так и пока в тестовом 6-ом). Заключается она в необходимости особого наименования процедур, для правильного восстановления базы из архива (дампа MySQL).
Смысл заключается в алфавитном порядке функций. При создании дампа базы все элементы сохраняются в алфавитном порядке, тоесть если в процедуре proc1 вызвать процедуру proc2 — то при восстановлении из дампа вылетит ошибка поскольку первой будет восстанавливаться процедура proc1 — которой требуется proc2 — но её в базе на момент воссоздания ещё не будет.
Здесь я приведу некоторые очень полезные вещи при разработке на .NET Compact Framework.
Итак, приступаем:
Узнаём версию .NET Compact Framework
FrmTxt.Text = Environment.Version.ToString();
Узнаём версию операционной системы
OsVersion.Text = Environment.OSVersion.ToString();
Из архива - вдруг пригодится...
Вроде бы нет ничего проще открытия картинки с диска в C#. А нет, И тут есть свои грабли!
Здесь просто приведу два примера.
Первый способ (неправильный):
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
Image img = Image.FromFile(openFileDialog1.FileName);
pictureBox1.Image = img;
}
Из архива - вдруг пригодится...
Очень часто при добавлении изображений в проект приходится изменять размеры изображения, и часто хочется это делать грамотно, с сохранением пропорций изображения. Лично мне часто бывает надо вставить картинки в ListView допустим и ужать их правильно (так чтобы не расползлись в квадрат заданных размеров). Именно в этом деле и поможет написанная ниже процедура.
Процедура изменения размеров:
static Image ScaleImage(Image source, int width, int height)
{
Image dest = new Bitmap(width, height);
using (Graphics gr = Graphics.FromImage(dest))
{
gr.FillRectangle(Brushes.White, 0, 0, width, height); // Очищаем экран
gr.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
float srcwidth = source.Width;
float srcheight = source.Height;
float dstwidth = width;
float dstheight = height;
if (srcwidth <= dstwidth && srcheight <= dstheight) // Исходное изображение меньше целевого
{
int left = (width - source.Width) / 2;
int top = (height - source.Height) / 2;
gr.DrawImage(source, left, top, source.Width, source.Height);
}
else if (srcwidth / srcheight > dstwidth / dstheight) // Пропорции исходного изображения более широкие
{
float cy = srcheight / srcwidth * dstwidth;
float top = ((float)dstheight - cy) / 2.0f;
if (top < 1.0f) top = 0;
gr.DrawImage(source, 0, top, dstwidth, cy);
}
else // Пропорции исходного изображения более узкие
{
float cx = srcwidth / srcheight * dstheight;
float left = ((float)dstwidth - cx) / 2.0f;
if (left < 1.0f) left = 0;
gr.DrawImage(source, left, 0, cx, dstheight);
}
return dest;
}
}
Для того чтобы разрешить ввод в поле TextBox только цифр в C#, самый простой способ воспользоваться обработчиком события KeyPress.
Вот как это делается:
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (!(Char.IsDigit(e.KeyChar)))
{
e.Handled = true;
}
}
Здесь я не буду приводить подробных инструкций, какую кнопочку необходимо нажать и какую менюшку ткнуть в Visual Studio. Здесь я остановлюсь на основных двух проблемных моментах с которыми сам столкнулся при создании собственной службы.
Первый момент. Собственно служба должна что нибудь делать, это что нибудь обычно делается по таймеру, вот он то никак и не запускался. Не работал, и всё тут! Выяснилось что обычный таймер System.Windows.Forms.Timer работает только на основе оконных сообщений! Находил информацию по поводу того что можно и без этого запустить как: System.Timers.Timer или System.Threading.Timer — но с ними тоже ничего не получилось. Вернулся к первому варианту, просто в отдельном потоке создал форму и таймер, ниже пример.
public partial class Service1 : ServiceBase
{
System.Windows.Forms.Timer timer1;
System.Windows.Forms.Form form1;
System.Threading.Thread thread1;
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
//При запуске службы запускаем новый поток
thread1 = new System.Threading.Thread(new System.Threading.ThreadStart(ThreadProc));
thread1.Start();
thread1.IsBackground = true;
}
void ThreadProc()
{
//Создаем во вновь созданном потоке форму и таймер
form1 = new System.Windows.Forms.Form();
timer1 = new System.Windows.Forms.Timer();
timer1.Tick += new EventHandler(timer_Tick);
timer1.Interval = 2000;
timer1.Start();
form1.Show();
//Запускаем всё это добро.
System.Windows.Forms.Application.Run(form1);
}
protected override void OnStop()
{
thread1.Abort();
}
private void timer_Tick(object sender, EventArgs e)
{
timer1.Enabled = false;
timer1.Stop();
runProcedure(); //Запускаем процедуру (чего хотим выполнить по таймеру).
timer1.Enabled = true;
timer1.Start();
}
}
Собственно вот так вот таймер и запустил в службе, ничего сложного, тяп ляп и всё заработало.
Но не тут то было!
Второй момент!
Как это всё теперь установить? Так чтобы это всё было в службах и запускалось само и работало.
Для того чтобы установить написанную на C# службу потребуется утилита «InstallUtil.exe» — находится она в папке с .NET 2 — у меня нашлось конкретно вот в этой папочке: C:\Windows\Microsoft.NET\Framework\v2.0.50727. У меня там было ещё куча версий, но нужный файлик был именно там.
Чтобы не прописывать пути скопировал из этой папки файлики InstallUtil.exe и InstallUtilLib.dll в папку с скомпилированным проектом службы, и запускал инсталл вот такой строчкой:
InstallUtil.exe /i MyService.exe
Но это не сработает если предварительно в проект не добавить Класс Инсталлера, делается это так: кликаете правой кнопкой мыши по Пустому месту в Дизайнере службы (в моём случае вкладка Service1.cs[Design]) и кликаете по менюшке «Add Installer». Собственно всё. После этого действия появится вкладка «Project Installer» — там в свойствах ServiceInstaller задаём название и описание нашей службы, а в свойствах ServiceProcessInstaller — от чьего имени будет выполняться служба. Если поставите в свойстве Account > User — то при установке служба спросит имя пользователя и пароль от которого будет запускаться.
Вот собственно и всё.
Полезный пример изменения кодировки (COLLATION) на уже созданной базе данных.
В данном примере устанавливается русская кодировка: Cyrillic_General_CI_AS
USE master;
GO
-- Переводим БД в single-user mode
ALTER DATABASE [имя_базы_данных]
SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO
-- Меняем кодировку COLLATION
ALTER DATABASE [имя_базы_данных]
COLLATE Cyrillic_General_CI_AS ;
GO
-- Переводим БД обратно в multi-user mode
ALTER DATABASE [имя_базы_данных]
SET MULTI_USER WITH ROLLBACK IMMEDIATE;
GO
--Проверяем настройки COLLATION.
SELECT name, collation_name
FROM sys.databases
WHERE name = 'имя_базы_данных';
GO
Правильный способ удаления временной таблицы:
IF OBJECT_ID('tempdb.dbo.#tmp', 'U') IS NOT NULL
DROP TABLE #tmp;
Простой пример генерации MD5 на Oracle PL/SQL.
declare
cln_md5raw raw(2000);
out_raw raw(16);
begin
cln_md5raw := utl_raw.cast_to_raw('Наш текст для хеширования');
dbms_obfuscation_toolkit.md5(input=>cln_md5raw,checksum=>out_raw);
-- Выводится hex версия (32 символа)
dbms_output.put_line(lower(out_raw));
end;
100% работает на версии Oracle 11g.
Всё что описано ниже, выполнялось на Windows сервере.
Для создания Бэкапа открываем командную строку cmd.exe
В командной строке запускаем утилиту rman
Далее, для бэкапа базы данных без АрхивЛогов:
connect target user/password;
shutdown immediate;
startup mount;
backup database;
sql 'alter database open';