Поиск  Пользователи  Правила 
Закрыть
Логин:
Пароль:
Забыли свой пароль?
Регистрация
Войти
 
Выбрать дату в календареВыбрать дату в календаре

Страницы: 1 2 След.
Быстрый способ поменять местами значения в двух диапазонах в C# VSTO
 
Добрый день всем!
Давненько я здесь не писал.  :)
Для тех, кто пишет надстройки/книги на C# VSTO, есть быстрый способ поменять местами два диапазона. Данный способ использует кортежи.
Код
Excel.Range rng1 = sheet.Range["A1:C1"];
Excel.Range rng2 = sheet.Range["A2:C2"];
// Меняем местами
(rng1.Value, rng2.Value) = (rng2.Value, rng1.Value);
Всем удачи!  :)  
There is no knowledge that is not power
PowerQuery не сохраняет типы данных после Table.ExpandTableColumn?
 
Делал-делал я один запрос, но в итоге вдруг у меня стали вываливаться ошибки. Сначала не понял, почему, но потом разобрался - PowerQuery после группировки (например, суммирование) не сохраняет типы данных, которые я присвоил столбцам в предыдущих шагах.
Например, есть такая табличка:


Запрос PowerQuery:
Код
let
    Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
    ChangedType = Table.TransformColumnTypes(Source,{{"ID", Int64.Type}, {"Date1", type date}, {"Sum", Int64.Type}}),
    GroupedRows = Table.Group(ChangedType, {"ID"}, {{"SUM_GROUP", each List.Sum([Sum]), type number}, {"ALL_ROWS", each _, type table}}),
    ExpandedALLROWS = Table.ExpandTableColumn(GroupedRows, "ALL_ROWS", {"ID", "Date1", "Sum"}, {"ALL_ROWS.ID", "ALL_ROWS.Sum", "ALL_ROWS.Date1"})
in
    ExpandedALLROWS

На шаге ChangedType всё ОК:




Но на шаге ExpandedALLROWS типы данных слетают:



Это никак не лечится? Или придётся в конце заново изменять типы? Или лучше сначала вообще не изменять типы, а изменть их только в конце?
Изменено: SuperCat - 26 июл 2019 22:48:07
There is no knowledge that is not power
В Power Query определить номер строки у каждой группы значений
 
Привет всем! :)
В SQL существуют так называемые оконные функции (window functions), одна из которых - ROW_NUMBER. Эта функция позволяет вывести номер строки для каждой группы значений. Чтобы было понятно, вот пример, что нужно получить:

Как видно из таблицы, для каждой группы ID определяется своя нумерация строк (ROW_NUMBER). Возможно ли такое сделать с помощью Power Query?
There is no knowledge that is not power
Microsoft без предупреждения начала "убивать" Windows 7
 
Компания Microsoft без предупреждения прекратила поддержку операционной системы Windows 7 на старых компьютерах, процессоры которых не поддерживают инструкции SSE2. Последние появились в процессорах Intel Pentium 4.
Таким образом, компьютеры на базе процессоров предыдущих поколений не будут получать обновления операционной системы, несмотря на то, что Microsoft официально продлила поддержку Windows 7 до середины января 2020 года, пишет РГ со ссылкой на ComputerWorld.
Помимо этого, стало известно, что с июля сотрудники Microsoft не будут консультировать пользователей форума техподдержки по вопросам, связанным с программными продуктами Windows 7, 8. и 8.1 RT, Microsoft Security Essentials, Internet Explorer 10, Office 2010 и 2013, планшетами Surface Pro, Surface Pro 2, Surface RT и Surface 2, фитнес-браслетом Microsoft Band и сервисом Zune.

Взято отсюда
There is no knowledge that is not power
Office 2019
 
New features coming:
- Inking feature (Использование пера)
- Improved data analysis capabilities (Улучшенные возможности анализа данных)
- Expanded PowerPoint animation features (Расширенные возможности анимации в PowerPoint)
- Better security (Улучшенная безопасность)

Самое главное - Office 2019 будет работать только в Windows 10.
There is no knowledge that is not power
Создание элементов управления в VBA с помощью WinAPI
 
Приветствую! :)
Возникла необходимость создавать динамически элементы управления через WinAPI. Стал разбираться в этой теме. Удалось создать ListBox и добавить в него некоторые строки. Проблема в том, что созданный ListBox никак ни на что не реагирует: полосы прокрутки не работают, выделение не работает. Как будто он в режиме Disabled или Locked. Есть у кого-либо какие идеи, как заставить ListBox отвечать на действия? :)

Что имеем:
1. WinAPI функции:
Код
Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" ( _
    ByVal lpClassName As String, _
    ByVal lpWindowName As String) As Long

Declare Function CreateWindow Lib "user32.dll" Alias "CreateWindowExA" ( _
     ByVal dwExStyle As WindowStylesEx, _
     ByVal lpClassName As String, _
     ByVal lpWindowName As String, _
     ByVal dwStyle As Long, _
     ByVal x As Long, _
     ByVal y As Long, _
     ByVal nWidth As Long, _
     ByVal nHeight As Long, _
     ByVal hWndParent As Long, _
     ByVal hMenu As Long, _
     ByVal hInstance As Long, _
     ByVal lpParam As Long) As Long

Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" ( _
    ByVal hwnd As Long, _
    ByVal wMsg As Long, _
    ByVal wParam As Long, _
    ByVal lParam As Any) As Long
2. В UserForm'e создаём ListBox и добавляем значения:
Код
hlist = CreateWindow( _
    dwExStyle:=WS_EX_CLIENTEDGE, _
    lpClassName:="LISTBOX", _
    lpWindowName:="MYLISTBOX", _
    dwStyle:=WS_CHILD Or WS_VISIBLE Or LBS_NOTIFY Or WS_VSCROLL Or WS_BORDER Or LBS_HASSTRINGS, _
    x:=10, _
    y:=10, _
    nWidth:=100, _
    nHeight:=100, _
    hWndParent:=FindWindow("ThunderDFrame", Me.Caption), _
    hMenu:=0, _
    hInstance:=Application.hInstance, _
    lpParam:=0 _
)
' Добавляем значения
For x = 1 To 10
    Call SendMessage(hlist, LB_ADDSTRING, 0, CStr(x))
Next

Скриншот:
Изменено: SuperCat - 8 фев 2018 12:55:23
There is no knowledge that is not power
SQL Operations Studio - кросс-платформенная SSMS
 
SQL Operations Studio
There is no knowledge that is not power
Использование dynamic в .NET EntityFramework
 
Хочу поделиться одной идеей, как в C# можно эффективно использовать dynamic в EF (на примере WPF приложения). Например, есть три таблицы в базе данных (по сути - справочники) с одной и той же структурой:
Код
class Strategy
{
    public int Id { get; set; }
    public string Name { get; set; }
}

class Operator
{
    public int Id { get; set; }
    public string Name { get; set; }
}

class OrderState
{
    public int Id { get; set; }
    public string Name { get; set; }
}
Задача: создать функционал для изменения значений справочников. У нас есть два комбобокса (ComboBox) и текстовое поле (TextBox):
1) сmbDictionaries - список доступных справочников
2) cmbDictionaryEntries - список значений в выбранном справочнике
3) txtEntryName - выбранное значение справочника

Итак, сначала подгружаем список доступных справочников:
Код
private void OnWindowLoaded(object sender, RoutedEventArgs e)
{
    // Создаём контекст
    context = new TestContext(@"Server=(localdb)\MSSQLLocalDB;Database=Test;Trusted_Connection=Yes;");

    // Загрузка справочников
    var dic = new Dictionary<string, string>
    {
        ["Стратегия"] = "Strategy",
   ["Оператор"] = "Operator",
   ["Статус"] = "OrderState"
    };

    foreach (var item in dic)
    {
        cmbDictionaries.Items.Add(new ComboBoxItem { Content = item.Key, Tag = item.Value });
    }
}

Заполняем комбобокс при перевыборе справочника:
Код
private async void OnDictionaryChanged(object sender, SelectionChangedEventArgs e)
{
    var set = GetDbSet();
    set.Load();
    cmbDictionaryEntries.ItemsSource = null;
    cmbDictionaryEntries.ItemsSource = await set.ToListAsync();
}

Создание и изменение:
Код
private async void OnChangeEntry(object sender, RoutedEventArgs e)
{
    // Taк как Binding у текстового поля использует режим TwoWay,
    // то все изменения транслируются автоматически в сущность.
    // По умолчанию, у текстового поля изменения транслируются при потере фокуса.
    int count = await context.SaveChangesAsync();
    MessageBox.Show($"Сохранено записей: {count}");
}

private async void OnAddEntry(object sender, RoutedEventArgs e)
{
    var set = GetDbSet();
    // Используем dynamic, чтобы проще было добраться до свойства Name
    dynamic entry = set.Create();
    entry.Name = txtEntryName.Text;
    set.Add(entry);
    int count = await context.SaveChangesAsync();
    MessageBox.Show($"Сохранено записей: {count}");
}

На данный момент мы уже с помощью dynamic облегчаем себе работу. Так как у нас таблицы (и сущности) одинаковые, то мы можем использовать обобщённый (generic) метод Set, чтобы создавать новые сущности и сохранять их. Вся изюминка - в методе GetDbSet:
Код
private DbSet GetDbSet()
{
    // cmbDictionaries в качестве ItemContainer использует ComboBoxItem.
    // Ранее был показан код добавления значений словаря. В свойство Tag было записано название класса сущности.
    // Здесь SelectedItem возвращает нам Object, а в конечном итоге - ComboBoxItem, у которого мы должны взять Tag.
    // По идее, можно сделать кастинг SelectedItem'a в ComboBoxItem, взять свойство Tag и сконвертировать в String...
    // Но используя dynamic, всё становится намного проще. В итоге setName имеет тип String. В этом можно убедиться,
    // если в Immediate Window выполнить запрос: ?setName.GetType().FullName
    // Ответом будет "System.String".
    dynamic setName = ((dynamic)cmbDictionaries.SelectedItem).Tag;
    // После получения названия целевой сущности, нужно получить её тип.
    // Нужно в строке указать полный путь к классу. Здесь для удобства используется фишка C#7.0 - Interpolation String.
    var type = Type.GetType($"DynamicEFWPF.{setName}");
    // Далее получаем DbSet, но не типизированный (Object).
    var set = context.Set(type);
    return set;
    // Или всё в одну строку:
    //return context.Set(Type.GetType($"DynamicEFWPF.{((dynamic)cmbDictionaries.SelectedItem).Tag}"));
}

Таким образом, нам не надо плодить кучу if'ов, чтобы выбрать тип. Но опять же повторюсь - это работает только для сущностей одинаковой структуры.
Полный WPF проект можно посмотреть/скачать здесь. Скрипт для создания базы данных - файл Scripts.sql в папке Database (работает с SQL Server 2016 и выше).
There is no knowledge that is not power
VTT to SRT - конвертер VTT субтитров (для web) в SRT
 
Всем привет!
На сайте channel 9 есть много видео с конференций и выступлений от Microsoft (Build, Ignite, Visual Studio Live и так далее). Видео также можно скачать, причём к некоторым видео можно скачать субтитры. Я всегда смотрю с субтитрами, так как иногда не совсем понятно, что говорят участники выступлений, поэтому субтитры являются большим подспорьем. Но вот незадача - субтитры в формате VTT, то есть в плеер (например, Light Alloy) их не вставишь. Я посмотрел отличия, и оказалось, что нужно внести совсем небольшие изменения - и SRT готов! Я написал простую программу для конвертации. Если кто-то заинтересовался, то исполняемый файл - в папке build, исходники - в папке source. Можно указать несколько файлов. После конвертации файл VTT удаляется.
There is no knowledge that is not power
Вышла новая версия Ribbon XML Editor 5.2
 
Вышла новая версия редактора ленты Ribbon XML Editor версия 5.2.
There is no knowledge that is not power
C# vs VB.NET
 
Кто чем пользуется и какие, на ваш взгляд, удобства одного языка перед другим? :)
There is no knowledge that is not power
Excel 2016 и Power Query
 
Установил Excel 2016. Решил почитать, чего там нового. Интересное из диаграмм - водопады. И ещё интегрировали Power Query, который раньше был надстройкой (Data => Get & Transform/Данные => Скачать & Преобразовать [ну и перевели!!! ]). Решил посмотреть, что за зверь, так как Andrey VG частенько отвечал в виде Power Query. Прочитал, что у Power Query есть свой язык Power Query Formula Language ("M" Language).
Решил бегло пробежаться и понажимать кнопки. Благо, и повод есть - база в SQL Server'е, в которой 250 000 строк. При подсоединении задал свой простенький SQL:
Код
SELECT * FROM dbo.MyTable
WHERE Id = 0;
Первое, что бросилось в глаза - данные не все были загружены, а точнее - всего лишь 58 строк с сообщением "The data in the preview has been truncated due to size limits". Но где регулировать этот "size limits" - я так и не нашёл.
Я не зря написал SQL-запрос выше. В строке формулы был мой запрос: [Query="SELECT * FROM dbo.MyTable#(lf)WHERE Id = 0;"]. Сначала не понял, где у меня в запросе #(lf), а потом понял, что это знак новой строки (Line Feed).
В общем, думаю почитать про Power Query, но у меня вопрос - насколько необходимо знать язык "M"? Другими словами, какие вещи нельзя сделать в GUI, для которых необходимо знать "M"? И какие есть хорошие книги/статьи? :)
There is no knowledge that is not power
Задолбали халявщики!
 
Предлагаю закрывать темы халявщиков. Как-то так. Задолбали. Честное слово.
There is no knowledge that is not power
Запрет редактирования сообщения, если ниже есть сообщения
 
Субж, собственно. :)
Вот примерчик. Михаил Лебедев пишет "Зачем Вам такое бешеное количество (385 + еще 2) листов в книге?", однако ТС отредактировал своё оригинальное сообщение - и теперь ничего непонятно.
There is no knowledge that is not power
Обработка Big Data - язык U-SQL
 
Introducing U-SQL – A Language that makes Big Data Processing Easy
There is no knowledge that is not power
Почему при смене расширения файла Excel не открывает его?, Вопрос с подвохом :)
 
Есть файл Эксель с макросами. Его расширение - XLSM. В спешке при копировании похожего названия с некоторым изменением вы переименовываете его, но не заметили, что у того файла было расширение XLSX - и теперь у нового файла тоже расширение XLSX. И вот вы пытаетесь открыть его, но у вас не получится.
Внимание, знатоки, вопрос - почему? :D
There is no knowledge that is not power
Создание базы Access без установленного Access
 
Сегодня как-то между делом Александр (ikki) спросил про код, который позволяет создавать базу данных (и структуру) без наличия установленного Access'а. Я ответил ему, но продублирую ответ здесь - на всякий случай. :)
Для этого потребуется библиотека "Microsoft ADO Ext. 6.0 for DDL  and Security".
Код
Sub CreateAccessDatabaseWithoutAccess()
     
    Dim cat As ADOX.Catalog '// Каталог (база данных)
    Dim t As ADOX.Table     '// Таблица
    Dim c As ADOX.Column    '// Столбец
     
    '// Создаём файл базы данных "C:\Temp\1.mdb".
    Set cat = New ADOX.Catalog
    '// Excel 2007+
    cat.Create "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Temp\1.mdb"
    '// Excel 97-2003
    '// cat.Create "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Temp\1.mdb"
     
    '// Создаём таблицу
    Set t = New ADOX.Table
    t.Name = "User"
     
    '// Создаём два столбца: Id и UserName
    Set c = New ADOX.Column
    c.Name = "Id"      '// Название столбца
    c.Type = adInteger '// Тип данных
    t.Columns.Append c '// Добавляем столбец в таблицу
 
    Set c = New ADOX.Column
    c.Name = "UserName"
    c.Type = adWChar
    c.DefinedSize = 255
    t.Columns.Append c
 
    '// Добавляем таблицу в базу
    cat.Tables.Append t
     
    Set cat = Nothing
     
End Sub
There is no knowledge that is not power
Microsoft Power Query for Excel: Discover and Refine Your Data
 
Линк (на английском).
There is no knowledge that is not power
"Двуликий" ОП
 
Насколько я заметил, имя ОП сохраняется вместе с темой, а не берётся из профиля. Дело в том, что когда модератор просит ОП изменить имя и когда он его меняет, то:
1) имя в списке тем остаётся старым;
2) имя в самой теме не меняется до тех пор, пока ОП не сменил имя.
Привожу пример подобного ОП. Данная тема примечательна ещё и тем, что непонятно, что ОП сменил имя (с "s7263808" на "Korss"), так как обычно изменению имени предшествует просьба модератора сменить имя.
Таким образом, делаю заключение, что имя ОП, отображаемое в списке тем и в самом сообщении берётся не из профиля (как было бы правильно).
Поэтому есть просьба брать имя ОП из профиля.
There is no knowledge that is not power
Головоломка, :)
 
По радио крутится реклама лотереи "Столото". Разговор одной подруги (П1) с другой (П2):

П1: Я теперь жена миллионера!
П2: А Валера?
П1: А Валера - муж жены миллионера!

Вопрос - кто такой Валера и сколько мужей у это жены?  :D   :D
Изменено: Johny - 21 окт 2014 10:38:31
There is no knowledge that is not power
Excel в C#: кастинг SpecialCells в массив
 
Здравствуйте, товарищи! Бью к вам челом!  :)   Вопрос к тем, кто программировал/программирует Excel в C# (.NET Framework).

В общем, проблема такого характера. Имеется некий диапазон. Фильтрую его. Мне нужно получить этот отфильтрованный диапазон и пихнуть его в массив. В VBA я делаю так:
Код
Sub F1()  
    Dim rng As Range, arr As Variant
    Set rng = Sheets(1).Range("AS5:AS6094").SpecialCells(xlCellTypeVisible) 
    arr = rng.Value
End Sub"
Это в VBA. А вот аналогичный метод в C#:
Код
using Excel = Microsoft.Office.Interop.Excel; 
 
...... 
 
private void LoadExcelFile()
{
   // Выбираем файл и открываем его
   var dialog = new Microsoft.Win32.OpenFileDialog { InitialDirectory = Directory.GetCurrentDirectory() };
   if (!dialog.ShowDialog(this).Value) return;
   var excelFile = dialog.FileName;
   Excel.Application xlApp = new Excel.Application() { Visible = true };
   Excel.Workbook book = xlApp.Workbooks.Open(excelFile);
   Excel.Worksheet sheet = book.Sheets[1];

   // Убираем автофильтр
   if (sheet.AutoFilter != null) sheet.AutoFilterMode = false;

   // Фильтруем
   sheet.Range["A5:BA5"].AutoFilter(Field: 25, Criteria1: "31.07.2014");

   // Получаем фильтрованный диапазон
   var rng1 = sheet.Range["AS5", "AS6094"].SpecialCells(Excel.XlCellType.xlCellTypeVisible);

   // Получаем весь диапазон
   var rng2 = sheet.Range["AS5", "AS6094"];

   // Значение диапазона (ожидаем массив)
   dynamic val1 = rng1.Value;
   dynamic val2 = rng2.Value;

   MessageBox.Show(val1.GetType().Name);  // Возвращает: String <= Ожидался массив Object[,]
   MessageBox.Show(val2.GetType().Name);  // Возвращает: Object[,] <= Правильно

   book.Close();
   xlApp.Quit();
   System.Runtime.InteropServices.Marshal.ReleaseComObject(book);
   System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);
}
Как видно, диапазон, полученный через SpecialCells, даёт нам String, а не массив. Кто-нибудь знает, как решить эту проблему?  :(
There is no knowledge that is not power
Языковой перевод фильмов
 
Привет всем!
Очень интересная тема - перевод американских фильмов на русский язык.  :)  Хочу сказать, что смотрю американские фильмы исключительно с субтитрами! Многие скажут, что мне делать нечего - лучше расслабиться и смотреть картинку, чем бегать глазами по тексту. Так-то оно так, но... Дело в том, что перевод текста 1) может быть не совсем точным, 2) может содержать одно неверно переведённое слово, 3) иметь вольный перевод (так сказать, "близко к тексту"  ;)  и, наконец, 4) иметь вообще другой перевод и, соответственно, другой смысл.
Самый интересный пункт - это, конечно, четвёртый. И я вам покажу примерчик.
Фильм "Враг государства" (Enemy of the state) 1998 года.
На времени 38:30 мужик говорит такую фразу:
I've seen KILLERS walk free because the EYEWITNESS  was an ALCOHOLIC
Вот перевод:
Я видел, как НАСИЛЬНИКОВ отпускают, потому что ЖЕРТВА была ПРОСТИТУТКОЙ
Вот правильный перевод:
Я видел, как УБИЙЦ отпускают, потому что СВИДЕТЕЛЬ был АЛКОГОЛИКОМ

Из этого перевода следует, что проституток можно насиловать - и насильника просто отпустят.  :)
Предлагаю сюда выкладывать несуразицы перевода.  :)
There is no knowledge that is not power
Значок "есть новые сообщения" и темы, в которых принимается участие
 
1. Значок "есть новые сообщения". Он у меня не появляется. :(

2. Будет ли когда-нибудь реализована возможность пометки темы, в которой я принимаю участие (например, в виде загнутой стрелки как в ярлыке)? :)
There is no knowledge that is not power
Узнать, в каких столбцах применён фильтр в автофильтре
 
Только что на форуме MrExcel.com задали вопрос о том, как можно узнать те столбцы, где применён фильтр в автофильтре. Действительно, иногда попадаются длинные таблицы, где стоит автофильтр, и возникает необходимость найти, где чего применено. Если кому-то пригодится, то вот код. :)

Код
Sub ShowFilterInfo()

    Dim af As AutoFilter, f As Filter
    Dim sCols As String
    Dim c As Integer, iCol As Integer, firstCell As Integer
    Dim re As Object
    
    If Not ActiveSheet.AutoFilterMode Then
        MsgBox "Автофильтр на листе не найден.", vbExclamation
        Exit Sub
    End If

    Set af = ActiveSheet.AutoFilter
    firstCell = af.Range(1).Column
    Set re = CreateObject("VBScript.RegExp")
    re.Pattern = "[A-Z]+"
    
    For Each f In af.Filters
        c = c + 1
        If f.On Then
            iCol = c + firstCell - 1
            sCols = sCols & re.Execute(Cells(1, iCol).Address)(0) & ", "
        End If
    Next

    If Len(sCols) > 0 Then
        MsgBox "В следующих столбцах установлен фильтр: " & Chr(13) & Left$(sCols, Len(sCols) - 2)
    Else
        MsgBox "Фильтры не найдены.", vbExclamation
    End If
    
    Set re = Nothing

End Sub 
Изменено: Johny - 13 май 2014 12:09:06
There is no knowledge that is not power
Word VBA. Таблица - это текст
 
Как-то нужно было мне скопировать таблицу из одного места в другое в одном и том же документе. Так как с Word'овским VBA почти не знаком, то за неимением знания, как сделать, решить пойти методом копипаста. :D
Код
Dim doc As Document
Dim t As Table

Set doc = ThisDocument
Set t = doc.Tables(1)
t.Select
Selection.Copy
doc.Bookmarks("bm46").Select
Selection.Paste 
Но потом подумал, что всё-таки должен быть более другой метод, который был бы более верным. Решил зайти на буржуйский форум и задал вопрос. На что мне ответили так:
Код
Sub TableDuplicate()
    With ActiveDocument
        .Bookmarks("bm46").Range.FormattedText = .Tables(1).Range.FormattedText
    End With
End Sub
Так вот как так можно догадаться интуитивно, что таблица в терминах Word'а - это форматированный текст (FormattedText)?
Интересно, есть ли у кого-нибудь опыт работы с Word VBA и какое впечатление от его использования? :)
Изменено: Johny - 1 апр 2014 14:33:41
There is no knowledge that is not power
Excel 2013 + JavaScript = ?
 
Как вы знаете, MSFT внедрило в Office 2013 так называемые Office Apps. Для написания его используется JavaScript. Честно скажу, мне лично не нравится этот язык. Я стал изучать его, но так в нём ничего не понял. Сегодня прочитал вот эту статью на Хабре про JavaScript. Очень интересно.
P.S. Для заметки - для написания Apps необходимо знание всей внутренней структуры файла, а это значит, что надо знать всю спецификацию. Кто готов? :)
P.P.S. Слышу гневные слова Саши. :D
There is no knowledge that is not power
Использование функций библиотеки на языке C в Excel
 
Недавно начал изучать язык программирования C и меня сразу заинтересовала такая тема, что можно написать для себя функции для использования в Excel'е. Вроде где-то читал, что функции, написанные на C/C++, быстро работают в Экселе по сравнению с VBA функциями, ну и решил написать простейшие функции для теста. На выходе мы получаем Win32 библиотеку (DLL), которую используем в Declare Function. Далее я узнал, что можно написать XLL надстройки, которые позволяют использовать функции С сразу в ячейках, а не в VBA, но это я не осилил, конечно.  С улыбкой Если кто-то знает, есть ли разница в скорости работы VBA и функций, буду очень благодарен.0
На ваш суд выношу библиотеку с двумя функциями. Первая из них (addOne) совсем простая - прибавляет единичку к аргументу Double и возвращает результат.
Вторая функция - очень интересная. Если мне не изменяет память, этот вопрос задавал nerv - можно ли использовать VBA-функцию в качестве callback-функции. Ответ - с помощью C DLL можно!
Библиотеки сделал в двух вариантах - 32 и 64-х битные. Предпроцессорная директива (#If Win64) сама выберет нужную библиотеку. От вас требуется скопировать куда-нибудь эти две библиотеки и указать к ним полный путь после Lib. Файл с кодом я приложу.
Итак, сначала код VBA.
Код
#If Win64 Then
    
    ' Excel 64-бит
    Private Declare PtrSafe Function addOne Lib "c:\DLLs\ExcelFuncs_x64.dll" _
        (ByVal x As Double) As Double
    
    Private Declare PtrSafe Function addOneWithCallback Lib "c:\DLLs\ExcelFuncs_x64.dll" _
        (ByVal funcPtr As LongPtr, ByVal x As Double) As Double

#Else

    ' Excel 32-бит
    Private Declare Function addOne Lib "c:\DLLs\ExcelFuncs_x86.dll" _
        (ByVal x As Double) As Double

    Private Declare Function addOneWithCallback Lib "c:\DLLs\ExcelFuncs_x86.dll" _
        (ByVal funcPtr As Long, ByVal x As Double) As Double

#End If

Sub AddOneTest()
    MsgBox "Сумма = " & addOne(5)
End Sub

Sub AddOneUsingCallback()
    
    ' C-фукнция получает указатель VBA функции "AddOneCallback" и передаёт ей пятёрку.
    ' VBA функция прибавляет 1 к аргументу и возвращает 6.
    ' С функция возвращает в VBA шестёрку.
    MsgBox "5 + 1 = " & addOneWithCallback(AddressOf AddOneCallback, 5)
    
End Sub

Function AddOneCallback(ByVal x As Double) As Double
    AddOneCallback = x + 1
End Function
 

Итак, разберём, что к чему. Как я и говорил выше, директива #If Win64 автоматически загрузит нужную библиотеку - свою для 32 и 64-битного Офиса. Если вы не программировали Win32 API для 64-битного Офиса, то для 64-битного Офиса поменялись некоторые типы данных, которые необходимо использовать. Например, вместо Long - LongPtr и т.д. На моём примере мы видим для 64-битного Экселя "PtrSafe" и вместо Long используется LongPtr (так как указатели имеют длину не 32 бита (Integer - 4 байта)).
После того, как вы подправили путь к библиотеке, далее идут две тестовые процедуры (AddOneTest и AddOneUsingCallback) и вспомогательная функция (callback) для AddOneUsingCallback.
Первая простейшая C-функция - addOne в AddOneTest. Как видно, ничего нет сложного - вызываем функцию обычно как будто это VBA-функция. В примере в неё передаётся пятёрка, к ней прибавляется единичка, на выходе - 6.
Вторая C-функция - addOneWithCallback. Она имеем два аргумента. Первый - это адрес callback-функции, которая будет вызываться в C-функции. Второй аргумент я сделал для наглядности - он будет передаваться в VBA-функцию в C-библиотеке.  :)  В комментариях я написал, что получается.
Итак, callback'и в VBA возможны. Думаю, Саша прочитает эту тему.  :D  
Исходный C код:
Код
#define WINAPI __stdcall

// Указатель функции
typedef double (WINAPI *fptrAddNum)(double);

double WINAPI addOne(double x)
{
    return x + 1;
}

double WINAPI addOneWithCallback(fptrAddNum callback, double x)
{
    return callback(x);
}
Ссылка на файл.
There is no knowledge that is not power
Новая версия редактора ленты Ribbon XML Editor - 4
 
Уважаемые товарищи!
Вышла новая версия очень удобного редактора ленты Ribbon XML Editor 4 с большим количеством доработок.
Среди фишек новой версии - подсветка парных тегов, автооткрытие документа в редакторе после его закрытия в родном приложении, быстрые переходы по тегам, стили подсветки кода и вменяемая справка.
Здесь описание от автора.  :)
Изменено: Johny - 17 фев 2014 15:35:21
There is no knowledge that is not power
Обращаемся к ячейкам :)
 
Наша повседневная работа написания кода так или иначе связана с обращением к ячейкам.
Хотелось бы написать про методы обращения к ячейкам. Если что-то пропустил - не ругайте.  :D  
Итак, поехали...  :)  

Код
Sub CellsSelection()
    
    Dim cell As Range
    Dim severalCells As Range
    Dim rng As Range

    '=======================================
    'Выделяем ячейку F6
    '=======================================
    Set cell = Range("F6")
    Set cell = Cells(6, 6) 
    Set cell = Cells(6, "F")
    Set cell = Cells(81926) ' (16384 * 5) + 6
    Set cell = Cells.Item(6, 6)
    Set cell = Cells.Cells(6, 6)

    '=======================================
    '1. Выделяем диапазон D4:G10
    '=======================================
    Set rng = Range("D4:G10")
    Set rng = Range(Cells(4, "D"), Cells(10, "G"))
    Set rng = Range(Cells(4, 4), Cells(10, 7))
    Set rng = Range("D4", Cells(10, 7))
    Set rng = Range("D4", "G10")
    Set rng = Range(Range("D4"), "G10")
    Set rng = Range("D4").Resize(7, 4)
    'Обращаемся к диапазону без привязки к объекту Worksheet
    Set rng = Range("Лист1!D4:G10")
    
    
    'Во всех нижеприведённых методах необходимо
    'представить диапазон D4:G10 как лист
    'с верхней левой ячейкой A1, то есть мысленно
    'переносим D4:G10 в A1. :)
    
    '========================================
    '2. Выделяем ячейку F6 в диапазоне D4:G10
    '========================================
    Set cell = rng.Range("C3")
    Set cell = rng(3, 3)
    Set cell = rng(11)
    Set cell = rng.Item(3, 3)
    Set cell = rng.Item(11)
    Set cell = rng.Cells(11)
    Set cell = rng.Cells(3, 3)
    
    '===========================================
    '3. Выделяем ячейку E11 ВНЕ диапазона D4:G10
    '===========================================
    Set cell = rng(30)
    Set cell = rng.Item(30)
    Set cell = rng.Cells(30)
    Set cell = rng.Range("B8")
    Set cell = rng.Cells(8, 2)
    Set cell = rng(8, 2)
    Set cell = rng.Item(8, 2)
    Set cell = rng.Cells(8, 2)
    
    '=============================================
    '4. Выделяем диапазон E8:F9 в диапазоне D4:G10
    '=============================================
    Set severalCells = rng.Range("B5:C6")
    Set severalCells = rng.Range("B5", "C6")
    'В общем, принцип такой же, что и в пункте 2. :)
    
End Sub
There is no knowledge that is not power
Необычный Select Case
 
Скажем, на листе или форме имеются 5 радиокнопок. Задача тривиальная - определить, какая радиокнопка включена, и запустить соответствующую процедуру. Вот возможное решение.
Код
Sub RunProcedure_If_End_If()
    With ActiveSheet
        If .OLEObjects("OptionButton1").Object = True Then
            Call Sub1
        ElseIf .OLEObjects("OptionButton2").Object = True Then
            Call Sub2
        ElseIf .OLEObjects("OptionButton3").Object = True Then
            Call Sub3
        ElseIf .OLEObjects("OptionButton4").Object = True Then
            Call Sub4
        ElseIf .OLEObjects("OptionButton5").Object = True Then
            Call Sub5
        End If
    End With
End Sub

Скажем так - не очень читабельный код. Но что мы видем общее, так это "True" во всех If'ах. Это даёт нам следующую необычную конструкцию Select Case:
Код
Sub RunProcedure_Select_Case()
    With ActiveSheet
        Select Case True
            Case .OLEObjects("OptionButton1").Object: Call Sub1
            Case .OLEObjects("OptionButton2").Object: Call Sub2
            Case .OLEObjects("OptionButton3").Object: Call Sub3
            Case .OLEObjects("OptionButton4").Object: Call Sub4
            Case .OLEObjects("OptionButton5").Object: Call Sub5
        End Select
    End With
End Sub
There is no knowledge that is not power
Страницы: 1 2 След.
Наверх